[med-svn] [libbpp-phyl] 01/02: Imported Upstream version 2.1.0

Andreas Tille tille at debian.org
Wed Apr 13 13:27:12 UTC 2016


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository libbpp-phyl.

commit a6bd549456be2051e12efca9f966d42b970a3145
Author: Andreas Tille <tille at debian.org>
Date:   Sat Apr 9 13:44:46 2016 +0200

    Imported Upstream version 2.1.0
---
 AUTHORS.txt                                        |   23 +
 CMakeLists.txt                                     |  190 ++
 COPYING.txt                                        |  505 ++++++
 ChangeLog                                          |  615 +++++++
 Doxyfile                                           | 1889 ++++++++++++++++++++
 INSTALL.txt                                        |   12 +
 bpp-phyl.spec                                      |  210 +++
 debian/changelog                                   |   78 +
 debian/compat                                      |    1 +
 debian/control                                     |   25 +
 debian/copyright                                   |   66 +
 debian/docs                                        |    0
 debian/libbpp-phyl-dev.install                     |    3 +
 debian/libbpp-phyl9.install                        |    1 +
 debian/postinst                                    |   43 +
 debian/postrm                                      |   45 +
 debian/prerm                                       |   27 +
 debian/rules                                       |  120 ++
 debian/source/format                               |    1 +
 src/Bpp/Phyl/AncestralStateReconstruction.h        |  110 ++
 src/Bpp/Phyl/App/PhylogeneticsApplicationTools.cpp | 1489 +++++++++++++++
 src/Bpp/Phyl/App/PhylogeneticsApplicationTools.h   |  630 +++++++
 src/Bpp/Phyl/BipartitionList.cpp                   |  827 +++++++++
 src/Bpp/Phyl/BipartitionList.h                     |  234 +++
 src/Bpp/Phyl/BipartitionTools.cpp                  |  329 ++++
 src/Bpp/Phyl/BipartitionTools.h                    |  171 ++
 .../AbstractAgglomerativeDistanceMethod.cpp        |  121 ++
 .../Distance/AbstractAgglomerativeDistanceMethod.h |  230 +++
 src/Bpp/Phyl/Distance/BioNJ.cpp                    |  130 ++
 src/Bpp/Phyl/Distance/BioNJ.h                      |  112 ++
 src/Bpp/Phyl/Distance/DistanceEstimation.cpp       |  695 +++++++
 src/Bpp/Phyl/Distance/DistanceEstimation.h         |  544 ++++++
 src/Bpp/Phyl/Distance/DistanceMethod.h             |  120 ++
 src/Bpp/Phyl/Distance/HierarchicalClustering.cpp   |  213 +++
 src/Bpp/Phyl/Distance/HierarchicalClustering.h     |  115 ++
 src/Bpp/Phyl/Distance/NeighborJoining.cpp          |  159 ++
 src/Bpp/Phyl/Distance/NeighborJoining.h            |  119 ++
 src/Bpp/Phyl/Distance/PGMA.cpp                     |  155 ++
 src/Bpp/Phyl/Distance/PGMA.h                       |  118 ++
 src/Bpp/Phyl/Graphics/AbstractDendrogramPlot.cpp   |   55 +
 src/Bpp/Phyl/Graphics/AbstractDendrogramPlot.h     |   92 +
 src/Bpp/Phyl/Graphics/AbstractTreeDrawing.cpp      |  103 ++
 src/Bpp/Phyl/Graphics/AbstractTreeDrawing.h        |  379 ++++
 src/Bpp/Phyl/Graphics/CladogramPlot.cpp            |  144 ++
 src/Bpp/Phyl/Graphics/CladogramPlot.h              |  115 ++
 src/Bpp/Phyl/Graphics/PhylogramPlot.cpp            |  171 ++
 src/Bpp/Phyl/Graphics/PhylogramPlot.h              |  113 ++
 src/Bpp/Phyl/Graphics/TreeDrawing.h                |  403 +++++
 .../Phyl/Graphics/TreeDrawingDisplayControler.cpp  |   74 +
 .../Phyl/Graphics/TreeDrawingDisplayControler.h    |  182 ++
 src/Bpp/Phyl/Graphics/TreeDrawingListener.cpp      |  247 +++
 src/Bpp/Phyl/Graphics/TreeDrawingListener.h        |  303 ++++
 src/Bpp/Phyl/Io/BppOFrequenciesSetFormat.cpp       |  604 +++++++
 src/Bpp/Phyl/Io/BppOFrequenciesSetFormat.h         |  100 ++
 src/Bpp/Phyl/Io/BppORateDistributionFormat.cpp     |  361 ++++
 src/Bpp/Phyl/Io/BppORateDistributionFormat.h       |   92 +
 src/Bpp/Phyl/Io/BppOSubstitutionModelFormat.cpp    | 1331 ++++++++++++++
 src/Bpp/Phyl/Io/BppOSubstitutionModelFormat.h      |  154 ++
 src/Bpp/Phyl/Io/IoDistanceMatrix.h                 |  173 ++
 src/Bpp/Phyl/Io/IoDistanceMatrixFactory.cpp        |   58 +
 src/Bpp/Phyl/Io/IoDistanceMatrixFactory.h          |  101 ++
 src/Bpp/Phyl/Io/IoFrequenciesSet.h                 |  129 ++
 src/Bpp/Phyl/Io/IoFrequenciesSetFactory.cpp        |   57 +
 src/Bpp/Phyl/Io/IoFrequenciesSetFactory.h          |  101 ++
 src/Bpp/Phyl/Io/IoPairedSiteLikelihoods.cpp        |  276 +++
 src/Bpp/Phyl/Io/IoPairedSiteLikelihoods.h          |  126 ++
 src/Bpp/Phyl/Io/IoSubstitutionModel.h              |  138 ++
 src/Bpp/Phyl/Io/IoSubstitutionModelFactory.cpp     |   57 +
 src/Bpp/Phyl/Io/IoSubstitutionModelFactory.h       |  102 ++
 src/Bpp/Phyl/Io/IoTree.h                           |  295 +++
 src/Bpp/Phyl/Io/IoTreeFactory.cpp                  |   66 +
 src/Bpp/Phyl/Io/IoTreeFactory.h                    |   98 +
 src/Bpp/Phyl/Io/Newick.cpp                         |  198 ++
 src/Bpp/Phyl/Io/Newick.h                           |  207 +++
 src/Bpp/Phyl/Io/NexusIoTree.cpp                    |  320 ++++
 src/Bpp/Phyl/Io/NexusIoTree.h                      |  170 ++
 src/Bpp/Phyl/Io/Nhx.cpp                            |  572 ++++++
 src/Bpp/Phyl/Io/Nhx.h                              |  282 +++
 src/Bpp/Phyl/Io/PhylipDistanceMatrixFormat.cpp     |  123 ++
 src/Bpp/Phyl/Io/PhylipDistanceMatrixFormat.h       |   87 +
 ...tractDiscreteRatesAcrossSitesTreeLikelihood.cpp |  332 ++++
 ...bstractDiscreteRatesAcrossSitesTreeLikelihood.h |  147 ++
 .../AbstractHomogeneousTreeLikelihood.cpp          |  415 +++++
 .../Likelihood/AbstractHomogeneousTreeLikelihood.h |  261 +++
 .../AbstractNonHomogeneousTreeLikelihood.cpp       |  469 +++++
 .../AbstractNonHomogeneousTreeLikelihood.h         |  289 +++
 src/Bpp/Phyl/Likelihood/AbstractTreeLikelihood.cpp |   97 +
 src/Bpp/Phyl/Likelihood/AbstractTreeLikelihood.h   |  318 ++++
 .../Phyl/Likelihood/AbstractTreeLikelihoodData.h   |  145 ++
 src/Bpp/Phyl/Likelihood/ClockTreeLikelihood.h      |   90 +
 .../Phyl/Likelihood/DRASDRTreeLikelihoodData.cpp   |  263 +++
 src/Bpp/Phyl/Likelihood/DRASDRTreeLikelihoodData.h |  454 +++++
 .../Phyl/Likelihood/DRASRTreeLikelihoodData.cpp    |  293 +++
 src/Bpp/Phyl/Likelihood/DRASRTreeLikelihoodData.h  |  311 ++++
 .../DRHomogeneousMixedTreeLikelihood.cpp           |  522 ++++++
 .../Likelihood/DRHomogeneousMixedTreeLikelihood.h  |  218 +++
 .../Likelihood/DRHomogeneousTreeLikelihood.cpp     |  977 ++++++++++
 .../Phyl/Likelihood/DRHomogeneousTreeLikelihood.h  |  312 ++++
 .../Likelihood/DRNonHomogeneousTreeLikelihood.cpp  | 1336 ++++++++++++++
 .../Likelihood/DRNonHomogeneousTreeLikelihood.h    |  315 ++++
 src/Bpp/Phyl/Likelihood/DRTreeLikelihood.h         |  111 ++
 src/Bpp/Phyl/Likelihood/DRTreeLikelihoodTools.cpp  |  147 ++
 src/Bpp/Phyl/Likelihood/DRTreeLikelihoodTools.h    |   89 +
 .../DiscreteRatesAcrossSitesTreeLikelihood.h       |  210 +++
 .../GlobalClockTreeLikelihoodFunctionWrapper.cpp   |  124 ++
 .../GlobalClockTreeLikelihoodFunctionWrapper.h     |  104 ++
 .../Phyl/Likelihood/HomogeneousTreeLikelihood.h    |   98 +
 .../MarginalAncestralStateReconstruction.cpp       |  184 ++
 .../MarginalAncestralStateReconstruction.h         |  199 +++
 .../Likelihood/NNIHomogeneousTreeLikelihood.cpp    |  363 ++++
 .../Phyl/Likelihood/NNIHomogeneousTreeLikelihood.h |  284 +++
 .../Phyl/Likelihood/NonHomogeneousTreeLikelihood.h |  123 ++
 src/Bpp/Phyl/Likelihood/PairedSiteLikelihoods.cpp  |  189 ++
 src/Bpp/Phyl/Likelihood/PairedSiteLikelihoods.h    |  195 ++
 src/Bpp/Phyl/Likelihood/PseudoNewtonOptimizer.cpp  |  194 ++
 src/Bpp/Phyl/Likelihood/PseudoNewtonOptimizer.h    |  139 ++
 src/Bpp/Phyl/Likelihood/RASTools.cpp               |   73 +
 src/Bpp/Phyl/Likelihood/RASTools.h                 |   76 +
 .../Likelihood/RHomogeneousClockTreeLikelihood.cpp |  218 +++
 .../Likelihood/RHomogeneousClockTreeLikelihood.h   |  168 ++
 .../Likelihood/RHomogeneousMixedTreeLikelihood.cpp |  339 ++++
 .../Likelihood/RHomogeneousMixedTreeLikelihood.h   |  211 +++
 .../Phyl/Likelihood/RHomogeneousTreeLikelihood.cpp |  882 +++++++++
 .../Phyl/Likelihood/RHomogeneousTreeLikelihood.h   |  276 +++
 .../RNonHomogeneousMixedTreeLikelihood.cpp         |  825 +++++++++
 .../RNonHomogeneousMixedTreeLikelihood.h           |  294 +++
 .../Likelihood/RNonHomogeneousTreeLikelihood.cpp   | 1365 ++++++++++++++
 .../Likelihood/RNonHomogeneousTreeLikelihood.h     |  278 +++
 .../Phyl/Likelihood/SitePartitionTreeLikelihood.h  |   96 +
 src/Bpp/Phyl/Likelihood/TreeLikelihood.h           |  430 +++++
 src/Bpp/Phyl/Likelihood/TreeLikelihoodData.h       |  151 ++
 src/Bpp/Phyl/Likelihood/TreeLikelihoodTools.cpp    |  121 ++
 src/Bpp/Phyl/Likelihood/TreeLikelihoodTools.h      |  119 ++
 .../Mapping/DecompositionSubstitutionCount.cpp     |  295 +++
 .../Phyl/Mapping/DecompositionSubstitutionCount.h  |  142 ++
 src/Bpp/Phyl/Mapping/LaplaceSubstitutionCount.cpp  |  148 ++
 src/Bpp/Phyl/Mapping/LaplaceSubstitutionCount.h    |  129 ++
 src/Bpp/Phyl/Mapping/NaiveSubstitutionCount.cpp    |   70 +
 src/Bpp/Phyl/Mapping/NaiveSubstitutionCount.h      |  169 ++
 src/Bpp/Phyl/Mapping/OneJumpSubstitutionCount.cpp  |   54 +
 src/Bpp/Phyl/Mapping/OneJumpSubstitutionCount.h    |  122 ++
 .../Mapping/ProbabilisticSubstitutionMapping.cpp   |   66 +
 .../Mapping/ProbabilisticSubstitutionMapping.h     |  189 ++
 src/Bpp/Phyl/Mapping/SubstitutionCount.h           |  220 +++
 src/Bpp/Phyl/Mapping/SubstitutionMapping.h         |  254 +++
 src/Bpp/Phyl/Mapping/SubstitutionMappingTools.cpp  | 1011 +++++++++++
 src/Bpp/Phyl/Mapping/SubstitutionMappingTools.h    |  243 +++
 src/Bpp/Phyl/Mapping/SubstitutionRegister.h        |  634 +++++++
 .../Mapping/UniformizationSubstitutionCount.cpp    |  273 +++
 .../Phyl/Mapping/UniformizationSubstitutionCount.h |  130 ++
 src/Bpp/Phyl/Mapping/WeightedSubstitutionCount.cpp |   51 +
 src/Bpp/Phyl/Mapping/WeightedSubstitutionCount.h   |  117 ++
 .../Model/AbstractBiblioMixedSubstitutionModel.cpp |   76 +
 .../Model/AbstractBiblioMixedSubstitutionModel.h   |  173 ++
 .../Phyl/Model/AbstractBiblioSubstitutionModel.cpp |  122 ++
 .../Phyl/Model/AbstractBiblioSubstitutionModel.h   |  196 ++
 .../Phyl/Model/AbstractMixedSubstitutionModel.cpp  |  216 +++
 .../Phyl/Model/AbstractMixedSubstitutionModel.h    |  236 +++
 src/Bpp/Phyl/Model/AbstractSubstitutionModel.cpp   |  472 +++++
 src/Bpp/Phyl/Model/AbstractSubstitutionModel.h     |  412 +++++
 .../Phyl/Model/AbstractWordSubstitutionModel.cpp   |  665 +++++++
 src/Bpp/Phyl/Model/AbstractWordSubstitutionModel.h |  184 ++
 src/Bpp/Phyl/Model/BinarySubstitutionModel.cpp     |  241 +++
 src/Bpp/Phyl/Model/BinarySubstitutionModel.h       |  152 ++
 .../AbstractCodonDistanceSubstitutionModel.cpp     |   87 +
 .../Codon/AbstractCodonDistanceSubstitutionModel.h |  148 ++
 .../AbstractCodonFitnessSubstitutionModel.cpp      |   83 +
 .../Codon/AbstractCodonFitnessSubstitutionModel.h  |  104 ++
 .../AbstractCodonFrequenciesSubstitutionModel.cpp  |   87 +
 .../AbstractCodonFrequenciesSubstitutionModel.h    |  117 ++
 ...tractCodonPhaseFrequenciesSubstitutionModel.cpp |  124 ++
 ...bstractCodonPhaseFrequenciesSubstitutionModel.h |  129 ++
 .../Model/Codon/AbstractCodonSubstitutionModel.cpp |  195 ++
 .../Model/Codon/AbstractCodonSubstitutionModel.h   |  172 ++
 ...nceFitnessPhaseFrequenciesSubstitutionModel.cpp |  115 ++
 ...tanceFitnessPhaseFrequenciesSubstitutionModel.h |  161 ++
 .../CodonDistanceFrequenciesSubstitutionModel.cpp  |  111 ++
 .../CodonDistanceFrequenciesSubstitutionModel.h    |  183 ++
 ...onDistancePhaseFrequenciesSubstitutionModel.cpp |  109 ++
 ...odonDistancePhaseFrequenciesSubstitutionModel.h |  164 ++
 .../Model/Codon/CodonDistanceSubstitutionModel.cpp |   97 +
 .../Model/Codon/CodonDistanceSubstitutionModel.h   |  143 ++
 .../CodonRateFrequenciesSubstitutionModel.cpp      |  102 ++
 .../Codon/CodonRateFrequenciesSubstitutionModel.h  |  127 ++
 .../Model/Codon/CodonRateSubstitutionModel.cpp     |   84 +
 .../Phyl/Model/Codon/CodonRateSubstitutionModel.h  |  111 ++
 src/Bpp/Phyl/Model/Codon/CodonSubstitutionModel.h  |   84 +
 src/Bpp/Phyl/Model/Codon/GY94.cpp                  |   86 +
 src/Bpp/Phyl/Model/Codon/GY94.h                    |  121 ++
 src/Bpp/Phyl/Model/Codon/MG94.cpp                  |   83 +
 src/Bpp/Phyl/Model/Codon/MG94.h                    |  115 ++
 .../Phyl/Model/Codon/TripletSubstitutionModel.cpp  |  153 ++
 .../Phyl/Model/Codon/TripletSubstitutionModel.h    |  113 ++
 src/Bpp/Phyl/Model/Codon/YN98.cpp                  |   86 +
 src/Bpp/Phyl/Model/Codon/YN98.h                    |  119 ++
 src/Bpp/Phyl/Model/Codon/YNGKP_M1.cpp              |  155 ++
 src/Bpp/Phyl/Model/Codon/YNGKP_M1.h                |  125 ++
 src/Bpp/Phyl/Model/Codon/YNGKP_M2.cpp              |  162 ++
 src/Bpp/Phyl/Model/Codon/YNGKP_M2.h                |  121 ++
 src/Bpp/Phyl/Model/Codon/YNGKP_M3.cpp              |  204 +++
 src/Bpp/Phyl/Model/Codon/YNGKP_M3.h                |  120 ++
 src/Bpp/Phyl/Model/Codon/YNGKP_M7.cpp              |  157 ++
 src/Bpp/Phyl/Model/Codon/YNGKP_M7.h                |  122 ++
 src/Bpp/Phyl/Model/Codon/YNGKP_M8.cpp              |  171 ++
 src/Bpp/Phyl/Model/Codon/YNGKP_M8.h                |  125 ++
 .../Model/FrequenciesSet/CodonFrequenciesSet.cpp   |  622 +++++++
 .../Model/FrequenciesSet/CodonFrequenciesSet.h     |  390 ++++
 .../Phyl/Model/FrequenciesSet/FrequenciesSet.cpp   |  205 +++
 src/Bpp/Phyl/Model/FrequenciesSet/FrequenciesSet.h |  294 +++
 .../Model/FrequenciesSet/MvaFrequenciesSet.cpp     |  159 ++
 .../Phyl/Model/FrequenciesSet/MvaFrequenciesSet.h  |  124 ++
 .../FrequenciesSet/NucleotideFrequenciesSet.cpp    |  161 ++
 .../FrequenciesSet/NucleotideFrequenciesSet.h      |  201 +++
 .../Model/FrequenciesSet/ProteinFrequenciesSet.h   |  135 ++
 .../Model/FrequenciesSet/WordFrequenciesSet.cpp    |  396 ++++
 .../Phyl/Model/FrequenciesSet/WordFrequenciesSet.h |  243 +++
 src/Bpp/Phyl/Model/G2001.h                         |  172 ++
 .../Model/MarkovModulatedSubstitutionModel.cpp     |  229 +++
 .../Phyl/Model/MarkovModulatedSubstitutionModel.h  |  316 ++++
 src/Bpp/Phyl/Model/MixedSubstitutionModel.h        |  137 ++
 src/Bpp/Phyl/Model/MixedSubstitutionModelSet.cpp   |  482 +++++
 src/Bpp/Phyl/Model/MixedSubstitutionModelSet.h     |  400 +++++
 src/Bpp/Phyl/Model/MixtureOfASubstitutionModel.cpp |  325 ++++
 src/Bpp/Phyl/Model/MixtureOfASubstitutionModel.h   |  169 ++
 src/Bpp/Phyl/Model/MixtureOfSubstitutionModels.cpp |  320 ++++
 src/Bpp/Phyl/Model/MixtureOfSubstitutionModels.h   |  199 +++
 src/Bpp/Phyl/Model/Nucleotide/F84.cpp              |  465 +++++
 src/Bpp/Phyl/Model/Nucleotide/F84.h                |  228 +++
 src/Bpp/Phyl/Model/Nucleotide/GTR.cpp              |  151 ++
 src/Bpp/Phyl/Model/Nucleotide/GTR.h                |  183 ++
 src/Bpp/Phyl/Model/Nucleotide/HKY85.cpp            |  476 +++++
 src/Bpp/Phyl/Model/Nucleotide/HKY85.h              |  227 +++
 src/Bpp/Phyl/Model/Nucleotide/JCnuc.cpp            |  189 ++
 src/Bpp/Phyl/Model/Nucleotide/JCnuc.h              |  179 ++
 src/Bpp/Phyl/Model/Nucleotide/K80.cpp              |  394 ++++
 src/Bpp/Phyl/Model/Nucleotide/K80.h                |  198 ++
 src/Bpp/Phyl/Model/Nucleotide/L95.cpp              |  118 ++
 src/Bpp/Phyl/Model/Nucleotide/L95.h                |  132 ++
 .../Model/Nucleotide/NucleotideSubstitutionModel.h |   75 +
 src/Bpp/Phyl/Model/Nucleotide/RN95.cpp             |  529 ++++++
 src/Bpp/Phyl/Model/Nucleotide/RN95.h               |  181 ++
 src/Bpp/Phyl/Model/Nucleotide/RN95s.cpp            |  477 +++++
 src/Bpp/Phyl/Model/Nucleotide/RN95s.h              |  161 ++
 src/Bpp/Phyl/Model/Nucleotide/SSR.cpp              |  120 ++
 src/Bpp/Phyl/Model/Nucleotide/SSR.h                |  135 ++
 src/Bpp/Phyl/Model/Nucleotide/T92.cpp              |  466 +++++
 src/Bpp/Phyl/Model/Nucleotide/T92.h                |  202 +++
 src/Bpp/Phyl/Model/Nucleotide/TN93.cpp             |  448 +++++
 src/Bpp/Phyl/Model/Nucleotide/TN93.h               |  181 ++
 src/Bpp/Phyl/Model/Nucleotide/YpR.cpp              |  468 +++++
 src/Bpp/Phyl/Model/Nucleotide/YpR.h                |  290 +++
 src/Bpp/Phyl/Model/Nucleotide/gBGC.cpp             |  178 ++
 src/Bpp/Phyl/Model/Nucleotide/gBGC.h               |  131 ++
 src/Bpp/Phyl/Model/Protein/Coala.cpp               |  223 +++
 src/Bpp/Phyl/Model/Protein/Coala.h                 |  113 ++
 src/Bpp/Phyl/Model/Protein/CoalaCore.cpp           |  190 ++
 src/Bpp/Phyl/Model/Protein/CoalaCore.h             |  103 ++
 src/Bpp/Phyl/Model/Protein/DSO78.cpp               |   91 +
 src/Bpp/Phyl/Model/Protein/DSO78.h                 |  150 ++
 src/Bpp/Phyl/Model/Protein/JCprot.cpp              |  194 ++
 src/Bpp/Phyl/Model/Protein/JCprot.h                |  240 +++
 src/Bpp/Phyl/Model/Protein/JTT92.cpp               |   92 +
 src/Bpp/Phyl/Model/Protein/JTT92.h                 |  150 ++
 src/Bpp/Phyl/Model/Protein/LG08.cpp                |   92 +
 src/Bpp/Phyl/Model/Protein/LG08.h                  |  148 ++
 src/Bpp/Phyl/Model/Protein/LGL08_CAT.cpp           |  159 ++
 src/Bpp/Phyl/Model/Protein/LGL08_CAT.h             |  130 ++
 src/Bpp/Phyl/Model/Protein/LLG08_EHO.cpp           |  116 ++
 src/Bpp/Phyl/Model/Protein/LLG08_EHO.h             |  134 ++
 src/Bpp/Phyl/Model/Protein/LLG08_EX2.cpp           |  116 ++
 src/Bpp/Phyl/Model/Protein/LLG08_EX2.h             |  130 ++
 src/Bpp/Phyl/Model/Protein/LLG08_EX3.cpp           |  117 ++
 src/Bpp/Phyl/Model/Protein/LLG08_EX3.h             |  135 ++
 src/Bpp/Phyl/Model/Protein/LLG08_UL2.cpp           |  116 ++
 src/Bpp/Phyl/Model/Protein/LLG08_UL2.h             |  130 ++
 src/Bpp/Phyl/Model/Protein/LLG08_UL3.cpp           |  117 ++
 src/Bpp/Phyl/Model/Protein/LLG08_UL3.h             |  134 ++
 .../Phyl/Model/Protein/ProteinSubstitutionModel.h  |   75 +
 .../Model/Protein/UserProteinSubstitutionModel.cpp |  167 ++
 .../Model/Protein/UserProteinSubstitutionModel.h   |  161 ++
 src/Bpp/Phyl/Model/Protein/WAG01.cpp               |   92 +
 src/Bpp/Phyl/Model/Protein/WAG01.h                 |  155 ++
 src/Bpp/Phyl/Model/Protein/__CATC10FrequenciesCode |  230 +++
 src/Bpp/Phyl/Model/Protein/__CATC10RatesProps      |   50 +
 src/Bpp/Phyl/Model/Protein/__CATC20FrequenciesCode |  460 +++++
 src/Bpp/Phyl/Model/Protein/__CATC20RatesProps      |  100 ++
 src/Bpp/Phyl/Model/Protein/__CATC30FrequenciesCode |  690 +++++++
 src/Bpp/Phyl/Model/Protein/__CATC30RatesProps      |  150 ++
 src/Bpp/Phyl/Model/Protein/__CATC40FrequenciesCode |  920 ++++++++++
 src/Bpp/Phyl/Model/Protein/__CATC40RatesProps      |  200 +++
 src/Bpp/Phyl/Model/Protein/__CATC50FrequenciesCode | 1150 ++++++++++++
 src/Bpp/Phyl/Model/Protein/__CATC50RatesProps      |  250 +++
 src/Bpp/Phyl/Model/Protein/__CATC60FrequenciesCode | 1380 ++++++++++++++
 src/Bpp/Phyl/Model/Protein/__CATC60RatesProps      |  300 ++++
 .../Phyl/Model/Protein/__DSO78ExchangeabilityCode  |  400 +++++
 src/Bpp/Phyl/Model/Protein/__DSO78FrequenciesCode  |   20 +
 .../Phyl/Model/Protein/__JTT92ExchangeabilityCode  |  400 +++++
 src/Bpp/Phyl/Model/Protein/__JTT92FrequenciesCode  |   20 +
 .../Phyl/Model/Protein/__LG08ExchangeabilityCode   |  400 +++++
 src/Bpp/Phyl/Model/Protein/__LG08FrequenciesCode   |   21 +
 .../Model/Protein/__LLG08_EHOExchangeabilityCode   | 1224 +++++++++++++
 .../Phyl/Model/Protein/__LLG08_EHOFrequenciesCode  |   72 +
 src/Bpp/Phyl/Model/Protein/__LLG08_EHORatesProps   |   18 +
 .../Model/Protein/__LLG08_EX2ExchangeabilityCode   |  816 +++++++++
 .../Phyl/Model/Protein/__LLG08_EX2FrequenciesCode  |   48 +
 src/Bpp/Phyl/Model/Protein/__LLG08_EX2RatesProps   |   12 +
 .../Model/Protein/__LLG08_EX3ExchangeabilityCode   | 1224 +++++++++++++
 .../Phyl/Model/Protein/__LLG08_EX3FrequenciesCode  |   72 +
 src/Bpp/Phyl/Model/Protein/__LLG08_EX3RatesProps   |   18 +
 .../Model/Protein/__LLG08_UL2ExchangeabilityCode   |  816 +++++++++
 .../Phyl/Model/Protein/__LLG08_UL2FrequenciesCode  |   48 +
 src/Bpp/Phyl/Model/Protein/__LLG08_UL2RatesProps   |   12 +
 .../Model/Protein/__LLG08_UL3ExchangeabilityCode   | 1223 +++++++++++++
 .../Phyl/Model/Protein/__LLG08_UL3FrequenciesCode  |   72 +
 src/Bpp/Phyl/Model/Protein/__LLG08_UL3RatesProps   |   18 +
 .../Phyl/Model/Protein/__WAG01ExchangeabilityCode  |  820 +++++++++
 src/Bpp/Phyl/Model/Protein/__WAG01FrequenciesCode  |   21 +
 src/Bpp/Phyl/Model/RE08.cpp                        |  321 ++++
 src/Bpp/Phyl/Model/RE08.h                          |  200 +++
 .../RateDistribution/ConstantRateDistribution.h    |   66 +
 .../ExponentialDiscreteRateDistribution.h          |   66 +
 .../GammaDiscreteRateDistribution.h                |   66 +
 .../GaussianDiscreteRateDistribution.h             |   66 +
 src/Bpp/Phyl/Model/RateDistributionFactory.cpp     |   64 +
 src/Bpp/Phyl/Model/RateDistributionFactory.h       |  110 ++
 src/Bpp/Phyl/Model/StateMap.cpp                    |   53 +
 src/Bpp/Phyl/Model/StateMap.h                      |  166 ++
 src/Bpp/Phyl/Model/SubstitutionModel.h             |  493 +++++
 src/Bpp/Phyl/Model/SubstitutionModelFactory.cpp    |  188 ++
 src/Bpp/Phyl/Model/SubstitutionModelFactory.h      |  131 ++
 src/Bpp/Phyl/Model/SubstitutionModelSet.cpp        |  471 +++++
 src/Bpp/Phyl/Model/SubstitutionModelSet.h          |  590 ++++++
 src/Bpp/Phyl/Model/SubstitutionModelSetTools.cpp   |  211 +++
 src/Bpp/Phyl/Model/SubstitutionModelSetTools.h     |  100 ++
 src/Bpp/Phyl/Model/TS98.h                          |  138 ++
 src/Bpp/Phyl/Model/WordSubstitutionModel.cpp       |  319 ++++
 src/Bpp/Phyl/Model/WordSubstitutionModel.h         |  129 ++
 src/Bpp/Phyl/NNISearchable.h                       |  151 ++
 src/Bpp/Phyl/NNITopologySearch.cpp                 |  367 ++++
 src/Bpp/Phyl/NNITopologySearch.h                   |  172 ++
 src/Bpp/Phyl/Node.cpp                              |  155 ++
 src/Bpp/Phyl/Node.h                                |  697 ++++++++
 src/Bpp/Phyl/NodeTemplate.h                        |  198 ++
 src/Bpp/Phyl/OptimizationTools.cpp                 |  766 ++++++++
 src/Bpp/Phyl/OptimizationTools.h                   |  770 ++++++++
 src/Bpp/Phyl/Parsimony/AbstractTreeParsimonyData.h |  118 ++
 .../Phyl/Parsimony/AbstractTreeParsimonyScore.cpp  |  108 ++
 .../Phyl/Parsimony/AbstractTreeParsimonyScore.h    |  122 ++
 src/Bpp/Phyl/Parsimony/DRTreeParsimonyData.cpp     |  219 +++
 src/Bpp/Phyl/Parsimony/DRTreeParsimonyData.h       |  317 ++++
 src/Bpp/Phyl/Parsimony/DRTreeParsimonyScore.cpp    |  405 +++++
 src/Bpp/Phyl/Parsimony/DRTreeParsimonyScore.h      |  195 ++
 src/Bpp/Phyl/Parsimony/TreeParsimonyData.h         |  115 ++
 src/Bpp/Phyl/Parsimony/TreeParsimonyScore.h        |  102 ++
 src/Bpp/Phyl/PatternTools.cpp                      |  130 ++
 src/Bpp/Phyl/PatternTools.h                        |  108 ++
 src/Bpp/Phyl/PhyloStatistics.cpp                   |  108 ++
 src/Bpp/Phyl/PhyloStatistics.h                     |  109 ++
 src/Bpp/Phyl/Simulation/DetailedSiteSimulator.h    |  250 +++
 .../Phyl/Simulation/HomogeneousSequenceSimulator.h |   77 +
 src/Bpp/Phyl/Simulation/MutationProcess.cpp        |  193 ++
 src/Bpp/Phyl/Simulation/MutationProcess.h          |  379 ++++
 .../Simulation/NonHomogeneousSequenceSimulator.cpp |  526 ++++++
 .../Simulation/NonHomogeneousSequenceSimulator.h   |  335 ++++
 .../Phyl/Simulation/SequenceSimulationTools.cpp    |   92 +
 src/Bpp/Phyl/Simulation/SequenceSimulationTools.h  |  103 ++
 src/Bpp/Phyl/Simulation/SequenceSimulator.h        |   74 +
 src/Bpp/Phyl/Simulation/SiteSimulator.h            |   73 +
 src/Bpp/Phyl/SitePatterns.cpp                      |  118 ++
 src/Bpp/Phyl/SitePatterns.h                        |  187 ++
 src/Bpp/Phyl/TopologySearch.h                      |  157 ++
 src/Bpp/Phyl/Tree.h                                |  410 +++++
 src/Bpp/Phyl/TreeExceptions.cpp                    |   78 +
 src/Bpp/Phyl/TreeExceptions.h                      |  281 +++
 src/Bpp/Phyl/TreeTemplate.h                        |  541 ++++++
 src/Bpp/Phyl/TreeTemplateTools.cpp                 | 1187 ++++++++++++
 src/Bpp/Phyl/TreeTemplateTools.h                   | 1246 +++++++++++++
 src/Bpp/Phyl/TreeTools.cpp                         | 1263 +++++++++++++
 src/Bpp/Phyl/TreeTools.h                           |  715 ++++++++
 src/CMakeLists.txt                                 |  366 ++++
 test/CMakeLists.txt                                |   86 +
 test/example1.mp.dnd                               |    2 +
 test/example1.ph                                   |    6 +
 test/test_bowker.cpp                               |  163 ++
 test/test_detailed_simulations.cpp                 |  110 ++
 test/test_likelihood.cpp                           |  101 ++
 test/test_likelihood_clock.cpp                     |  134 ++
 test/test_likelihood_nh.cpp                        |  156 ++
 test/test_mapping.cpp                              |  296 +++
 test/test_mapping_codon.cpp                        |  229 +++
 test/test_models.cpp                               |  128 ++
 test/test_nhx.cpp                                  |   82 +
 test/test_parsimony.cpp                            |   69 +
 test/test_simulations.cpp                          |  147 ++
 test/test_tree.cpp                                 |  245 +++
 395 files changed, 98401 insertions(+)

diff --git a/AUTHORS.txt b/AUTHORS.txt
new file mode 100644
index 0000000..0aba1e4
--- /dev/null
+++ b/AUTHORS.txt
@@ -0,0 +1,23 @@
+Julien Dutheil     <julien.dutheil at univ-montp2.fr>
+Vincent Ranwez     <ranwez at univ-montp2.fr>
+Nicolas Galtier    <galtier at univ-montp2.fr>
+Bastien Boussau    <bastien.boussau at univ-lyon1.fr>
+Céline Scornavacca <celine.scornavacca at lirmm.fr>
+Laurent Guéguen    <laurent.gueguen at univ-lyon1.fr>
+Nicolas Rochette   <nicolas.rochette at univ-lyon1.fr>
+
+Contributed code to Bio++ was enabled thanks to the following institutions and resources:
+
+2002 - 2006 Laboratoire GPIA - UMR CNRS 5171 Université Montpellier 2 (Eric Bazin, Khalid Belkhir, Guillaume Deuchst, Julien Dutheil, Sylvain Gaillard, Nicolas Galtier, Sylvain Glémin)
+2005 -      ISE-M UMR CNRS 5554 Université Montpellier 2 (Vincent Ranwez, Céline Scornavacca)
+2006 -      ISE-M UMR CNRS 5554 Université Montpellier 2 (Khalid Belkhir, Nicolas Galtier, Sylvain Glémin)
+2006 - 2007 ISE-M UMR CNRS 5554 Université Montpellier 2 (Julien Dutheil)
+2007 - 2010 Bioinformatics Research Center, University of Aarhus (Julien Dutheil).
+            Funded by European research Area on Plant Genomics (ERA-PG) ARelatives.
+2010 -      ISE-M UMR CNRS 5554 Université Montpellier 2 (Julien Dutheil)
+2011 -      Max Planck Institute for Terrestrial Microbiology (Julien Dutheil)
+2007 -      Genetics and Horticulture UMR INRA 1259 Angers-Nantes INRA Center (Sylvain Gaillard)
+2008 - 2009 Laboratoire BBE - UMR CNRS 5558 Université Lyon 1 (Bastien Boussau)
+2009 - 2010 Berkeley University (Bastien Boussau)
+2010 -      Laboratoire BBE - UMR CNRS 5558 Université Lyon 1 (Bastien Boussau)   
+2008 -      Laboratoire BBE - UMR CNRS 5558 Université Lyon 1 (Laurent Guéguen)
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..72d0254
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,190 @@
+# CMake script for Bio++ PhylLib
+# Author: Sylvain Gaillard and Julien Dutheil
+# Created: 20/08/2009
+
+# Global parameters
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(bpp-phyl CXX)
+IF(NOT CMAKE_BUILD_TYPE)
+  SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
+      "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
+      FORCE)
+ENDIF(NOT CMAKE_BUILD_TYPE)
+
+SET(CMAKE_CXX_FLAGS "-Wall -Wshadow -Weffc++ -Wconversion")
+IF(NOT NO_VIRTUAL_COV)
+  SET(NO_VIRTUAL_COV FALSE CACHE BOOL
+      "Disable covariant return type with virtual inheritance, for compilers that do not support it."
+      FORCE)
+ENDIF(NOT NO_VIRTUAL_COV)
+
+IF(NO_VIRTUAL_COV)
+  MESSAGE("-- Covariant return with virtual inheritance disabled.")
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNO_VIRTUAL_COV=1")
+ENDIF(NO_VIRTUAL_COV)
+
+IF(NOT NO_DEP_CHECK)
+  SET(NO_DEP_CHECK FALSE CACHE BOOL
+      "Disable dependencies check for building distribution only."
+      FORCE)
+ENDIF(NOT NO_DEP_CHECK)
+
+IF(NO_DEP_CHECK)
+  MESSAGE("-- Dependencies checking disabled. Only distribution can be built.")
+ELSE(NO_DEP_CHECK)
+
+# Libtool-like version number
+# CURRENT:REVISION:AGE => file.so.(C-A).A.R
+# current:  The most recent interface number that this library implements.
+# revision: The implementation number of the current interface.
+# age:      The difference between the newest and oldest interfaces that this
+#           library implements.
+# In other words, the library implements all the interface numbers in the
+# range from number current - age to current.
+SET(BPPPHYL_VERSION_CURRENT "10")
+SET(BPPPHYL_VERSION_REVISION "3")
+SET(BPPPHYL_VERSION_AGE "1")
+
+# Effective version number computation
+MATH(EXPR BPPPHYL_VERSION_MAJOR "${BPPPHYL_VERSION_CURRENT} - ${BPPPHYL_VERSION_AGE}")
+SET(BPPPHYL_VERSION_MINOR ${BPPPHYL_VERSION_AGE})
+SET(BPPPHYL_VERSION_PATCH ${BPPPHYL_VERSION_REVISION})
+SET(BPPPHYL_VERSION "${BPPPHYL_VERSION_MAJOR}.${BPPPHYL_VERSION_MINOR}.${BPPPHYL_VERSION_PATCH}")
+
+# Set the CMAKE_PREFIX_PATH for the find_library fonction when using non
+# standard install location
+IF(CMAKE_INSTALL_PREFIX)
+  SET(CMAKE_PREFIX_PATH "${CMAKE_INSTALL_PREFIX}" ${CMAKE_PREFIX_PATH})
+ENDIF(CMAKE_INSTALL_PREFIX)
+
+#here is a useful function:
+MACRO(IMPROVED_FIND_LIBRARY OUTPUT_LIBS lib_name include_to_find)
+  #start:
+  FIND_PATH(${lib_name}_INCLUDE_DIR ${include_to_find})
+  SET(${lib_name}_NAMES ${lib_name} ${lib_name}lib ${lib_name}dll)
+  FIND_LIBRARY(${lib_name}_LIBRARY NAMES ${${lib_name}_NAMES} PATH_SUFFIXES lib${LIB_SUFFIX})
+
+  IF(${lib_name}_LIBRARY)
+    MESSAGE("-- Library ${lib_name} found here:")
+    MESSAGE("   includes : ${${lib_name}_INCLUDE_DIR}")
+    MESSAGE("   libraries: ${${lib_name}_LIBRARY}")
+  ELSE(${lib_name}_LIBRARY)
+    MESSAGE(FATAL_ERROR "${lib_name} required but not found.")
+  ENDIF(${lib_name}_LIBRARY)
+  
+  #add the dependency:
+  INCLUDE_DIRECTORIES(${${lib_name}_INCLUDE_DIR})
+  SET(${OUTPUT_LIBS} ${${OUTPUT_LIBS}} ${${lib_name}_LIBRARY})
+ENDMACRO(IMPROVED_FIND_LIBRARY)
+
+#Find the Bio++ libraries:
+IMPROVED_FIND_LIBRARY(LIBS bpp-seq Bpp/Seq/Alphabet/Alphabet.h)
+IMPROVED_FIND_LIBRARY(LIBS bpp-core Bpp/Clonable.h)
+
+# Subdirectories
+ADD_SUBDIRECTORY(src)
+
+# Doxygen
+FIND_PACKAGE(Doxygen)
+IF (DOXYGEN_FOUND)
+  ADD_CUSTOM_TARGET (apidoc cp Doxyfile ${CMAKE_BINARY_DIR}/Doxyfile-build
+    COMMAND echo "OUTPUT_DIRECTORY=${CMAKE_BINARY_DIR}" >> ${CMAKE_BINARY_DIR}/Doxyfile-build
+    COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile-build
+    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+  ADD_CUSTOM_TARGET (apidoc-stable cp Doxyfile ${CMAKE_BINARY_DIR}/Doxyfile-stable
+    COMMAND echo "OUTPUT_DIRECTORY=${CMAKE_BINARY_DIR}" >> ${CMAKE_BINARY_DIR}/Doxyfile-stable
+    COMMAND echo "HTML_HEADER=header.html" >> ${CMAKE_BINARY_DIR}/Doxyfile-stable
+    COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile-stable
+    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+ENDIF (DOXYGEN_FOUND)
+
+ENDIF(NO_DEP_CHECK)
+
+# Packager
+SET(CPACK_PACKAGE_NAME "libbpp-phyl")
+SET(CPACK_PACKAGE_VENDOR "Bio++ Development Team")
+SET(CPACK_PACKAGE_VERSION "2.1.0")
+SET(CPACK_PACKAGE_VERSION_MAJOR "2")
+SET(CPACK_PACKAGE_VERSION_MINOR "1")
+SET(CPACK_PACKAGE_VERSION_PATCH "0")
+SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The Bio++ Phylogenetics library")
+SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING.txt")
+SET(CPACK_RESOURCE_FILE_AUTHORS "${CMAKE_SOURCE_DIR}/AUTHORS.txt")
+SET(CPACK_RESOURCE_FILE_INSTALL "${CMAKE_SOURCE_DIR}/INSTALL.txt")
+SET(CPACK_SOURCE_GENERATOR "TGZ")
+SET(CPACK_SOURCE_IGNORE_FILES
+ "CMakeFiles"
+ "Makefile"
+ "_CPack_Packages"
+ "CMakeCache.txt"
+ ".*\\\\.cmake"
+ ".*\\\\.git"
+ ".*\\\\.gz"
+ ".*\\\\.deb"
+ ".*\\\\.rpm"
+ ".*\\\\.dmg"
+ ".*\\\\.sh"
+ ".*\\\\..*\\\\.swp"
+ "src/\\\\..*"
+ "src/libbpp*"
+ "test/tmp_*"
+ "tmp_*"
+ "debian/tmp"
+ "debian/libbpp.*/"
+ "debian/libbpp.*\\\\.so.*"
+ "debian/libbpp.*\\\\.a"
+ "debian/libbpp.*\\\\.substvars"
+ "debian/libbpp.*\\\\.debhelper"
+ "debian/debhelper\\\\.log"
+ "html"
+ "Phyl.tag"
+ "Testing"
+ "build-stamp"
+ "install_manifest.txt"
+ "DartConfiguration.tcl"
+ ${CPACK_SOURCE_IGNORE_FILES}
+)
+IF (MACOS)
+  SET(CPACK_GENERATOR "Bundle")
+ENDIF()
+
+SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+SET(CPACK_DEBSOURCE_PACKAGE_FILE_NAME "lib${CMAKE_PROJECT_NAME}_${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}.orig")
+INCLUDE(CPack)
+
+#This adds the 'dist' target
+ADD_CUSTOM_TARGET(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
+# 'clean' is not (yet) a first class target. However, we need to clean the directories before building the sources:
+IF("${CMAKE_GENERATOR}" MATCHES "Make")
+  ADD_CUSTOM_TARGET(make_clean
+  COMMAND ${CMAKE_MAKE_PROGRAM} clean
+  WORKING_DIRECTORY ${CMAKE_CURRENT_DIR}
+  )
+  ADD_DEPENDENCIES(dist make_clean)
+ENDIF()
+
+IF(NOT NO_DEP_CHECK)
+IF (UNIX)
+#This creates deb packages:
+ADD_CUSTOM_TARGET(origdist COMMAND cp ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.gz ../${CPACK_DEBSOURCE_PACKAGE_FILE_NAME}.tar.gz)
+ADD_DEPENDENCIES(origdist dist)
+ADD_CUSTOM_TARGET(deb dpkg-buildpackage -uc -us -i${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.gz)
+ADD_DEPENDENCIES(deb origdist)
+
+#This creates rpm packages:
+ADD_CUSTOM_TARGET(rpm rpmbuild -ta ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.gz)
+ADD_DEPENDENCIES(rpm dist)
+
+ENDIF()
+
+SET(CTEST_UPDATE_TYPE git)
+SET(UPDATE_COMMAND "git")
+SET(UPDATE_OPTIONS "")
+
+ENABLE_TESTING()
+INCLUDE(CTest)
+IF (BUILD_TESTING)
+  ADD_SUBDIRECTORY(test)
+ENDIF(BUILD_TESTING)
+
+ENDIF(NOT NO_DEP_CHECK)
diff --git a/COPYING.txt b/COPYING.txt
new file mode 100644
index 0000000..7e84b53
--- /dev/null
+++ b/COPYING.txt
@@ -0,0 +1,505 @@
+
+               CeCILL FREE SOFTWARE LICENSE AGREEMENT
+
+
+    Notice
+
+This Agreement is a Free Software license agreement that is the result
+of discussions between its authors in order to ensure compliance with
+the two main principles guiding its drafting:
+
+    * firstly, compliance with the principles governing the distribution
+      of Free Software: access to source code, broad rights granted to
+      users,
+    * secondly, the election of a governing law, French law, with which
+      it is conformant, both as regards the law of torts and
+      intellectual property law, and the protection that it offers to
+      both authors and holders of the economic rights over software.
+
+The authors of the CeCILL (for Ce[a] C[nrs] I[nria] L[logiciel] L[ibre])
+license are:
+
+Commissariat à l'Energie Atomique - CEA, a public scientific, technical
+and industrial establishment, having its principal place of business at
+31-33 rue de la Fédération, 75752 Paris cedex 15, France.
+
+Centre National de la Recherche Scientifique - CNRS, a public scientific
+and technological establishment, having its principal place of business
+at 3 rue Michel-Ange 75794 Paris cedex 16, France.
+
+Institut National de Recherche en Informatique et en Automatique -
+INRIA, a public scientific and technological establishment, having its
+principal place of business at Domaine de Voluceau, Rocquencourt, BP
+105, 78153 Le Chesnay cedex, France.
+
+
+    Preamble
+
+The purpose of this Free Software license agreement is to grant users
+the right to modify and redistribute the software governed by this
+license within the framework of an open source distribution model.
+
+The exercising of these rights is conditional upon certain obligations
+for users so as to preserve this status for all subsequent redistributions.
+
+In consideration of access to the source code and the rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty and the software's author, the holder of the
+economic rights, and the successive licensors only have limited liability.
+
+In this respect, the risks associated with loading, using, modifying
+and/or developing or reproducing the software by the user are brought to
+the user's attention, given its Free Software status, which may make it
+complicated to use, with the result that its use is reserved for
+developers and experienced professionals having in-depth computer
+knowledge. Users are therefore encouraged to load and test the
+Software's suitability as regards their requirements in conditions
+enabling the security of their systems and/or data to be ensured and,
+more generally, to use and operate it in the same conditions of
+security. This Agreement may be freely reproduced and published,
+provided it is not altered, and that no provisions are either added or
+removed herefrom.
+
+This Agreement may apply to any or all software for which the holder of
+the economic rights decides to submit the use thereof to its provisions.
+
+
+    Article 1 - DEFINITIONS
+
+For the purpose of this Agreement, when the following expressions
+commence with a capital letter, they shall have the following meaning:
+
+Agreement: means this license agreement, and its possible subsequent
+versions and annexes.
+
+Software: means the software in its Object Code and/or Source Code form
+and, where applicable, its documentation, "as is" when the Licensee
+accepts the Agreement.
+
+Initial Software: means the Software in its Source Code and possibly its
+Object Code form and, where applicable, its documentation, "as is" when
+it is first distributed under the terms and conditions of the Agreement.
+
+Modified Software: means the Software modified by at least one
+Contribution.
+
+Source Code: means all the Software's instructions and program lines to
+which access is required so as to modify the Software.
+
+Object Code: means the binary files originating from the compilation of
+the Source Code.
+
+Holder: means the holder(s) of the economic rights over the Initial
+Software.
+
+Licensee: means the Software user(s) having accepted the Agreement.
+
+Contributor: means a Licensee having made at least one Contribution.
+
+Licensor: means the Holder, or any other individual or legal entity, who
+distributes the Software under the Agreement.
+
+Contribution: means any or all modifications, corrections, translations,
+adaptations and/or new functions integrated into the Software by any or
+all Contributors, as well as any or all Internal Modules.
+
+Module: means a set of sources files including their documentation that
+enables supplementary functions or services in addition to those offered
+by the Software.
+
+External Module: means any or all Modules, not derived from the
+Software, so that this Module and the Software run in separate address
+spaces, with one calling the other when they are run.
+
+Internal Module: means any or all Module, connected to the Software so
+that they both execute in the same address space.
+
+GNU GPL: means the GNU General Public License version 2 or any
+subsequent version, as published by the Free Software Foundation Inc.
+
+Parties: mean both the Licensee and the Licensor.
+
+These expressions may be used both in singular and plural form.
+
+
+    Article 2 - PURPOSE
+
+The purpose of the Agreement is the grant by the Licensor to the
+Licensee of a non-exclusive, transferable and worldwide license for the
+Software as set forth in Article 5 hereinafter for the whole term of the 
+protection granted by the rights over said Software.
+
+
+    Article 3 - ACCEPTANCE
+
+3.1 The Licensee shall be deemed as having accepted the terms and
+conditions of this Agreement upon the occurrence of the first of the
+following events:
+
+    * (i) loading the Software by any or all means, notably, by
+      downloading from a remote server, or by loading from a physical
+      medium;
+    * (ii) the first time the Licensee exercises any of the rights
+      granted hereunder.
+
+3.2 One copy of the Agreement, containing a notice relating to the
+characteristics of the Software, to the limited warranty, and to the
+fact that its use is restricted to experienced users has been provided
+to the Licensee prior to its acceptance as set forth in Article 3.1
+hereinabove, and the Licensee hereby acknowledges that it has read and 
+understood it.
+
+
+    Article 4 - EFFECTIVE DATE AND TERM
+
+
+      4.1 EFFECTIVE DATE
+
+The Agreement shall become effective on the date when it is accepted by
+the Licensee as set forth in Article 3.1.
+
+
+      4.2 TERM
+
+The Agreement shall remain in force for the entire legal term of
+protection of the economic rights over the Software.
+
+
+    Article 5 - SCOPE OF RIGHTS GRANTED
+
+The Licensor hereby grants to the Licensee, who accepts, the following
+rights over the Software for any or all use, and for the term of the
+Agreement, on the basis of the terms and conditions set forth hereinafter.
+
+Besides, if the Licensor owns or comes to own one or more patents
+protecting all or part of the functions of the Software or of its
+components, the Licensor undertakes not to enforce the rights granted by
+these patents against successive Licensees using, exploiting or
+modifying the Software. If these patents are transferred, the Licensor
+undertakes to have the transferees subscribe to the obligations set
+forth in this paragraph.
+
+
+      5.1 RIGHT OF USE
+
+The Licensee is authorized to use the Software, without any limitation
+as to its fields of application, with it being hereinafter specified
+that this comprises:
+
+   1. permanent or temporary reproduction of all or part of the Software
+      by any or all means and in any or all form.
+
+   2. loading, displaying, running, or storing the Software on any or
+      all medium.
+
+   3. entitlement to observe, study or test its operation so as to
+      determine the ideas and principles behind any or all constituent
+      elements of said Software. This shall apply when the Licensee
+      carries out any or all loading, displaying, running, transmission
+      or storage operation as regards the Software, that it is entitled
+      to carry out hereunder.
+
+
+      5.2 ENTITLEMENT TO MAKE CONTRIBUTIONS
+
+The right to make Contributions includes the right to translate, adapt,
+arrange, or make any or all modifications to the Software, and the right
+to reproduce the resulting Software.
+
+The Licensee is authorized to make any or all Contributions to the
+Software provided that it includes an explicit notice that it is the
+author of said Contribution and indicates the date of the creation thereof.
+
+
+      5.3 RIGHT OF DISTRIBUTION
+
+In particular, the right of distribution includes the right to publish,
+transmit and communicate the Software to the general public on any or
+all medium, and by any or all means, and the right to market, either in
+consideration of a fee, or free of charge, one or more copies of the
+Software by any means.
+
+The Licensee is further authorized to distribute copies of the modified
+or unmodified Software to third parties according to the terms and
+conditions set forth hereinafter.
+
+
+        5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION
+
+The Licensee is authorized to distribute true copies of the Software in
+Source Code or Object Code form, provided that said distribution
+complies with all the provisions of the Agreement and is accompanied by:
+
+   1. a copy of the Agreement,
+
+   2. a notice relating to the limitation of both the Licensor's
+      warranty and liability as set forth in Articles 8 and 9,
+
+and that, in the event that only the Object Code of the Software is
+redistributed, the Licensee allows future Licensees unhindered access to
+the full Source Code of the Software by indicating how to access it, it
+being understood that the additional cost of acquiring the Source Code
+shall not exceed the cost of transferring the data.
+
+
+        5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE
+
+When the Licensee makes a Contribution to the Software, the terms and
+conditions for the distribution of the Modified Software become subject
+to all the provisions of this Agreement.
+
+The Licensee is authorized to distribute the Modified Software, in
+Source Code or Object Code form, provided that said distribution
+complies with all the provisions of the Agreement and is accompanied by:
+
+   1. a copy of the Agreement,
+
+   2. a notice relating to the limitation of both the Licensor's
+      warranty and liability as set forth in Articles 8 and 9,
+
+and that, in the event that only the Object Code of the Modified
+Software is redistributed, the Licensee allows future Licensees
+unhindered access to the full Source Code of the Modified Software by
+indicating how to access it, it being understood that the additional
+cost of acquiring the Source Code shall not exceed the cost of
+transferring the data.
+
+
+        5.3.3 DISTRIBUTION OF EXTERNAL MODULES
+
+When the Licensee has developed an External Module, the terms and
+conditions of this Agreement do not apply to said External Module, that
+may be distributed under a separate license agreement.
+
+
+        5.3.4 COMPATIBILITY WITH THE GNU GPL
+
+The Licensee can include a code that is subject to the provisions of one
+of the versions of the GNU GPL in the Modified or unmodified Software,
+and distribute that entire code under the terms of the same version of
+the GNU GPL.
+
+The Licensee can include the Modified or unmodified Software in a code
+that is subject to the provisions of one of the versions of the GNU GPL,
+and distribute that entire code under the terms of the same version of
+the GNU GPL.
+
+
+    Article 6 - INTELLECTUAL PROPERTY
+
+
+      6.1 OVER THE INITIAL SOFTWARE
+
+The Holder owns the economic rights over the Initial Software. Any or
+all use of the Initial Software is subject to compliance with the terms
+and conditions under which the Holder has elected to distribute its work
+and no one shall be entitled to modify the terms and conditions for the
+distribution of said Initial Software.
+
+The Holder undertakes that the Initial Software will remain ruled at
+least by the current license, for the duration set forth in article 4.2.
+
+
+      6.2 OVER THE CONTRIBUTIONS
+
+A Licensee who develops a Contribution is the owner of the intellectual
+property rights over this Contribution as defined by applicable law.
+
+
+      6.3 OVER THE EXTERNAL MODULES
+
+A Licensee who develops an External Module is the owner of the
+intellectual property rights over this External Module as defined by
+applicable law and is free to choose the type of agreement that shall
+govern its distribution.
+
+
+      6.4 JOINT PROVISIONS
+
+The Licensee expressly undertakes:
+
+   1. not to remove, or modify, in any manner, the intellectual property
+      notices attached to the Software;
+
+   2. to reproduce said notices, in an identical manner, in the copies
+      of the Software modified or not.
+
+The Licensee undertakes not to directly or indirectly infringe the
+intellectual property rights of the Holder and/or Contributors on the
+Software and to take, where applicable, vis-à-vis its staff, any and all
+measures required to ensure respect of said intellectual property rights
+of the Holder and/or Contributors.
+
+
+    Article 7 - RELATED SERVICES
+
+7.1 Under no circumstances shall the Agreement oblige the Licensor to
+provide technical assistance or maintenance services for the Software.
+
+However, the Licensor is entitled to offer this type of services. The
+terms and conditions of such technical assistance, and/or such
+maintenance, shall be set forth in a separate instrument. Only the
+Licensor offering said maintenance and/or technical assistance services
+shall incur liability therefor.
+
+7.2 Similarly, any Licensor is entitled to offer to its licensees, under
+its sole responsibility, a warranty, that shall only be binding upon
+itself, for the redistribution of the Software and/or the Modified
+Software, under terms and conditions that it is free to decide. Said
+warranty, and the financial terms and conditions of its application,
+shall be subject of a separate instrument executed between the Licensor
+and the Licensee.
+
+
+    Article 8 - LIABILITY
+
+8.1 Subject to the provisions of Article 8.2, the Licensee shall be
+entitled to claim compensation for any direct loss it may have suffered
+from the Software as a result of a fault on the part of the relevant
+Licensor, subject to providing evidence thereof.
+
+8.2 The Licensor's liability is limited to the commitments made under
+this Agreement and shall not be incurred as a result of in particular:
+(i) loss due the Licensee's total or partial failure to fulfill its
+obligations, (ii) direct or consequential loss that is suffered by the
+Licensee due to the use or performance of the Software, and (iii) more
+generally, any consequential loss. In particular the Parties expressly
+agree that any or all pecuniary or business loss (i.e. loss of data,
+loss of profits, operating loss, loss of customers or orders,
+opportunity cost, any disturbance to business activities) or any or all
+legal proceedings instituted against the Licensee by a third party,
+shall constitute consequential loss and shall not provide entitlement to
+any or all compensation from the Licensor.
+
+
+    Article 9 - WARRANTY
+
+9.1 The Licensee acknowledges that the scientific and technical
+state-of-the-art when the Software was distributed did not enable all
+possible uses to be tested and verified, nor for the presence of
+possible defects to be detected. In this respect, the Licensee's
+attention has been drawn to the risks associated with loading, using,
+modifying and/or developing and reproducing the Software which are
+reserved for experienced users.
+
+The Licensee shall be responsible for verifying, by any or all means,
+the product's suitability for its requirements, its good working order,
+and for ensuring that it shall not cause damage to either persons or
+properties.
+
+9.2 The Licensor hereby represents, in good faith, that it is entitled
+to grant all the rights over the Software (including in particular the
+rights set forth in Article 5).
+
+9.3 The Licensee acknowledges that the Software is supplied "as is" by
+the Licensor without any other express or tacit warranty, other than
+that provided for in Article 9.2 and, in particular, without any warranty
+as to its commercial value, its secured, safe, innovative or relevant 
+nature.
+
+Specifically, the Licensor does not warrant that the Software is free
+from any error, that it will operate without interruption, that it will
+be compatible with the Licensee's own equipment and software
+configuration, nor that it will meet the Licensee's requirements.
+
+9.4 The Licensor does not either expressly or tacitly warrant that the
+Software does not infringe any third party intellectual property right
+relating to a patent, software or any other property right. Therefore,
+the Licensor disclaims any and all liability towards the Licensee
+arising out of any or all proceedings for infringement that may be
+instituted in respect of the use, modification and redistribution of the
+Software. Nevertheless, should such proceedings be instituted against
+the Licensee, the Licensor shall provide it with technical and legal
+assistance for its defense. Such technical and legal assistance shall be
+decided on a case-by-case basis between the relevant Licensor and the
+Licensee pursuant to a memorandum of understanding. The Licensor
+disclaims any and all liability as regards the Licensee's use of the
+name of the Software. No warranty is given as regards the existence of
+prior rights over the name of the Software or as regards the existence
+of a trademark.
+
+
+    Article 10 - TERMINATION
+
+10.1 In the event of a breach by the Licensee of its obligations
+hereunder, the Licensor may automatically terminate this Agreement
+thirty (30) days after notice has been sent to the Licensee and has
+remained ineffective.
+
+10.2 A Licensee whose Agreement is terminated shall no longer be
+authorized to use, modify or distribute the Software. However, any
+licenses that it may have granted prior to termination of the Agreement
+shall remain valid subject to their having been granted in compliance
+with the terms and conditions hereof.
+
+
+    Article 11 - MISCELLANEOUS
+
+
+      11.1 EXCUSABLE EVENTS
+
+Neither Party shall be liable for any or all delay, or failure to
+perform the Agreement, that may be attributable to an event of force
+majeure, an act of God or an outside cause, such as defective
+functioning or interruptions of the electricity or telecommunications
+networks, network paralysis following a virus attack, intervention by
+government authorities, natural disasters, water damage, earthquakes,
+fire, explosions, strikes and labor unrest, war, etc.
+
+11.2 Any Failure by either Party, on one or more occasions, to invoke
+one or more of the provisions hereof, shall under no circumstances be
+interpreted as being a waiver by the interested Party of its right to
+invoke said provision(s) subsequently.
+
+11.3 The Agreement cancels and replaces any or all previous agreements,
+whether written or oral, between the Parties and having the same
+purpose, and constitutes the entirety of the agreement between said
+Parties concerning said purpose. No supplement or modification to the
+terms and conditions hereof shall be effective as between the Parties
+unless it is made in writing and signed by their duly authorized
+representatives.
+
+11.4 In the event that one or more of the provisions hereof were to
+conflict with a current or future applicable act or legislative text,
+said act or legislative text shall prevail, and the Parties shall make
+the necessary amendments so as to comply with said act or legislative
+text. All other provisions shall remain effective. Similarly, invalidity
+of a provision of the Agreement, for any reason whatsoever, shall not
+cause the Agreement as a whole to be invalid.
+
+
+      11.5 LANGUAGE
+
+The Agreement is drafted in both French and English and both versions
+are deemed authentic.
+
+
+    Article 12 - NEW VERSIONS OF THE AGREEMENT
+
+12.1 Any person is authorized to duplicate and distribute copies of this
+Agreement.
+
+12.2 So as to ensure coherence, the wording of this Agreement is
+protected and may only be modified by the authors of the License, who
+reserve the right to periodically publish updates or new versions of the
+Agreement, each with a separate number. These subsequent versions may
+address new issues encountered by Free Software.
+
+12.3 Any Software distributed under a given version of the Agreement may
+only be subsequently distributed under the same version of the Agreement
+or a subsequent version, subject to the provisions of Article 5.3.4.
+
+
+    Article 13 - GOVERNING LAW AND JURISDICTION
+
+13.1 The Agreement is governed by French law. The Parties agree to
+endeavor to seek an amicable solution to any disagreements or disputes
+that may arise during the performance of the Agreement.
+
+13.2 Failing an amicable solution within two (2) months as from their
+occurrence, and unless emergency proceedings are necessary, the
+disagreements or disputes shall be referred to the Paris Courts having
+jurisdiction, by the more diligent Party.
+
+
+Version 2.0 dated 2005-05-21.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..aa599bb
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,615 @@
+07/03/13 -*- Version 2.1.0 -*-
+
+06/03/13 Nicolas Rochette
+* Bug #71 fixed.
+
+24/01/13 Julien Dutheil
+* Bug fixed in NHX parser: node ids are now properly set.
+
+20/01/13 Julien Dutheil
+* bpp-phyl now compiles with -Wconversion.
+
+13/01/13 Julien Dutheil
+* Added new COaLA protein substitution model.
+
+18/11/12 Julien Dutheil
+* New RateDistribution classes.
+* Better BppO parser and PhylogeneticsApplicationTools.
+
+26/08/12 Julien Dutheil
+* Bug #57 fixed in distance methods
+  
+13/06/12 Julien Dutheil
+* Added new class StateMap, and enable support for gaps in parsimony calculation.
+
+09/02/12 -*- Version 2.0.3 -*-
+
+08/02/12 L. Guéguen
+* PseudoNewtonOptimizer accepts to stop after too many trials
+
+08/02/12 Julien Dutheil
+* Newick parsing improved!
+
+19/01/12 L. Guéguen
+* Complex eigenvalues are taken into account
+
+16/01/12 Julien Dutheil
+* Bug #43 solved.
+* Bug #41 solved.
+
+16/12/11 L. Guéguen
+* Addition of neigbour-dependent models
+
+23/09/11 L. Guéguen
+* New hierarchy in codon models
+
+26/07/11 L. Guéguen
+* Mgmt of constraints (paths) between submodels in non-homogeneous trees with mixed models
+
+19/07/11 L. Guéguen
+* Biblio models
+
+16/06/11 Julien Dutheil
+* Bug #40 solved.
+* Bug #16 solved (with a small change in interface).
+
+09/06/11 -*- Version 2.0.2 -*-
+
+09/06/11 Julien Dutheil
+* Removed COA model, which was buggy (and not used). A fixed version will be added once it is published.
+
+08/04/11 Julien Dutheil (after suggestion from Mathieu Groussin)
+* Added backup system in optimization of likelihood function.
+
+19/03/11 Julien Dutheil
+* Added uniformization method for analytical substitution mapping.
+
+18/03/11 Julien Dutheil
+* Added the decomposition method in order to perform analytical substitution mapping (cf work by Asger Hobolth and co-workers).
+
+28/02/11 -*- Version 2.0.1 -*-
+
+25/02/11 Julien Dutheil
+* Improve drawing algorithms.
+
+18/02/11 Julien Dutheil
+* Fixed bug #27
+
+07/02/11 -*- Version 2.0.0 -*-
+
+07/02/11 Julien Dutheil
+* Proposed a fix for bug #25. SubstitutionModelSet now inherits from
+  ParameterAliasable.
+
+02/12/10 Julien Dutheil
+* Improved SubstitutionCount class to allow multiple counts.
+* Added simple GC<->AT substitution count.
+
+15/11/10 Julien Dutheil
+* Added topology comparison tools.
+* New unit testing framework.
+
+18/05/10 Julien Dutheil
+* new TreeDrawing framework, fully event-driven.
+
+24/03/10 -*- Version 1.9.0 -*-
+
+11/03/10 Julien Dutheil
+* Nexus format now allows lower case keywords ([biopp-devel-forum:287])
+* GY94 and MG94 now have frequency option like YN98.
+
+10/03/10 Julien Dutheil
+* Added stationarity option in non-homogeneous models.
+
+09/03/10 Julien Dutheil
+* Added reparametrization option in optimization methods.
+
+26/02/10 Nicolas Rochette and Julien Dutheil
+* More efficient TreeTemplateTools::getDistanceMatrix.
+
+08/12/10 Julien Dutheil
+* Now compiles with -Weffc++!
+* A lot of code updates and small bugs fixed!
+* BioNJ is now faster when using the full constructor.
+* Parsimony and Likelihood data structure improved.
+* Nucleotide and ProteinSubstitutionModels are now full interfaces.
+* No more ProteinSubstitutionModelWithFrequencies... corresponding models take
+as input an optional FrequenciesSet object.
+
+29/12/09 Julien Dutheil
+* Improved TreeDrawing classes: added Listeners.
+
+26/12/09 Julien Dutheil
+* Removed all "using namespace std" in header files.
+* Code cleaning.
+
+15/12/09 Laurent Guegen
+* Added classes for mixed models.
+
+08/12/09 Julien Dutheil
+* First draft of new TreeLikelihood model iterators
+* Updated TreeLikelihood interfaces
+* New interface SitePartitionTreeLikelihood interface, allowing different
+  sites to have a distinct substitution model.
+
+24/11/09 Julien Dutheil
+* Cleaned substitution mapping classes, and added a new one.
+
+31/10/09 Julien Dutheil
+* Code cleaning in FrequenciesSet.
+
+19/10/09 Julien Dutheil
+* Bug fixed in node setFather method + new check and warning messages in tree
+  edition methods.
+
+21/08/09 Julien Dutheil
+* Added config files for CMake.
+
+12/08/09 Bastien Boussau & Julien Dutheil
+* Function getValue in likelihood classes now does not repeat calculations
+  if called several times on the same parameters.
+
+09/08/09 Julien Dutheil
+* Added PhyloStatistics class for computing several quantities on a tree
+  in an efficient manner.
+
+08/08/09 Bastien Boussau
+* Added support for reading trees with id in TreeTemplateTools.
+
+07/08/09 Sophie Abby & Julien Dutheil
+* [biopp-help-forum:214] Bug fixed in cloneSubtree, remove the link toward the
+father node of the root node of the subtree.
+
+05/08/09 Julien Dutheil
+* TreeDrawing classes improved.
+
+22/07/09 Julien Dutheil
+* Added TreeDrawing classes.
+
+29/06/09 Julien Dutheil
+* Upgraded TreeLikelihood interfaces and SubstitutionModel interface + code lifting.
+* New class TreeLikelihoodTools
+* Added computation of expected ancestral frequencies.
+* Added computation of ancestral frequencies using an empirical bayesian
+  approach.
+
+27/06/09 Céline Scornavacca & Julien Dutheil
+* Newick and Nexus tree output now use polymorphism in order to print
+TreeTemplate objects more efficiently.
+
+24/06/09 Julien Dutheil
+* Change precision output while printing parameters.
+
+24/06/09 Laurent Guéguen
+* Added codon and general word models.
+
+23/06/09 Julien Dutheil
+* Compatibility update: now containers returns references instead of pointers.
+* TreeTemplate now uses pointers and not references.
+* Added dropTip function in TreeTemplateTools.
+
+10/06/09 -*- Version 1.8.0 -*-
+
+05/06/09 Julien Dutheil
+* Bug fixed in Newick parser!
+
+28/05/09 Julien Dutheil
+* A hell of bugs fixed!
+* Better support for the new model syntax in PhylogeneticsApplicationTools
+* Support for the Nexus tree format (single tree, read only for now).
+
+15/05/09 Julien Dutheil
+* New syntax for model specification in PhylogeneticApplicationTools.
+
+07/03/09 Julien Dutheil
+* Added pseudo counts in substitution models, when setting equilibrium
+frequencies [biopp-help-forum:139]
+* Changed SubstitutionModel interface in order to return references instead of
+  hard copy of matrices.
+* Models updated to use the new functions in MatrixTools.
+
+29/03/09 Julien Dutheil
+* MarkovModulatedSubstitutionModel inherits from AbstractParametrizable.
+* Several changes to support the new parameter aliasing function,
+	including in PhylogeneticApplicationTools.
+
+28/03/09 [biopp-devel-forum:19]
+* Now empirical substitution models can be properly loaded with non-homogeneous models.
+
+17/03/09 [biopp-devel-forum:11]
+* Bug fixed in PhylogeneticApplicationTools::optimizeParameters.
+* Also fixed error in documentation of JC models.
+
+19/02/09 [biopp-devel-forum:6]
+* Method clone in abstract[Reversible]SubstitutionModel.
+
+02/02/09 Julien Dutheil (tnx to Emmanuel Douzery!)
+* Bug fixed in TreeTools::treeToParenthesis: no more seg fault if tree is
+  empty.
+* Progress bar in computeBootstrapValues.	
+
+20/01/09 Julien Dutheil
+* Added getBootstrapValue method in Node.
+* New PropertyNotFoundException and property methods update.
+
+05/01/09 Julien Dutheil
+* Added Rivas and Eddy substitution model with gaps.
+* Small bug fixed in Markov-modulated substitution models.
+
+18/01/08 -*- Version 1.7.0 -*-
+
+11/12/08 Julien Dutheil
+* Bug fixed in BioNJ.
+
+10/12/08 Celine Scornavacca & Julien Dutheil
+* Bug fixed int Node::getName and NodeException: no more recursive call!
+
+07/12/08 Julien Dutheil
+* New getRootFrequenciesSet in SubstitutionModelSet.
+* New getStatesFrequenciesSet in MarkovModulatedFrequenciesSet.
+
+04/12/08 Julien Dutheil
+* Added a bit more options in tree length computation.
+
+17/11/08 Julien Dutheil
+* DistanceEstimation now allows to change the precision in the branch length
+  estimation (no longer fixed to 0.0001, although it is still the default
+	value).
+
+10/11/08 Julien Dutheil
+* Bug fixed in HomogeneousSequenceSimulator, ancestral root frequencies are
+  not necessarily equal now!
+
+04/11/08 Julien Dutheil
+* New Strand-Symmetric subtituion mode from Lobry 1995.
+* Numerical issue solved in GTR.
+
+20/10/08 Bastien Boussau
+* Bug fixed in PhylogeneticApplicationTools: now can run protein with covarion
+models.
+
+10/10/08 Julien Dutheil
+* Bug fixed in FrequenciesSet when testing sum for frequencies.
+
+18/01/08 -*- Version 1.6.0 -*-
+
+12/09/08 Julien Dutheil
+* Ancestral sequence reconstruction debugged and now allow sampling from the
+  posterior distribution.
+* PhylogeneticApplicationTools updated: observed frequencies are now set up
+  in the 'initial values' methods.
+
+11/09/08 Julien Dutheil
+* Large update on TreeLikelihoodData and TreeParsimonyData to rely mostly on
+  nodes id instead of Node*. Likelihood, parsimony and substitution mapping
+	methods have been updated accordingly.
+* Ancestral state reconstruction method has a new method to get a
+  SequenceContainer with all sequences.
+
+10/09/08 Sophie Abby
+* Corrected memory leak in BipartitionList (delete -> delete[]).
+
+02/09/08 Julien Dutheil
+* Added "real" +F protein substitution models, with frequencies estimation.
+
+18/01/08 -*- Version 1.5.1 -*-
+
+01/06/08 Julien Dutheil
+* Bug fixed in FrequenciesSet: the sum critierion was changed to be less
+restrictive! (now 1e-6).
+
+22/05/08 Julien Dutheil
+* Added method getLikelihoodData() in R(Non)HomogeneousTreeLikelihood.
+
+06/05/08 Bastien Boussau & Simon Carrignon
+* Bug fixed in TreeTools::getLastCommonAncestor.
+
+04/04/08 Julien Dutheil
+* Bug fixed in copy constructors: now NH models work with covarions.
+
+27/03/08 Nicolas Galtier & Julien Dutheil
+* Bug solved in NNIHomogeneousTreeLikelihood: branch lengths are now correctly
+  actualized after a NNI movement. This bug was introduced with version 1.5.
+	It mainly caused an exception to be thrown inapropriately.
+
+20/03/08 Julien Dutheil
+* Kappa parameter can no longer be 0 (avoid likelihood to be 0 in some cases)
+* Newton-Raphson algorithm fixed: deals with case when f'' is equal to zero.
+* Reading parameters from file (PhylogeneticApplicationTools) now deals with
+  parameter constraints.
+* Recopy of Abstract(Non)HomogeneousTreeLikelihood fixed.
+* New methods in SubstitutionModelSet.
+
+18/02/08 Céline Scornavacca & Julien Dutheil
+* Bug fixed in TreeTemplate::newOutGroup.
+
+21/01/08 Julien Dutheil
+* New function TreeTools::checkIds, used in likelihood classes (included in
+		version 1.5).
+* Important bug fixed in RTreeLikelihood: derivatives are correct when nodes
+  id are not reset.
+* Important bug fixed in substitution mapping.
+* Bug fixed in substitution models with frequency parameters (init from data) !
+
+18/01/08 -*- Version 1.5.0 -*-
+
+18/01/08 Julien Dutheil 
+* DistanceEstimation and SitePatterns classes are now Clonable.
+
+18/01/08 Celine Scornavacca & Julien Dutheil 
+* New function getNode(name) in TreeTemplate
+* New function searNodeWithName dans TreeTemplateTools
+* Improved multitree support in Newick
+
+13/01/08 Julien Dutheil
+* DRASRTreeLikelihoodData class improved by using the SitePatterns class.
+
+11/01/08 Julien Dutheil
+* Inclusion in new namespace bpp.
+* Bug fixed in DRNonHomogeneousTreeLikelihood.
+* Fixed recently introduced bug in DRHomogeneousTreeLikelihood.
+
+29/12/07 Julien Dutheil
+* New class DRNonHomogeneousTreeLikelihood.
+* Methods getLogLikelihood now sort terms before adding them.
+
+24/12/07 Julien Dutheil
+* Added support for invariants in rate distributions.
+
+18/12/07 Céline Scornavacca & Julien Dutheil
+* TreeTemplateTools::parenthesisToTree now sends exceptions in case of bad
+format.
+* Removed a 'unused variable' warning in NonHomogeneousSequenceSimulator.
+
+21/11/07 Julien Dutheil
+* Tree(Template)Tools do not throw exception if the root node do not have a
+  branch length.
+
+15/11/07 Julien Dutheil
+* Bug fixed in clonage of empty DR*LikelihoodData.
+
+14/11/07 Julien Dutheil
+* New methods getAncestors and getLastCommonAncestor in TreeTools.
+
+07/11/07 Julien Dutheil
+* Nucleotide substitution models re-parametrized to remove constraint on
+  equilibrium frequencies. These frequencies can now be fully optimized.
+	Root frequencies in non-stationary models also updated.
+* More bugs fixed due to the new heterogeneous models.
+* Sequence simulations improved (faster), due to the use of NodeTemplates
+  instead of maps for storing node-specific data.
+* HomogeneousSequenceSimulator moved to HomogeneousSequenceSimulator.h.
+
+10/10/07 Bastien Boussau & Julien Dutheil
+* New class NonHomogeneousTreeLikelihood, which deal with non-homogeneous
+  models of sequence evolution (fixed topology).
+* SubstitutionModels parameters are now cloned propoerly (no more Constraint issue).
+* ClockTreeLikelihood has been chaged to HomogeneousClockLikelihood, and a
+  NonHomogeneousClockTreeLikelihood was created. The ClockTreeLikelihood is
+	now a common (empty) interface for both, which a specialisation of
+	TreeLikelihood.
+* NewtonBrentMetaOptimizer becomes MetaOptimizer, is more general, and was
+  moved to NumCalc.
+
+05/10/07 Julien Dutheil
+* New PhylogeneticApplicationTools (more general) method to instanciate substitution models.
+* New method PhylogeneticsApplicationTools::getSubstitutionModelSet.
+
+28/09/07 Julien Dutheil
+* New verbose option in distance methods.
+
+21/09/07 Julien Dutheil
+* OptimizationTools::buildDistanceTree improved: iterative algorithm stops
+  when topological distance equals 0 instead of checking likelihoods.
+* PhylogeneticsApplicationTools now supports several NNI algorithms.
+* Bug fixed in SubstitutionModels! Frequencies parameters are now updated
+  correctly!
+* Analytical substitution models now save more calculations and declarations.
+* New midpoint rooting method in TreeTools.
+
+19/09/07 Bastien Boussau & Julien Dutheil
+* New NonHomogeneousSequenceSimulator class, which replaces
+  HomogeneousSequenceSimulator. An alias for backward compatibility is provided.
+* Updated class names for sequence simulations, to deal with the
+  non-homogeneous case: HomogeneousSiteSimulationResult=>RASSiteSimulationResult.
+
+17/09/07 Julien Dutheil
+* New interface ReversibleSubstitutionModel.
+* New class AbstractReversibleSubstitutionModel.
+* Bug fixed in SubstitutionModelSet (root frequencies are now properly set for
+  the homogeneous case)
+
+26/08/07 Julien Dutheil
+* Class SubstitutionMapping is now Clonable.
+	
+24/08/07 Bastien Boussau & Julien Dutheil
+* New class SubstitutionModelSet (early draft)
+
+17/01/07 Julien Dutheil
+* Bug fixed in PseudoNewtonOptimizer! (included in version 1.4.0).
+
+06/07/07 -*- Version 1.4.0 -*-
+
+27/06/07 Nicolas Galtier & Julien Dutheil
+* No more memory leak when optimizing tree topology using NNI and PhyML algorithm.
+* NNI Topology optimization method (OptimizationTools) improved and duplicated
+  (optimizeTreeTopology1 & 2).
+* Optimization with a molecular clock do not perform a Powell optimization as
+  a last step.
+
+12/05/07 Julien Dutheil
+* DistanceMatrix class is now in library seqlib.
+
+05/05/07 Julien Dutheil
+* Add support for multi-trees I/O.
+
+02/06/07 Julien Dutheil
+* Node/Branch properties are passed as references.
+* Bootstrap values computation in TreeTools.
+* New constructor in PGMA to chose between U/W PGMA.
+* New MRP super-tree function.
+
+29/05/07 Julien Dutheil
+* Optimization improved, with new options.
+
+07/05/07 Julien Dutheil
+* New method 'buildDistanceTree' in OptimizationTools, with iterative
+  estimation procedure of Ninio et al 2007.
+
+13/04/07 Julien Dutheil
+* New parametrization in ClockTreeLikelihood.
+* Optimizers improved.
+* TreeLikelihood interface a little bit modified for compatibility with NumCalc.
+
+07/04/07 Benoît Nabholz and Julien Dutheil
+* New ClockTreeLikelihood class.
+* New NNIHomogeneousTreeLikelihood class, splitted appart from DRHomogeneousTreeLikelihood.
+* DRHomogeneousTreeLikelihood a little bit improved (derivatives computation).
+* New method initialize() in TreeLikelihood classes.
+
+03/04/07 Julien Dutheil
+* VIRTUAL_COV variable changed to NO_VIRTUAL_COV. configure.ac file updated.
+  => Default behaviour is now /really/ to use covariant return type with
+	virtual inheritence, even when importing the files in an IDE. To use the old
+	compilers behaviour, one must set the NO_VIRTUAL_COV preproc variable.
+* Several useless 'VIRTUAL_COV' test removed.
+* A few more virtual inheritences removed for optimization sake. 
+* setMinimumBranchLength now reinitializes only the branch lengths parameters.
+
+02/04/07 Nicolas Galtier
+* Bug fixed in TreeTemplate assignment operator.
+
+06/03/07 Julien Dutheil
+* New Id gestion in TreeTemplate.
+  New tools to deal with ids in TreeTools and TreeTemplateTools.
+
+03/03/07 Julien Dutheil
+* Bug fixed in simulation with continuous rate (no more exception thrown for
+  duplicate site position).
+
+22/02/07 Julien Dutheil
+* Distance estimation now works properly with
+MarkovModulatedSubstitutionModel.
+
+17/02/07 Julien Dutheil
+* New (string,string) operator in DistanceMatrix.
+* New methods getState in SubstitutionModel and getRate in MarkovModulatedSubstitutionModel.
+* Simulations now work correctly with a MarkovModulatedSubstitutionModel.
+* SubstitutionModel are now clonable.
+* PhylogeneticsApplicationTools: now one may chose to not re-estimate branch
+lengths.
+
+05/02/07 Bastien Boussau & Julien Dutheil
+* Node properties are now splitted into NodeProperties and BranchProperties.
+  Bootstrap values belong to the last category, and are now properly updated
+	when rerooting a tree.
+
+28/01/07 -*- Version 1.3.1 -*-
+
+27/01/07 Julien Dutheil
+* Change getTree method in NNISearchable interface to getTopology, and
+getValue to getTopologyValue.
+  This solve a bug in DRHomogeneousTreeLikelihood and avoid confusion with
+	TreeLikelihood::getTree method, although both methods are identical.
+* No more dynamic_cast in NNITopologySearch + bug solved in methods FAST and BETTER.
+* Remove non required virtual inheritence to solve linker errors.
+
+19/01/07 -*- Version 1.3 -*-
+
+19/01/07 Julien Dutheil
+* Removed duplicated functions in HomogeneousTreeLikelihood.
+* Code update
+
+10/01/07 Julien Dutheil
+* Parsimony classes updated to match the new NNISearchable implementation.
+
+03/01/07 Julien Dutheil
+* --enable-virtual-cov option in configure script is now set by default.
+* The Tree interface inherits from Clonable.
+* TreeLikelihood and TreeParsimonyScore now implement the Clonable interface.
+* Use node ids instead of node pointers in all Data structure (likelihood and
+		parsimony).
+* NNISearchable interface rewritten, now use nodes id instead of pointers.
+  It now also inherits from Clonable and a new method getValue() was added.
+* PhyML option in NNITopologySearch now properly implemented (check if
+		multiple NNI really improve score).
+* DRHomogeneousTreeLikelihood now implements the NNISearchable interface!
+
+24/11/06 Julien Dutheil
+* HomogeneousSiteSimulator now properly inherits from SequenceSimulator interface.
+* New continuous rate simulation option in HomogeneousSiteSimulator.
+
+13/10/06 Julien Dutheil
+* TreeTools class was reorganized, augmented, more documented and splitted into TreeTools and TreeTemplateTools.
+* Tree, TreeTemplate and Node imporved (Exception support, etc.).
+* Small bugs fixed in TreeTemplate.
+
+04/10/06 Julien Dutheil
+* New function TreeTools::getHeight(Node).
+* "trees" file now includes TreeTemplate.h
+
+28/08/06 -*- Version 1.2.0 -*-
+
+28/08/06 Julien Dutheil
+* SubstitutionModel: new methods getNumberOfStates().
+* Covarion process:
+  + New MarkovModulatedSubstitutionModel abstract class,
+  + New SSRVSubstitution model implementation.
+* PhylogeneticsApplicationTools:
+  + No more exit(-1) in functions, Exception thrown instead.
+  + New method getCovarionProcess().
+* Optimization: rough optimization now applies when other parameters than branch length are found.
+* New copy constructor and assignation operator in ProbabilisticSubstitutionMapping class.
+
+01/08/06 Julien Dutheil
+* Bug fixed in GTR model: normalization constant was incorrect.
+
+12/07/06 Julien Dutheil
+* Bug fixed in DistanceEstimation constructor.
+
+06/06/06 Julien Dutheil
+* Bug fixed in F84 model. Substitution matrix is now correct!
+
+31/05/06 Julien Dutheil
+* HomogeneousTreeLikelihood classes now have a minimum for branch length, the default being 0.000001 (included).
+* Improved PseudoNewtonOptimizer, faster and no more stucked in local maximum (B. Nabohlz data test).
+
+30/05/06 Julien Dutheil
+* Improved TreeTools::nodeToParenthesis[Tree] method and Newick parser for writting.
+
+23/05/06 Julien Dutheil
+* New F84 model.
+
+04/05/06 Julien Dutheil
+* Improved TreeTools::parenthesisToNode[Tree] method and Newick parser.
+
+18/04/06 -*- Version 1.1.0 -*-
+
+18/04/06 Julien Dutheil
+* New Factory classes: SubstitutionModelFactory, IOTreeFactory, IOMatrixFactory.
+13/04/06 Vincent Ranwez
+* Bug fixed in NeighborJoining: finalStep now produces correct branch lengths.
+* New BioNJ distance method.
+13/04/06 Julien Dutheil
+* DistanceEstimation improved: copy constructor and assignment operator + resetAdditionalParameters() method.
+10/04/06 Julien Dutheil
+* TreeTemplate<N>(Tree) now properly clone branch lengths.
+06/04/06 Julien Dutheil 
+* New substitution mapping classes.
+14/03/06 Julien Dutheil
+* Simulation classes redesigned. More simulation methods added.
+09/03/06 Julien Dutheil
+* TreeLikelihood classes have now the setData() method to compute likelihood of a new dataset without changing parameters.
+Constructors now have a tree pointer as argument, and a new constructor without dataset has been added.
+02/03/06 Julien Dutheil
+* Bug fixed in TreeTools::cloneSubtree(), bad contructor call for class Node.
+16/01/06 Julien Dutheil
+* TreeTemplate(Tree) copy constructor.
+16/01/06 Julien Dutheil
+* writeId option in Newick TreeIO.
+21/12/05 Julien Dutheil
+* newOutGroup fixed in class TreeTemplate.
+Branch lengths are now properly updated. Root id is also corrected.
+New function getNextId in class tree.
+12/12/05 Julien Dutheil
+* getTotalLength, setBranchLengths, setVoidBranchLengths and scaleTree in TreeTemplate: now work when root node has no length.
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..23d0c62
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,1889 @@
+# Doxyfile 1.8.3.1-20130209
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file 
+# that follow. The default is UTF-8 which is also the encoding used for all 
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
+# iconv built into libc) for the transcoding. See 
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should 
+# identify the project. Note that if you do not use Doxywizard you need 
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME           = bpp-phyl
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 2.1.0
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description 
+# for a project that appears at the top of each page and should give viewer 
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = 
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is 
+# included in the documentation. The maximum height of the logo should not 
+# exceed 55 pixels and the maximum width should not exceed 200 pixels. 
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = 
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, 
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English 
+# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, Persian, 
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, 
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip. Note that you specify absolute paths here, but also 
+# relative paths, which will be relative from the directory where doxygen is 
+# started.
+
+STRIP_FROM_PATH        = ./src/
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = ./src/
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful if your file system 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 2
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only). 
+# A mapping has the form "name=value". For example adding 
+# "class=itcl::class" will allow you to use the command class in the 
+# itcl::class meaning.
+
+TCL_SUBST              = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Java. For instance, namespaces will be presented as packages, qualified 
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
+# sources. Doxygen will then generate output that is tailored for 
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it 
+# parses. With this tag you can assign which parser to use for a given 
+# extension. Doxygen has a built-in mapping, but you can override or extend it 
+# using this tag. The format is ext=language, where ext is a file extension, 
+# and language is one of the parsers supported by doxygen: IDL, Java, 
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, 
+# C++. For instance to make doxygen treat .inc files as Fortran files (default 
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note 
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the 
+# files are not read by doxygen.
+
+EXTENSION_MAPPING      = 
+
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all 
+# comments according to the Markdown format, which allows for more readable 
+# documentation. See http://daringfireball.net/projects/markdown/ for details. 
+# The output of markdown processing is further processed by doxygen, so you 
+# can mix doxygen, HTML, and XML commands with Markdown formatting. 
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented classes, 
+# or namespaces to their corresponding documentation. Such a link can be 
+# prevented in individual cases by by putting a % sign in front of the word or 
+# globally by setting AUTOLINK_SUPPORT to NO.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
+# to include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also makes the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to 
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate 
+# getter and setter methods for a property. Setting this option to YES (the 
+# default) will make doxygen replace the get and set methods by a property in 
+# the documentation. This will only work if the methods are indeed getting or 
+# setting a simple type. If this is not the case, or you want to show the 
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and 
+# unions are shown inside the group in which they are included (e.g. using 
+# @ingroup) instead of on a separate page (for HTML and Man pages) or 
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and 
+# unions with only public data fields or simple typedef fields will be shown 
+# inline in the documentation of the scope in which they are defined (i.e. file, 
+# namespace, or group documentation), provided this scope is documented. If set 
+# to NO (the default), structs, classes, and unions are shown on a separate 
+# page (for HTML and Man pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
+# is documented as struct, union, or enum with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code in case the coding convention dictates that all compound 
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 
+# determine which symbols to keep in memory and which to flush to disk. 
+# When the cache is full, less often used symbols will be written to disk. 
+# For small to medium size projects (<1000 input files) the default value is 
+# probably good enough. For larger projects a too small cache size can cause 
+# doxygen to be busy swapping symbols to and from disk most of the time 
+# causing a significant performance penalty. 
+# If the system has enough physical memory increasing the cache will improve the 
+# performance by keeping more symbols in memory. Note that the value works on 
+# a logarithmic scale so increasing the size by one will roughly double the 
+# memory usage. The cache size is given by this formula: 
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+SYMBOL_CACHE_SIZE      = 0
+
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be 
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given 
+# their name and scope. Since this can be an expensive process and often the 
+# same symbol appear multiple times in the code, doxygen keeps a cache of 
+# pre-resolved symbols. If the cache is too small doxygen will become slower. 
+# If the cache is too large, memory is wasted. The cache size is given by this 
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal 
+# scope will be included in the documentation.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be 
+# extracted and appear in the documentation as a namespace called 
+# 'anonymous_namespace{file}', where file will be replaced with the base 
+# name of the file that contains the anonymous namespace. By default 
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen 
+# will list include files with double quotes in the documentation 
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen 
+# will sort the (brief and detailed) documentation of class members so that 
+# constructors and destructors are listed first. If set to NO (the default) 
+# the constructors will appear in the respective orders defined by 
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. 
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO 
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
+# hierarchy of group names into alphabetical order. If set to NO (the default) 
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. 
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to 
+# do proper type resolution of all parameters of a function it will reject a 
+# match between the prototype and the implementation of a member function even 
+# if there is only one candidate or it is obvious which candidate to choose 
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen 
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if section-label ... \endif 
+# and \cond section-label ... \endcond blocks.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or macro consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and macros in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. 
+# This will remove the Files entry from the Quick Index and from the 
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
+# Namespaces page.  This will remove the Namespaces entry from the Quick Index 
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from 
+# the version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed 
+# by doxygen. The layout file controls the global structure of the generated 
+# output files in an output format independent way. To create the layout file 
+# that represents doxygen's defaults, run doxygen with the -l option. 
+# You can optionally specify a file name after the option, if omitted 
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            = 
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files 
+# containing the references data. This must be a list of .bib files. The 
+# .bib extension is automatically appended if omitted. Using this command 
+# requires the bibtex tool to be installed. See also 
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style 
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this 
+# feature you need bibtex and perl available in the search path. Do not use 
+# file names with spaces, bibtex cannot handle them.
+
+CITE_BIB_FILES         = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = src
+
+# This tag can be used to specify the character encoding of the source files 
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
+# also the default input encoding. Doxygen uses libiconv (or the iconv built 
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh 
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py 
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          = *.h \
+                         *.cpp
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag. 
+# Note that relative paths are relative to the directory from which doxygen is 
+# run.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or 
+# directories that are symbolic links (a Unix file system feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the 
+# output. The symbol name can be a fully qualified name, a word, or if the 
+# wildcard * is used, a substring. Examples: ANamespace, AClass, 
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty or if 
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file 
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) 
+# and it is also possible to disable source filtering for a specific pattern 
+# using *.ext= (so without naming a filter). This option only has effect when 
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS = 
+
+# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that 
+# is part of the input, its contents will be placed on the main page (index.html). 
+# This can be useful if you have a project on for instance GitHub and want reuse 
+# the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = 
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will 
+# link to the source code.  Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header. Note that when using a custom header you are responsible  
+# for the proper inclusion of any scripts and style sheets that doxygen 
+# needs, which is dependent on the configuration options used. 
+# It is advised to generate a default header using "doxygen -w html 
+# header.html footer.html stylesheet.css YourConfigFile" and then modify 
+# that header. Note that the header is subject to change so you typically 
+# have to redo this when upgrading to a newer version of doxygen or when 
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If left blank doxygen will 
+# generate a default style sheet. Note that it is recommended to use 
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this 
+# tag will in the future become obsolete.
+
+HTML_STYLESHEET        = 
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional 
+# user-defined cascading style sheet that is included after the standard 
+# style sheets created by doxygen. Using this option one can overrule 
+# certain style aspects. This is preferred over using HTML_STYLESHEET 
+# since it does not replace the standard style sheet and is therefor more 
+# robust against future updates. Doxygen will copy the style sheet file to 
+# the output directory.
+
+HTML_EXTRA_STYLESHEET  = 
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or 
+# other source files which should be copied to the HTML output directory. Note 
+# that these files will be copied to the base HTML output directory. Use the 
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these 
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that 
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES       = 
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. 
+# Doxygen will adjust the colors in the style sheet and background images 
+# according to this color. Hue is specified as an angle on a colorwheel, 
+# see http://en.wikipedia.org/wiki/Hue for more information. 
+# For instance the value 0 represents red, 60 is yellow, 120 is green, 
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 
+# the colors in the HTML output. For a value of 0 the output will use 
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 
+# the luminance component of the colors in the HTML output. Values below 
+# 100 gradually make the output lighter, whereas values above 100 make 
+# the output darker. The value divided by 100 is the actual gamma applied, 
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 
+# page will contain the date and time when the page was generated. Setting 
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded.
+
+HTML_DYNAMIC_SECTIONS  = YES
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of 
+# entries shown in the various tree structured indices initially; the user 
+# can expand and collapse entries dynamically later on. Doxygen will expand 
+# the tree to such a level that at most the specified number of entries are 
+# visible (unless a fully collapsed tree already exceeds this amount). 
+# So setting the number of entries 1 will produce a full collapsed tree by 
+# default. 0 is a special value representing an infinite number of entries 
+# and will result in a full expanded tree by default.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files 
+# will be generated that can be used as input for Apple's Xcode 3 
+# integrated development environment, introduced with OSX 10.5 (Leopard). 
+# To create a documentation set, doxygen will generate a Makefile in the 
+# HTML output directory. Running make will produce the docset in that 
+# directory and running "make install" will install the docset in 
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
+# it at startup. 
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html 
+# for more information.
+
+GENERATE_DOCSET        = YES
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
+# feed. A documentation feed provides an umbrella under which multiple 
+# documentation sets from a single provider (such as a company or product suite) 
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Bio++ Phylogenetic Library"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
+# should uniquely identify the documentation set bundle. This should be a 
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = bpp.phyl
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely 
+# identify the documentation publisher. This should be a reverse domain-name 
+# style string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING 
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file 
+# content.
+
+CHM_INDEX_ENCODING     = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and 
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated 
+# that can be used as input for Qt's qhelpgenerator to generate a 
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can 
+# be used to specify the file name of the resulting .qch file. 
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               = 
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to 
+# add. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   = 
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the 
+# custom filter to add. For more information please see 
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> 
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  = 
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this 
+# project's 
+# filter section matches. 
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> 
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  = 
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 
+# be used to specify the location of Qt's qhelpgenerator. 
+# If non-empty doxygen will try to run qhelpgenerator on the generated 
+# .qhp file.
+
+QHG_LOCATION           = 
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files  
+# will be generated, which together with the HTML files, form an Eclipse help 
+# plugin. To install this plugin and make it available under the help contents 
+# menu in Eclipse, the contents of the directory containing the HTML and XML 
+# files needs to be copied into the plugins directory of eclipse. The name of 
+# the directory within the plugins directory should be the same as 
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before 
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin 
+# the directory name containing the HTML and XML files should also have 
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) 
+# at top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it. Since the tabs have the same information as the 
+# navigation tree you can set this option to NO if you already set 
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 
+# structure should be generated to display hierarchical information. 
+# If the tag value is set to YES, a side panel will be generated 
+# containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). 
+# Windows users are probably better off using the HTML help feature. 
+# Since the tree basically has the same information as the tab index you 
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW      = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values 
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML 
+# documentation. Note that a value of 0 will completely suppress the enum 
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open 
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included 
+# as images in the HTML documentation. The default is 10. Note that 
+# when you change the font size after a successful doxygen run you need 
+# to manually remove any form_*.png images from the HTML output directory 
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images 
+# generated for formulas are transparent PNGs. Transparent PNGs are 
+# not supported properly for IE 6.0, but are supported on all modern browsers. 
+# Note that when changing this option you need to delete any form_*.png files 
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax 
+# (see http://www.mathjax.org) which uses client side Javascript for the 
+# rendering instead of using prerendered bitmaps. Use this if you do not 
+# have LaTeX installed or if you want to formulas look prettier in the HTML 
+# output. When enabled you may also need to install MathJax separately and 
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for 
+# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and 
+# SVG. The default value is HTML-CSS, which is slower, but has the best 
+# compatibility.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the 
+# HTML output directory using the MATHJAX_RELPATH option. The destination 
+# directory should contain the MathJax.js script. For instance, if the mathjax 
+# directory is located at the same level as the HTML output directory, then 
+# MATHJAX_RELPATH should be ../mathjax. The default value points to 
+# the MathJax Content Delivery Network so you can quickly see the result without 
+# installing MathJax.  However, it is strongly recommended to install a local 
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension 
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS     = 
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box 
+# for the HTML output. The underlying search engine uses javascript 
+# and DHTML and should work on any modern browser. Note that when using 
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets 
+# (GENERATE_DOCSET) there is already a search function so this one should 
+# typically be disabled. For large projects the javascript based search engine 
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be 
+# implemented using a web server instead of a web client using Javascript. 
+# There are two flavours of web server based search depending on the 
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for 
+# searching and an index file used by the script. When EXTERNAL_SEARCH is 
+# enabled the indexing and searching needs to be provided by external tools. 
+# See the manual for details.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP 
+# script for searching. Instead the search results are written to an XML file 
+# which needs to be processed by an external indexer. Doxygen will invoke an 
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain 
+# the search results. Doxygen ships with an example indexer (doxyindexer) and 
+# search engine (doxysearch.cgi) which are based on the open source search engine 
+# library Xapian. See the manual for configuration details.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server 
+# which will returned the search results when EXTERNAL_SEARCH is enabled. 
+# Doxygen ships with an example search engine (doxysearch) which is based on 
+# the open source search engine library Xapian. See the manual for configuration 
+# details.
+
+SEARCHENGINE_URL       = 
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed 
+# search data is written to a file for indexing by an external tool. With the 
+# SEARCHDATA_FILE tag the name of this file can be specified.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the 
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is 
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple 
+# projects and redirect the results back to the right project.
+
+EXTERNAL_SEARCH_ID     = 
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen 
+# projects other than the one defined by this configuration file, but that are 
+# all added to the same external search index. Each project needs to have a 
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id 
+# of to a relative location where the documentation can be found. 
+# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
+
+EXTRA_SEARCH_MAPPINGS  = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name. 
+# Note that when enabling USE_PDFLATEX this option is only used for 
+# generating bitmaps for formulas in the HTML output, but not in the 
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = amsmath
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for 
+# the generated latex document. The footer should contain everything after 
+# the last chapter. If it is left blank doxygen will generate a 
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER           = 
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images 
+# or other source files which should be copied to the LaTeX output directory. 
+# Note that the files will be copied as-is; there are no commands or markers 
+# available.
+
+LATEX_EXTRA_FILES      = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include 
+# source code with syntax highlighting in the LaTeX output. 
+# Note that which sources are shown also depends on other settings 
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the 
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See 
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files 
+# that can be used to generate PDF.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in 
+# front of it. If left blank docbook will be used as the default path.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition that 
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all references to function-like macros 
+# that are alone on a line, have an all uppercase name, and do not end with a 
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. For each 
+# tag file the location of the external documentation should be added. The 
+# format of a tag file without this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths 
+# or URLs. Note that each tag file must have a unique name (where the name does 
+# NOT include the path). If a tag file is not located in the directory in which 
+# doxygen is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = ../bpp-core/BppCore.tag=../../bpp-core/html \
+                         ../bpp-seq/BppSeq.tag=../../bpp-seq/html
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = BppPhyl.tag
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed 
+# in the related pages index. If set to NO, only the current project's 
+# pages will be listed.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option also works with HAVE_DOT disabled, but it is recommended to 
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see 
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
+# the mscgen tool resides. If left empty the tool is assumed to be found in the 
+# default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is 
+# allowed to run in parallel. When set to 0 (the default) doxygen will 
+# base this on the number of processors available in the system. You can set it 
+# explicitly to a value larger than 0 to get control over the balance 
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will use the Helvetica font for all dot files that 
+# doxygen generates. When you want a differently looking font you can specify 
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find 
+# the font, which can be done by putting it in a standard location or by setting 
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the 
+# directory containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the Helvetica font. 
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to 
+# set the path where dot can find it.
+
+DOT_FONTPATH           = 
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside 
+# the class node. If there are many fields or methods and many nodes the 
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS 
+# threshold limits the number of items for each type to make the size more 
+# managable. Set this to 0 for no limit. Note that the threshold may be 
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
+# doxygen will generate a call dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable call graphs 
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
+# doxygen will generate a caller dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable caller 
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include 
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are svg, png, jpg, or gif. 
+# If left blank png will be used. If you choose svg you need to set 
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files 
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to 
+# enable generation of interactive SVG images that allow zooming and panning. 
+# Note that this requires a modern browser other than Internet Explorer. 
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you 
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files 
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG        = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that 
+# contain msc files that are included in the documentation (see the 
+# \mscfile command).
+
+MSCFILE_DIRS           = 
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the 
+# number of direct children of the root node in a graph is already larger than 
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, because dot on Windows does not 
+# seem to support this out of the box. Warning: Depending on the platform used, 
+# enabling this option may lead to badly anti-aliased labels on the edges of 
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/INSTALL.txt b/INSTALL.txt
new file mode 100644
index 0000000..c8859da
--- /dev/null
+++ b/INSTALL.txt
@@ -0,0 +1,12 @@
+This software needs cmake >= 2.6 to build.
+
+After installing cmake, run it with the following command:
+cmake -DCMAKE_INSTALL_PREFIX=[where to install, for instance /usr/local or $HOME/.local] .
+
+If available, you can also use ccmake instead of cmake for a more user-friendly interface.
+
+Then compile and install the software with
+make install
+
+You may also consider installing and using the software checkinstall for easier system administration.
+
diff --git a/bpp-phyl.spec b/bpp-phyl.spec
new file mode 100644
index 0000000..ee686f8
--- /dev/null
+++ b/bpp-phyl.spec
@@ -0,0 +1,210 @@
+%define _basename bpp-phyl
+%define _version 2.1.0
+%define _release 1
+%define _prefix /usr
+
+URL: http://biopp.univ-montp2.fr/
+
+Name: %{_basename}
+Version: %{_version}
+Release: %{_release}
+License: CECILL-2.0
+Vendor: The Bio++ Project
+Source: http://biopp.univ-montp2.fr/repos/sources/%{_basename}-%{_version}.tar.gz
+Summary: Bio++ Phylogenetics library
+Group: Development/Libraries/C and C++
+Requires: bpp-core = %{_version}
+Requires: bpp-seq = %{_version}
+
+BuildRoot: %{_builddir}/%{_basename}-root
+BuildRequires: cmake >= 2.6.0
+BuildRequires: gcc-c++ >= 4.0.0
+BuildRequires: libbpp-core2 = %{_version}
+BuildRequires: libbpp-core-devel = %{_version}
+BuildRequires: libbpp-seq9 = %{_version}
+BuildRequires: libbpp-seq-devel = %{_version}
+
+AutoReq: yes
+AutoProv: yes
+
+%description
+This library contains utilitary and classes for phylogenetics and molecular evolution analysis.
+It is part of the Bio++ project.
+
+%package -n libbpp-phyl9
+Summary: Bio++ Phylogenetics library
+Group: Development/Libraries/C and C++
+
+%description -n libbpp-phyl9
+This library contains utilitary and classes for phylogenetics and molecular evolution analysis.
+It is part of the Bio++ project.
+
+
+%package -n libbpp-phyl-devel
+Summary: Libraries, includes to develop applications with %{_basename}
+Group: Development/Libraries/C and C++
+Requires: libbpp-phyl9 = %{_version}
+Requires: libbpp-seq9 = %{_version}
+Requires: libbpp-seq-devel = %{_version}
+Requires: libbpp-core2 = %{_version}
+Requires: libbpp-core-devel = %{_version}
+
+%description -n libbpp-phyl-devel
+The libbpp-phyl-devel package contains the header files and static libraries for
+building applications which use %{_basename}.
+
+%prep
+%setup -q
+
+%build
+CFLAGS="$RPM_OPT_FLAGS"
+CMAKE_FLAGS="-DCMAKE_INSTALL_PREFIX=%{_prefix} -DBUILD_TESTING=OFF"
+if [ %{_lib} == 'lib64' ] ; then
+  CMAKE_FLAGS="$CMAKE_FLAGS -DLIB_SUFFIX=64"
+fi
+cmake $CMAKE_FLAGS .
+make
+
+%install
+make DESTDIR=$RPM_BUILD_ROOT install
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post -n libbpp-phyl9 -p /sbin/ldconfig
+
+%post -n libbpp-phyl-devel
+createGeneric() {
+  echo "-- Creating generic include file: $1.all"
+  #Make sure we run into subdirectories first:
+  dirs=()
+  for file in "$1"/*
+  do
+    if [ -d "$file" ]
+    then
+      # Recursion:
+      dirs+=( "$file" )
+    fi
+  done
+  for dir in ${dirs[@]}
+  do
+    createGeneric $dir
+  done
+  #Now list all files, including newly created .all files:
+  if [ -f $1.all ]
+  then
+    rm $1.all
+  fi
+  dir=`basename $1`
+  for file in "$1"/*
+  do
+    if [ -f "$file" ] && ( [ "${file##*.}" == "h" ] || [ "${file##*.}" == "all" ] )
+    then
+      file=`basename $file`
+      echo "#include \"$dir/$file\"" >> $1.all
+    fi
+  done;
+}
+# Actualize .all files
+createGeneric %{_prefix}/include/Bpp
+exit 0
+
+%preun -n libbpp-phyl-devel
+removeGeneric() {
+  if [ -f $1.all ]
+  then
+    echo "-- Remove generic include file: $1.all"
+    rm $1.all
+  fi
+  for file in "$1"/*
+  do
+    if [ -d "$file" ]
+    then
+      # Recursion:
+      removeGeneric $file
+    fi
+  done
+}
+# Actualize .all files
+removeGeneric %{_prefix}/include/Bpp
+exit 0
+
+%postun -n libbpp-phyl9 -p /sbin/ldconfig
+
+%postun -n libbpp-phyl-devel
+createGeneric() {
+  echo "-- Creating generic include file: $1.all"
+  #Make sure we run into subdirectories first:
+  dirs=()
+  for file in "$1"/*
+  do
+    if [ -d "$file" ]
+    then
+      # Recursion:
+      dirs+=( "$file" )
+    fi
+  done
+  for dir in ${dirs[@]}
+  do
+    createGeneric $dir
+  done
+  #Now list all files, including newly created .all files:
+  if [ -f $1.all ]
+  then
+    rm $1.all
+  fi
+  dir=`basename $1`
+  for file in "$1"/*
+  do
+    if [ -f "$file" ] && ( [ "${file##*.}" == "h" ] || [ "${file##*.}" == "all" ] )
+    then
+      file=`basename $file`
+      echo "#include \"$dir/$file\"" >> $1.all
+    fi
+  done;
+}
+# Actualize .all files
+createGeneric %{_prefix}/include/Bpp
+exit 0
+
+%files -n libbpp-phyl9
+%defattr(-,root,root)
+%doc AUTHORS.txt COPYING.txt INSTALL.txt ChangeLog
+%{_prefix}/%{_lib}/lib*.so.*
+
+%files -n libbpp-phyl-devel
+%defattr(-,root,root)
+%doc AUTHORS.txt COPYING.txt INSTALL.txt ChangeLog
+%{_prefix}/%{_lib}/lib*.so
+%{_prefix}/%{_lib}/lib*.a
+%{_prefix}/include/*
+
+%changelog
+* Thu Mar 07 2013 Julien Dutheil <julien.dutheil at univ-montp2.fr> 2.1.0-1
+- New RateDistribution classes
+- New models for protein sequences (COaLA)
+- Support for gaps in parsimony score
+- Improved and extended support for BppO
+- Several bugs fixed and warnings removed
+* Thu Feb 09 2012 Julien Dutheil <julien.dutheil at univ-montp2.fr> 2.0.3-1
+- Reorganized model hierarchy
+- New pairwise models
+- Several bugs fixed
+* Thu Jun 09 2011 Julien Dutheil <julien.dutheil at univ-montp2.fr> 2.0.2-1
+- New substitution models, new substitution mapping tools.
+* Mon Feb 28 2011 Julien Dutheil <julien.dutheil at univ-montp2.fr> 2.0.1-1
+* Mon Feb 07 2011 Julien Dutheil <julien.dutheil at univ-montp2.fr> 2.0.0-1
+* Thu Mar 25 2010 Julien Dutheil <julien.dutheil at univ-montp2.fr> 1.9.0-1
+* Wed Jun 10 2009 Julien Dutheil <jdutheil at birc.au.dk> 1.8.0-1
+* Thu Dec 11 2008 Julien Dutheil <jdutheil at birc.au.dk> 1.7.0-1
+* Wed Sep 24 2008 Julien Dutheil <jdutheil at birc.au.dk> 1.6.0-1
+* Mon Jul 21 2008 Julien Dutheil <jdutheil at birc.au.dk> 1.5.1-1
+* Fri Jan 18 2008 Julien Dutheil <Julien.Dutheil at univ-montp2.fr> 1.5.0-1
+* Sat Jul 06 2007 Julien Dutheil <Julien.Dutheil at univ-montp2.fr> 1.4.0-1
+* Sat Jan 27 2007 Julien Dutheil <Julien.Dutheil at univ-montp2.fr> 1.3.1-1
+* Fri Jan 19 2007 Julien Dutheil <Julien.Dutheil at univ-montp2.fr> 1.3.0-1
+* Mon Aug 28 2006 Julien Dutheil <Julien.Dutheil at univ-montp2.fr> 1.2.0-1
+* Tue Apr 18 2006 Julien Dutheil <Julien.Dutheil at univ-montp2.fr> 1.1.0-1
+* Fri Nov 16 2005 Julien Dutheil <Julien.Dutheil at univ-montp2.fr> 1.0.0-1
+- First draft of the spec file
+
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..7855473
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,78 @@
+libbpp-phyl (2.1.0-1) unstable; urgency=low
+
+  * New RateDistribution classes
+  * New models for protein sequences (COaLA)
+  * Support for gaps in parsimony score
+  * Improved and extended support for BppO
+  * Several bugs fixed and warnings removed
+
+ -- Julien Dutheil <julien.dutheil at univ-montp2.fr>  Thu, 07 Mar 2013 15:58:00 +0100
+
+libbpp-phyl (2.0.3-1) unstable; urgency=low
+
+  * Reorganized model hierarchy
+  * New pairwise models
+  * Several bugs fixed
+
+ -- Julien Dutheil <julien.dutheil at univ-montp2.fr>  Thu, 09 Feb 2013 16:00:00 +0100
+
+libbpp-phyl (2.0.2-1) unstable; urgency=low
+
+  * RFP: Bio++ -- The Bio++ bioinformatics libraries. (Closes: #616373).
+  * Packages are now non-native.
+  * Exact substitution mapping with detailled counts.
+  * Backup system for ML estimation.
+
+ -- Julien Dutheil <julien.dutheil at univ-montp2.fr>  Thu, 09 Jun 2011 11:00:00 +0100
+
+libbpp-phyl (2.0.1) unstable; urgency=low
+
+  * Fixed bug #27
+  * Improved tree drawing algorithms.
+
+ -- Julien Dutheil <julien.dutheil at univ-montp2.fr>  Mon, 28 Feb 2011 09:00:00 +0100
+
+libbpp-phyl (2.0.0) unstable; urgency=low
+
+  * Better mixed models
+  * Extended substitution mapping framework
+  * More bug fixed, notably in simulation procedures
+  * Topology comparison tools (ELW)
+  * Improved graphic classes
+
+ -- Julien Dutheil <julien.dutheil at univ-montp2.fr>  Mon, 07 Feb 2011 09:00:00 +0100
+
+libbpp-phyl (1.9.0) unstable; urgency=low
+
+  * Several bugs fixed and improvements, compilation with -Weffc++
+  * Codon models
+  * Improved non-homogeneous classes
+  * Improved tree drawing classes
+
+ -- Julien Dutheil <julien.dutheil at univ-montp2.fr>  Thu, 25 Mar 2010 13:47:24 +0100
+
+libbpp-phyl (1.8.0) unstable; urgency=low
+
+  * Several buf fixed and improvements.
+  * New support for Nexus tree files.
+  * New syntax for model description using keyvals.
+
+ -- Julien Dutheil <jdutheil at birc.au.dk>  Wed, 10 Jun 2009 11:28:58 +0100
+
+libbpp-phyl (1.7.0) unstable; urgency=low
+
+  * Several bug fixed and improvements...
+
+ -- Julien Dutheil <jdutheil at birc.au.dk>  Thu, 11 Dec 2008 12:21:37 +0100
+
+libbpp-phyl (1.6.0) unstable; urgency=low
+
+  * New +F protein models + bugs fixed.
+
+ -- Julien Dutheil <jdutheil at birc.au.dk>  Wed, 24 Sep 2008 14:07:26 +0200
+
+libbpp-phyl (1.5.1) unstable; urgency=low
+
+  * Initial Release.
+
+ -- Julien Dutheil <jdutheil at birc.au.dk>  Mon, 21 Jul 2008 15:17:26 +0200
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..5f74897
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,25 @@
+Source: libbpp-phyl
+Section: libs
+Priority: optional
+Maintainer: Loic Dachary <loic at dachary.org>
+Uploaders: Julien Dutheil <julien.dutheil at univ-montp2.fr>
+Build-Depends: debhelper (>= 5), cmake (>= 2.6),
+  libbpp-seq-dev (>= 2.1.0)
+Standards-Version: 3.9.1
+
+Package: libbpp-phyl-dev
+Section: libdevel
+Architecture: any
+Depends: libbpp-phyl9 (= ${binary:Version}), ${misc:Depends},
+  libbpp-seq-dev (>= 2.1.0)
+Description: Bio++ Phylogenetic library development files.
+ Contains the Bio++ classes for phylogenetics.
+
+Package: libbpp-phyl9
+Section: libs
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends},
+  libbpp-seq9 (>= 2.1.0)
+Description: Bio++ Phylogenetic library.
+ Contains the Bio++ classes for phylogenetics.
+
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..142fcfb
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,66 @@
+This package was debianized by Julien Dutheil <julien.dutheil at univ-montp2.fr> on
+Thu, 07 Mar 2013 15:58:00 +0100
+
+It was downloaded from <http://biopp.univ-montp2.fr/Repositories/sources>
+
+Upstream Author: 
+
+    Julien Dutheil <julien.dutheil at univ-montp2.fr>
+
+Copyright: 
+
+    Copyright (C) 2013 Bio++ Development Team
+
+License:
+
+    This package is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+ 
+    This package is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+ 
+    You should have received a copy of the GNU General Public License
+    along with this package; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL'.
+
+The Debian packaging is (C) 2013, Julien Dutheil <julien.dutheil at univ-montp2.fr> and
+is licensed under the GPL, see above.
+
+The provided software is distributed under the CeCILL license:
+
+    This software is governed by the CeCILL license under French law and
+    abiding by the rules of distribution of free software.  You can  use, 
+    modify and/ or redistribute the software under the terms of the CeCILL
+    license as circulated by CEA, CNRS and INRIA at the following URL
+    "http://www.cecill.info". 
+
+    As a counterpart to the access to the source code and  rights to copy,
+    modify and redistribute granted by the license, users are provided only
+    with a limited warranty  and the software's author,  the holder of the
+    economic rights,  and the successive licensors  have only  limited
+    liability. 
+
+    In this respect, the user's attention is drawn to the risks associated
+    with loading,  using,  modifying and/or developing or reproducing the
+    software by the user in light of its specific status of free software,
+    that may mean  that it is complicated to manipulate,  and  that  also
+    therefore means  that it is reserved for developers  and  experienced
+    professionals having in-depth computer knowledge. Users are therefore
+    encouraged to load and test the software's suitability as regards their
+    requirements in conditions enabling the security of their systems and/or 
+    data to be ensured and,  more generally, to use and operate it in the 
+    same conditions as regards security. 
+
+    The fact that you are presently reading this means that you have had
+    knowledge of the CeCILL license and that you accept its terms.
+    
+The complete text of the license may be found here:
+http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
+
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 0000000..e69de29
diff --git a/debian/libbpp-phyl-dev.install b/debian/libbpp-phyl-dev.install
new file mode 100644
index 0000000..7d74f2b
--- /dev/null
+++ b/debian/libbpp-phyl-dev.install
@@ -0,0 +1,3 @@
+debian/tmp/usr/include/*
+debian/tmp/usr/lib/lib*.a
+debian/tmp/usr/lib/lib*.so
diff --git a/debian/libbpp-phyl9.install b/debian/libbpp-phyl9.install
new file mode 100644
index 0000000..c45ebcf
--- /dev/null
+++ b/debian/libbpp-phyl9.install
@@ -0,0 +1 @@
+debian/tmp/usr/lib/lib*.so.*
diff --git a/debian/postinst b/debian/postinst
new file mode 100755
index 0000000..cf9e925
--- /dev/null
+++ b/debian/postinst
@@ -0,0 +1,43 @@
+#! /bin/bash
+
+# Abort if any command returns an error value
+set -e
+
+createGeneric() {
+  echo "-- Creating generic include file: $1.all"
+  #Make sure we run into subdirectories first:
+  dirs=()
+  for file in "$1"/*
+  do
+    if [ -d "$file" ]
+    then
+      # Recursion:
+      dirs+=( "$file" )
+    fi
+  done
+  for dir in ${dirs[@]}
+  do
+    createGeneric $dir
+  done
+  #Now list all files, including newly created .all files:
+  if [ -f $1.all ]
+  then
+    rm $1.all
+  fi
+  dir=`basename $1`
+  for file in "$1"/*
+  do
+    if [ -f "$file" ] && ( [ "${file##*.}" == "h" ] || [ "${file##*.}" == "all" ] )
+    then
+      file=`basename $file`
+      echo "#include \"$dir/$file\"" >> $1.all
+    fi
+  done;
+}
+
+if [ "$1" = "configure" ]; then
+  # Actualize .all files
+  createGeneric /usr/include/Bpp
+fi
+
+exit 0
diff --git a/debian/postrm b/debian/postrm
new file mode 100755
index 0000000..3931669
--- /dev/null
+++ b/debian/postrm
@@ -0,0 +1,45 @@
+#! /bin/bash
+
+# Abort if any command returns an error value
+set -e
+
+createGeneric() {
+  echo "-- Creating generic include file: $1.all"
+  #Make sure we run into subdirectories first:
+  dirs=()
+  for file in "$1"/*
+  do
+    if [ -d "$file" ]
+    then
+      # Recursion:
+      dirs+=( "$file" )
+    fi
+  done
+  for dir in ${dirs[@]}
+  do
+    createGeneric $dir
+  done
+  #Now list all files, including newly created .all files:
+  if [ -f $1.all ]
+  then
+    rm $1.all
+  fi
+  dir=`basename $1`
+  for file in "$1"/*
+  do
+    if [ -f "$file" ] && ( [ "${file##*.}" == "h" ] || [ "${file##*.}" == "all" ] )
+    then
+      file=`basename $file`
+      echo "#include \"$dir/$file\"" >> $1.all
+    fi
+  done;
+}
+
+if [ "$1" = "remove" ]; then
+  # Automatically added by dh_makeshlibs
+  ldconfig
+  # Actualize .all files
+  createGeneric /usr/include/Bpp
+fi
+
+exit 0
diff --git a/debian/prerm b/debian/prerm
new file mode 100755
index 0000000..5aefd24
--- /dev/null
+++ b/debian/prerm
@@ -0,0 +1,27 @@
+#! /bin/bash
+
+# Abort if any command returns an error value
+set -e
+
+removeGeneric() {
+  if [ -f $1.all ]
+  then
+    echo "-- Remove generic include file: $1.all"
+    rm $1.all
+  fi
+  for file in "$1"/*
+  do
+    if [ -d "$file" ]
+    then
+      # Recursion:
+      removeGeneric $file
+    fi
+  done
+}
+
+if [ "$1" = "remove" ]; then
+  # Actualize .all files
+  removeGeneric /usr/include/Bpp
+fi
+
+exit 0
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..92c389e
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,120 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# 24/01/10 Modification for use with CMake by Julien Dutheil.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+
+# These are used for cross-compiling and for saving the configure script
+# from having to guess our platform (since we know it already)
+DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+
+
+CFLAGS = -Wall -g
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+	CFLAGS += -O0
+else
+	CFLAGS += -O2
+endif
+
+# shared library versions
+version=`ls src/lib*.so.* | \
+ awk '{if (match($$0,/[0-9]+\.[0-9]+\.[0-9]+$$/)) print substr($$0,RSTART)}'`
+major=`ls src/lib*.so.* | \
+ awk '{if (match($$0,/\.so\.[0-9]+$$/)) print substr($$0,RSTART+4)}'`
+
+configure:
+	cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=OFF .
+
+config.status: configure
+	dh_testdir
+
+build: build-stamp
+build-stamp:  config.status
+	dh_testdir
+
+	# Add here commands to compile the package.
+	$(MAKE)
+
+	touch $@
+
+clean:
+	dh_testdir
+	dh_testroot
+
+	# Add here commands to clean up after the build process.
+	[ ! -f Makefile ] || $(MAKE) clean;
+	[ ! -f Makefile ] || rm Makefile;
+	[ ! -f src/Makefile ] || rm src/Makefile;
+	[ ! -f test/Makefile ] || rm test/Makefile;
+	rm -f config.sub config.guess
+	rm -f build-stamp
+	rm -f CMakeCache.txt
+	rm -f *.cmake
+	rm -f src/*.cmake
+	rm -f test/*.cmake
+	rm -rf CMakeFiles
+	rm -rf src/CMakeFiles
+	rm -rf test/CMakeFiles
+	rm -rf _CPack_Packages
+	rm -rf Testing
+	rm -f DartConfiguration.tcl
+
+	dh_clean 
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_prep 
+	dh_installdirs
+
+	# Add here commands to install the package into debian/tmp
+	$(MAKE) DESTDIR=$(CURDIR)/debian/tmp install
+
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+	dh_testdir
+	dh_testroot
+	dh_installchangelogs ChangeLog
+	dh_installdocs
+	dh_installexamples
+	dh_install
+#	dh_installmenu
+#	dh_installdebconf	
+#	dh_installlogrotate
+#	dh_installemacsen
+#	dh_installpam
+#	dh_installmime
+#	dh_installinit
+#	dh_installcron
+#	dh_installinfo
+	dh_installman
+	dh_link
+	dh_strip
+	dh_compress
+	dh_fixperms
+#	dh_perl
+#	dh_python
+	dh_makeshlibs
+	dh_installdeb
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install 
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/src/Bpp/Phyl/AncestralStateReconstruction.h b/src/Bpp/Phyl/AncestralStateReconstruction.h
new file mode 100644
index 0000000..cd33f5b
--- /dev/null
+++ b/src/Bpp/Phyl/AncestralStateReconstruction.h
@@ -0,0 +1,110 @@
+//
+// File: AncestralStateReconstruction.h
+// Created by: Julien Dutheil
+// Created on: Fri Jul 08 13:32 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _ANCESTRALSTATESRECONSTRUCTION_H_
+#define _ANCESTRALSTATESRECONSTRUCTION_H_
+
+// From SeqLib:
+#include <Bpp/Seq/Sequence.h>
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+// From the STL:
+#include <vector>
+#include <map>
+
+namespace bpp
+{
+
+class Node;
+
+/**
+ * @brief Interface for ancestral states reconstruction methods.
+ */
+class AncestralStateReconstruction
+{
+  public:
+    AncestralStateReconstruction() {}
+    virtual ~AncestralStateReconstruction() {}
+
+  public:
+    /**
+     * @brief Get ancestral states for a given node as a vector of int.
+     *
+     * The size of the vector depends on the implementation.
+     * This method is mainly for efficient internal use in other classes.
+     * Consider using the getAncestralSequenceForNode() method for a more
+     * general output.
+     *
+     * @param nodeId the id of the node at which the states must be reconstructed.
+     * @return A vector of states indices.
+     * @see getAncestralSequenceForNode
+     */ 
+    virtual std::vector<size_t> getAncestralStatesForNode(int nodeId) const = 0;
+
+    /**
+     * @brief Get all ancestral states for all nodes.
+     *
+     * Call the getAncestralSequenceForNode() method on each node in the tree.
+     *
+     * @return A map with nodes id as key, and a vector of states indices as value.
+     * @see getAncestralSequenceForNode
+     */
+    virtual std::map<int, std::vector<size_t> > getAllAncestralStates() const = 0;
+
+    /**
+     * @brief Get the ancestral sequence for a given node.
+     *
+     * @param nodeId The id of the node at which the sequence must be reconstructed.
+     * @return A sequence object.
+     */ 
+    virtual Sequence* getAncestralSequenceForNode(int nodeId) const = 0;
+
+    /**
+     * @brief Get all the ancestral sequences for all nodes.
+     *
+     * @return A new SiteContainer object.
+     */ 
+    virtual SiteContainer* getAncestralSequences() const = 0;
+    
+};
+
+} //end of namespace bpp.
+
+#endif // _ANCESTRALSTATESRECONSTRUCTION_H_
+
diff --git a/src/Bpp/Phyl/App/PhylogeneticsApplicationTools.cpp b/src/Bpp/Phyl/App/PhylogeneticsApplicationTools.cpp
new file mode 100644
index 0000000..dbf3de9
--- /dev/null
+++ b/src/Bpp/Phyl/App/PhylogeneticsApplicationTools.cpp
@@ -0,0 +1,1489 @@
+//
+// File: PhylogeneticsApplicationTools.cpp
+// Created by: Julien Dutheil
+// Created on: Fri Oct 21 16:49 2005
+// from old file ApplicationTools.cpp created on Sun Dec 14 09:36:26 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "PhylogeneticsApplicationTools.h"
+#include "../Model/SubstitutionModel.h"
+#include "../Model/Protein/Coala.h"
+#include "../Model/FrequenciesSet/MvaFrequenciesSet.h"
+#include "../Likelihood/TreeLikelihood.h"
+#include "../Mapping/LaplaceSubstitutionCount.h"
+#include "../Mapping/UniformizationSubstitutionCount.h"
+#include "../Mapping/DecompositionSubstitutionCount.h"
+#include "../Mapping/NaiveSubstitutionCount.h"
+#include "../Mapping/OneJumpSubstitutionCount.h"
+#include "../OptimizationTools.h"
+#include "../Tree.h"
+#include "../Io/Newick.h"
+#include "../Io/NexusIoTree.h"
+#include "../Io/Nhx.h"
+#include "../Io/BppOSubstitutionModelFormat.h"
+#include "../Io/BppOFrequenciesSetFormat.h"
+#include "../Io/BppORateDistributionFormat.h"
+
+// From bpp-core
+#include <Bpp/Io/BppODiscreteDistributionFormat.h>
+#include <Bpp/Io/BppOParametrizableFormat.h>
+#include <Bpp/Io/FileTools.h>
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Text/StringTokenizer.h>
+#include <Bpp/Text/KeyvalTools.h>
+#include <Bpp/Numeric/AutoParameter.h>
+#include <Bpp/Numeric/Prob/DirichletDiscreteDistribution.h>
+#include <Bpp/Numeric/Function/DownhillSimplexMethod.h>
+#include <Bpp/Numeric/Function/PowellMultiDimensions.h>
+
+// From bpp-seq:
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+#include <Bpp/Seq/App/SequenceApplicationTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <fstream>
+#include <memory>
+#include <set>
+#include <vector>
+
+using namespace std;
+
+
+/*************************************************************/
+/*****************  TREES ************************************/
+/*************************************************************/
+
+
+/******************************************************************************/
+
+Tree* PhylogeneticsApplicationTools::getTree(
+  map<string, string>& params,
+  const string& prefix,
+  const string& suffix,
+  bool suffixIsOptional,
+  bool verbose) throw (Exception)
+{
+  string format = ApplicationTools::getStringParameter(prefix + "tree.format", params, "Newick", suffix, suffixIsOptional, true);
+  string treeFilePath = ApplicationTools::getAFilePath(prefix + "tree.file", params, true, true, suffix, suffixIsOptional);
+
+  ITree* treeReader;
+  if (format == "Newick")
+    treeReader = new Newick(true);
+  else if (format == "Nexus")
+    treeReader = new NexusIOTree();
+  else if (format == "NHX")
+    treeReader = new Nhx();
+  else
+    throw Exception("Unknow format for tree reading: " + format);
+  Tree* tree = treeReader->read(treeFilePath);
+  delete treeReader;
+
+  if (verbose)
+    ApplicationTools::displayResult("Tree file", treeFilePath);
+  return tree;
+}
+
+/******************************************************************************/
+
+vector<Tree*> PhylogeneticsApplicationTools::getTrees(
+  map<string, string>& params,
+  const string& prefix,
+  const string& suffix,
+  bool suffixIsOptional,
+  bool verbose) throw (Exception)
+{
+  string format = ApplicationTools::getStringParameter(prefix + "trees.format", params, "Newick", suffix, suffixIsOptional, true);
+  string treeFilePath = ApplicationTools::getAFilePath(prefix + "trees.file", params, true, true, suffix, suffixIsOptional);
+
+  IMultiTree* treeReader;
+  if (format == "Newick")
+    treeReader = new Newick(true);
+  else if (format == "Nexus")
+    treeReader = new NexusIOTree();
+  else if (format == "NHX")
+    treeReader = new Nhx();
+  else
+    throw Exception("Unknow format for tree reading: " + format);
+  vector<Tree*> trees;
+  treeReader->read(treeFilePath, trees);
+  delete treeReader;
+
+  if (verbose)
+  {
+    ApplicationTools::displayResult("Tree file", treeFilePath);
+    ApplicationTools::displayResult("Number of trees in file", trees.size());
+  }
+  return trees;
+}
+
+
+/*************************************************************/
+/******* MODELS **********************************************/
+/*************************************************************/
+
+/******************************************************************************/
+
+SubstitutionModel* PhylogeneticsApplicationTools::getSubstitutionModel(
+  const Alphabet* alphabet,
+  const SiteContainer* data,
+  std::map<std::string, std::string>& params,
+  const string& suffix,
+  bool suffixIsOptional,
+  bool verbose) throw (Exception)
+{
+  string modelDescription;
+  if (AlphabetTools::isCodonAlphabet(alphabet))
+    modelDescription = ApplicationTools::getStringParameter("model", params, "CodonRate(model=JC69)", suffix, suffixIsOptional, verbose);
+  else if (AlphabetTools::isWordAlphabet(alphabet))
+    modelDescription = ApplicationTools::getStringParameter("model", params, "Word(model=JC69)", suffix, suffixIsOptional, verbose);
+  else
+    modelDescription = ApplicationTools::getStringParameter("model", params, "JC69", suffix, suffixIsOptional, verbose);
+
+  map<string, string> unparsedParameterValues;
+
+  BppOSubstitutionModelFormat bIO(BppOSubstitutionModelFormat::ALL, true, true, true, verbose);
+  SubstitutionModel* model = bIO.read(alphabet, modelDescription, data, true);
+
+  return model;
+}
+
+/******************************************************************************/
+
+void PhylogeneticsApplicationTools::setSubstitutionModelParametersInitialValuesWithAliases(
+  SubstitutionModel& model,
+  std::map<std::string, std::string>& unparsedParameterValues,
+  const std::string& modelPrefix,
+  const SiteContainer* data,
+  std::map<std::string, double>& existingParams,
+  std::vector<std::string>& specificParams,
+  std::vector<std::string>& sharedParams,
+  bool verbose) throw (Exception)
+{
+  string initFreqs = ApplicationTools::getStringParameter(model.getNamespace() + "initFreqs", unparsedParameterValues, "", "", true, false);
+
+  if (verbose)
+    ApplicationTools::displayResult("Frequencies Initialization for model", (initFreqs == "") ? "None" : initFreqs);
+
+  if (initFreqs != "")
+  {
+    if (initFreqs == "observed")
+    {
+      if (!data)
+        throw Exception("Missing data for observed frequencies");
+      unsigned int psi = ApplicationTools::getParameter<unsigned int>(model.getNamespace() + "initFreqs.observedPseudoCount", unparsedParameterValues, 0);
+      model.setFreqFromData(*data, psi);
+    }
+    else if (initFreqs.substr(0, 6) == "values")
+    {
+      // Initialization using the "values" argument
+      map<int, double> frequencies;
+
+      string rf = initFreqs.substr(6);
+      StringTokenizer strtok(rf.substr(1, rf.length() - 2), ",");
+      int i = 0;
+      while (strtok.hasMoreToken())
+        frequencies[i++] = TextTools::toDouble(strtok.nextToken());
+      model.setFreq(frequencies);
+    }
+    else
+      throw Exception("Unknown initFreqs argument");
+  }
+
+  ParameterList pl = model.getIndependentParameters();
+  for (size_t i = 0; i < pl.size(); ++i)
+  {
+    AutoParameter ap(pl[i]);
+    ap.setMessageHandler(ApplicationTools::warning);
+    pl.setParameter(i, ap);
+  }
+
+  for (size_t i = 0; i < pl.size(); ++i)
+  {
+    const string pName = pl[i].getName();
+    size_t posp = model.getParameterNameWithoutNamespace(pName).rfind(".");
+    string value;
+    bool test1 = (initFreqs == "");
+    bool test2 = (model.getParameterNameWithoutNamespace(pName).substr(posp + 1, 5) != "theta");
+    bool test3 = (unparsedParameterValues.find(pName) != unparsedParameterValues.end());
+    if (test1 || test2 || test3)
+    {
+      if (!test1 && !test2 && test3)
+        ApplicationTools::displayWarning("Warning, initFreqs argument is set and a value is set for parameter " + pName);
+      value = ApplicationTools::getStringParameter(pName, unparsedParameterValues, TextTools::toString(pl[i].getValue()));
+      if (value.size() > 5 && value.substr(0, 5) == "model")
+      {
+        if (existingParams.find(value) != existingParams.end())
+        {
+          pl[i].setValue(existingParams[value]);
+          sharedParams.push_back(value);
+        }
+        else
+          throw Exception("Error, unknown parameter " + value);
+      }
+      else
+      {
+        double value2 = TextTools::toDouble(value);
+        existingParams[modelPrefix + pName] = value2;
+        specificParams.push_back(pName);
+        pl[i].setValue(value2);
+      }
+    }
+    else
+    {
+      existingParams[modelPrefix + pName] = pl[i].getValue();
+      specificParams.push_back(pName);
+    }
+    if (verbose)
+      ApplicationTools::displayResult("Parameter found", modelPrefix + pName + "=" + TextTools::toString(pl[i].getValue()));
+  }
+  model.matchParametersValues(pl);
+}
+
+
+/******************************************************/
+/**** FREQUENCIES SET *********************************/
+/******************************************************/
+
+/******************************************************************************/
+
+FrequenciesSet* PhylogeneticsApplicationTools::getRootFrequenciesSet(
+  const Alphabet* alphabet,
+  const SiteContainer* data,
+  std::map<std::string, std::string>& params,
+  const std::vector<double>& rateFreqs,
+  const std::string& suffix,
+  bool suffixIsOptional,
+  bool verbose) throw (Exception)
+{
+  string freqDescription = ApplicationTools::getStringParameter("nonhomogeneous.root_freq", params, "Full(init=observed)", suffix, suffixIsOptional);
+  if (freqDescription == "None")
+  {
+    return 0;
+  }
+  else
+  {
+    FrequenciesSet* freq = getFrequenciesSet(alphabet, freqDescription, data, rateFreqs, verbose);
+    if (verbose)
+      ApplicationTools::displayResult("Root frequencies ", freq->getName());
+    return freq;
+  }
+}
+
+/******************************************************************************/
+
+FrequenciesSet* PhylogeneticsApplicationTools::getFrequenciesSet(
+  const Alphabet* alphabet,
+  const std::string& freqDescription,
+  const SiteContainer* data,
+  const std::vector<double>& rateFreqs,
+  bool verbose) throw (Exception)
+{
+  map<string, string> unparsedParameterValues;
+  BppOFrequenciesSetFormat bIO(BppOFrequenciesSetFormat::ALL, verbose);
+  auto_ptr<FrequenciesSet> pFS(bIO.read(alphabet, freqDescription, data, true));
+
+  // /////// To be changed for input normalization
+  if (rateFreqs.size() > 0)
+  {
+    pFS.reset(new MarkovModulatedFrequenciesSet(pFS.release(), rateFreqs));
+  }
+
+  return pFS.release();
+}
+
+/******************************************************/
+/**** SUBSTITUTION MODEL SET **************************/
+/******************************************************/
+
+/******************************************************************************/
+
+SubstitutionModelSet* PhylogeneticsApplicationTools::getSubstitutionModelSet(
+  const Alphabet* alphabet,
+  const SiteContainer* data,
+  std::map<std::string, std::string>& params,
+  const std::string& suffix,
+  bool suffixIsOptional,
+  bool verbose)
+{
+  if (!ApplicationTools::parameterExists("nonhomogeneous.number_of_models", params))
+    throw Exception("You must specify this parameter: nonhomogeneous.number_of_models .");
+  size_t nbModels = ApplicationTools::getParameter<size_t>("nonhomogeneous.number_of_models", params, 1, suffix, suffixIsOptional, false);
+  if (nbModels == 0)
+    throw Exception("The number of models can't be 0 !");
+
+  bool nomix = true;
+  for (size_t i = 0; nomix &(i < nbModels); i++)
+  {
+    string prefix = "model" + TextTools::toString(i + 1);
+    string modelDesc;
+    modelDesc = ApplicationTools::getStringParameter(prefix, params, "", suffix, suffixIsOptional, verbose);
+
+    if (modelDesc.find("Mixed") != string::npos)
+      nomix = false;
+  }
+
+  SubstitutionModelSet* modelSet, * modelSet1 = 0;
+  modelSet1 = new SubstitutionModelSet(alphabet);
+  setSubstitutionModelSet(*modelSet1, alphabet, data, params, suffix, suffixIsOptional, verbose);
+
+  if (modelSet1->hasMixedSubstitutionModel())
+  {
+    modelSet = new MixedSubstitutionModelSet(*modelSet1);
+    completeMixedSubstitutionModelSet(*dynamic_cast<MixedSubstitutionModelSet*>(modelSet), alphabet, data, params, suffix, suffixIsOptional, verbose);
+  }
+  else
+    modelSet = modelSet1;
+
+  return modelSet;
+}
+
+/******************************************************************************/
+
+void PhylogeneticsApplicationTools::setSubstitutionModelSet(
+  SubstitutionModelSet& modelSet,
+  const Alphabet* alphabet,
+  const SiteContainer* data,
+  map<string, string>& params,
+  const string& suffix,
+  bool suffixIsOptional,
+  bool verbose)
+{
+  modelSet.clear();
+  if (!ApplicationTools::parameterExists("nonhomogeneous.number_of_models", params))
+    throw Exception("You must specify this parameter: nonhomogeneous.number_of_models .");
+  size_t nbModels = ApplicationTools::getParameter<size_t>("nonhomogeneous.number_of_models", params, 1, suffix, suffixIsOptional, false);
+  if (nbModels == 0)
+    throw Exception("The number of models can't be 0 !");
+
+  if (verbose)
+    ApplicationTools::displayResult("Number of distinct models", TextTools::toString(nbModels));
+
+  BppOSubstitutionModelFormat bIO(BppOSubstitutionModelFormat::ALL, true, true, true, verbose);
+
+  // ///////////////////////////////////////////
+  // Build a new model set object:
+
+  vector<double> rateFreqs;
+  string tmpDesc;
+  if (AlphabetTools::isCodonAlphabet(alphabet))
+    tmpDesc = ApplicationTools::getStringParameter("model1", params, "CodonRate(model=JC69)", suffix, suffixIsOptional, false);
+  else if (AlphabetTools::isWordAlphabet(alphabet))
+    tmpDesc = ApplicationTools::getStringParameter("model1", params, "Word(model=JC69)", suffix, suffixIsOptional, false);
+  else
+    tmpDesc = ApplicationTools::getStringParameter("model1", params, "JC69", suffix, suffixIsOptional, false);
+
+  auto_ptr<SubstitutionModel> tmp(bIO.read(alphabet, tmpDesc, data, false));
+  map<string, string> tmpUnparsedParameterValues(bIO.getUnparsedArguments());
+
+  if (tmp->getNumberOfStates() != alphabet->getSize())
+  {
+    // Markov-Modulated Markov Model...
+    size_t n = static_cast<size_t>(tmp->getNumberOfStates() / alphabet->getSize());
+    rateFreqs = vector<double>(n, 1. / static_cast<double>(n)); // Equal rates assumed for now, may be changed later (actually, in the most general case,
+  }
+
+  // ////////////////////////////////////
+  // Deal with root frequencies
+
+  bool stationarity = ApplicationTools::getBooleanParameter("nonhomogeneous.stationarity", params, false, "", false, false);
+  FrequenciesSet* rootFrequencies = 0;
+  if (!stationarity)
+  {
+    rootFrequencies = getRootFrequenciesSet(alphabet, data, params, rateFreqs, suffix, suffixIsOptional, verbose);
+    stationarity = !rootFrequencies;
+    string freqDescription = ApplicationTools::getStringParameter("nonhomogeneous.root_freq", params, "", suffix, suffixIsOptional);
+    if (freqDescription.substr(0, 10) == "MVAprotein")
+    {
+      if (dynamic_cast<Coala*>(tmp.get()))
+        dynamic_cast<MvaFrequenciesSet*>(rootFrequencies)->initSet(dynamic_cast<CoalaCore*>(tmp.get()));
+      else
+        throw Exception("The MVAprotein frequencies set at the root can only be used if a COaLA model is used on branches.");
+    }
+  }
+  ApplicationTools::displayBooleanResult("Stationarity assumed", stationarity);
+
+  if (!stationarity)
+    modelSet.setRootFrequencies(rootFrequencies);
+
+  // //////////////////////////////////////
+  // Now parse all models:
+
+  map<string, double> existingParameters;
+
+  for (size_t i = 0; i < nbModels; i++)
+  {
+    string prefix = "model" + TextTools::toString(i + 1);
+    string modelDesc;
+    if (AlphabetTools::isCodonAlphabet(alphabet))
+      modelDesc = ApplicationTools::getStringParameter(prefix, params, "CodonRate(model=JC69)", suffix, suffixIsOptional, verbose);
+    else if (AlphabetTools::isWordAlphabet(alphabet))
+      modelDesc = ApplicationTools::getStringParameter(prefix, params, "Word(model=JC69)", suffix, suffixIsOptional, verbose);
+    else
+      modelDesc = ApplicationTools::getStringParameter(prefix, params, "JC69", suffix, suffixIsOptional, verbose);
+
+    auto_ptr<SubstitutionModel> model(bIO.read(alphabet, modelDesc, data, false));
+    map<string, string> unparsedParameterValues(bIO.getUnparsedArguments());
+    prefix += ".";
+
+    vector<string> specificParameters, sharedParameters;
+    setSubstitutionModelParametersInitialValuesWithAliases(
+      *model,
+      unparsedParameterValues, prefix, data,
+      existingParameters, specificParameters, sharedParameters,
+      verbose);
+    vector<int> nodesId = ApplicationTools::getVectorParameter<int>(prefix + "nodes_id", params, ',', ':', TextTools::toString(i), suffix, suffixIsOptional, true);
+    if (verbose)
+      ApplicationTools::displayResult("Model" + TextTools::toString(i + 1) + " is associated to", TextTools::toString(nodesId.size()) + " node(s).");
+    // Add model and specific parameters:
+    // DEBUG: cout << "Specific parameters:" << endl;
+    // DEBUG: VectorTools::print(specificParameters);
+    modelSet.addModel(model.get(), nodesId, specificParameters);
+    // Now set shared parameters:
+    for (size_t j = 0; j < sharedParameters.size(); j++)
+    {
+      string pName = sharedParameters[j];
+      // DEBUG: cout << "Shared parameter found: " << pName << endl;
+      string::size_type index = pName.find(".");
+      if (index == string::npos)
+        throw Exception("PhylogeneticsApplicationTools::getSubstitutionModelSet. Bad parameter name: " + pName);
+      string name = pName.substr(index + 1) + "_" + pName.substr(5, index - 5);
+      // namespace checking:
+      vector<size_t> models = modelSet.getModelsWithParameter(name);
+      if (models.size() == 0)
+        throw Exception("PhylogeneticsApplicationTools::getSubstitutionModelSet. Parameter `" + name + "' is not associated to any model.");
+      if (model->getNamespace() == modelSet.getModel(models[0])->getNamespace())
+        modelSet.setParameterToModel(modelSet.getParameterIndex(name), modelSet.getNumberOfModels() - 1);
+      else
+      {
+        throw Exception("Assigning a value to a parameter with a distinct namespace is not (yet) allowed. Consider using parameter aliasing instead.");
+      }
+    }
+    model.release();
+  }
+  // Finally check parameter aliasing:
+  string aliasDesc = ApplicationTools::getStringParameter("nonhomogeneous.alias", params, "", suffix, suffixIsOptional, verbose);
+  StringTokenizer st(aliasDesc, ",");
+  while (st.hasMoreToken())
+  {
+    string alias = st.nextToken();
+    string::size_type index = alias.find("->");
+    if (index == string::npos)
+      throw Exception("PhylogeneticsApplicationTools::getSubstitutionModelSet. Bad alias syntax, should contain `->' symbol: " + alias);
+    string p1 = alias.substr(0, index);
+    string p2 = alias.substr(index + 2);
+    ApplicationTools::displayResult("Parameter alias found", p1 + "->" + p2);
+    modelSet.aliasParameters(p1, p2);
+  }
+}
+
+/******************************************************************************/
+void PhylogeneticsApplicationTools::completeMixedSubstitutionModelSet(
+  MixedSubstitutionModelSet& mixedModelSet,
+  const Alphabet* alphabet,
+  const SiteContainer* data,
+  map<string, string>& params,
+  const string& suffix,
+  bool suffixIsOptional,
+  bool verbose)
+{
+  // /////////////////////////////////////////
+  // Looks for the allowed paths
+
+  size_t numd;
+  if (!ApplicationTools::parameterExists("site.number_of_paths", params))
+    numd = 0;
+  else
+    numd = ApplicationTools::getParameter<size_t>("site.number_of_paths", params, 1, suffix, suffixIsOptional, false);
+
+  if (verbose)
+    ApplicationTools::displayResult("Number of distinct paths", TextTools::toString(numd));
+
+  vector<string> vdesc;
+  while (numd)
+  {
+    string desc = ApplicationTools::getStringParameter("site.path" + TextTools::toString(numd), params, "",  suffix, suffixIsOptional, verbose);
+    if (desc.size() == 0)
+      break;
+    else
+      vdesc.push_back(desc);
+    numd--;
+  }
+
+  if (vdesc.size() == 0)
+  {
+    mixedModelSet.complete();
+    mixedModelSet.computeHyperNodesProbabilities();
+    return;
+  }
+
+  for (vector<string>::iterator it(vdesc.begin()); it != vdesc.end(); it++)
+  {
+    mixedModelSet.addEmptyHyperNode();
+    StringTokenizer st(*it, "&");
+    while (st.hasMoreToken())
+    {
+      string submodel = st.nextToken();
+      string::size_type indexo = submodel.find("[");
+      string::size_type indexf = submodel.find("]");
+      if ((indexo == string::npos) | (indexf == string::npos))
+        throw Exception("PhylogeneticsApplicationTools::setMixedSubstitutionModelSet. Bad path syntax, should contain `[]' symbols: " + submodel);
+      int num = TextTools::toInt(submodel.substr(5, indexo - 5));
+      string p2 = submodel.substr(indexo + 1, indexf - indexo - 1);
+
+      const MixedSubstitutionModel* pSM = dynamic_cast<const MixedSubstitutionModel*>(mixedModelSet.getModel(num - 1));
+      if (pSM == NULL)
+        throw BadIntegerException("PhylogeneticsApplicationTools::setMixedSubstitutionModelSet: Wron gmodel for number", num - 1);
+      Vint submodnb = pSM->getSubmodelNumbers(p2);
+
+      mixedModelSet.addToHyperNode(num - 1, submodnb);
+    }
+
+    if (!mixedModelSet.getHyperNode(mixedModelSet.getNumberOfHyperNodes() - 1).isComplete())
+      throw Exception("A path should own at least a submodel of each mixed model: " + *it);
+
+    if (verbose)
+      ApplicationTools::displayResult("Site Path", *it);
+  }
+
+  // / Checks if the paths are separate
+  if (!mixedModelSet.hasExclusivePaths())
+    throw Exception("All paths must be disjoint.");
+
+  // / Puts all the remaining models in a new path
+  string st;
+  st = (mixedModelSet.complete()) ? "Yes" : "No";
+
+  if (verbose)
+    ApplicationTools::displayResult("Site Path Completion", st);
+
+  mixedModelSet.computeHyperNodesProbabilities();
+
+  if (!mixedModelSet.getHyperNode(mixedModelSet.getNumberOfHyperNodes() - 1).isComplete())
+    throw Exception("The remaining submodels can not create a complete path.");
+}
+
+
+/******************************************************/
+/*** DISTRIBUTIONS ********************************/
+/******************************************************/
+
+
+/******************************************************************************/
+
+MultipleDiscreteDistribution* PhylogeneticsApplicationTools::getMultipleDistributionDefaultInstance(
+  const std::string& distDescription,
+  std::map<std::string, std::string>& unparsedParameterValues,
+  bool verbose)
+{
+  string distName;
+  MultipleDiscreteDistribution* pMDD  = 0;
+  map<string, string> args;
+  KeyvalTools::parseProcedure(distDescription, distName, args);
+
+  if (distName == "Dirichlet")
+  {
+    if (args.find("classes") == args.end())
+      throw Exception("Missing argument 'classes' (vector of number of classes) in " + distName
+                      + " distribution");
+    if (args.find("alphas") == args.end())
+      throw Exception("Missing argument 'alphas' (vector of Dirichlet shape parameters) in Dirichlet distribution");
+    vector<double> alphas;
+    vector<size_t> classes;
+
+    string rf = args["alphas"];
+    StringTokenizer strtok(rf.substr(1, rf.length() - 2), ",");
+    while (strtok.hasMoreToken())
+      alphas.push_back(TextTools::toDouble(strtok.nextToken()));
+
+    rf = args["classes"];
+    StringTokenizer strtok2(rf.substr(1, rf.length() - 2), ",");
+    while (strtok2.hasMoreToken())
+      classes.push_back(TextTools::toInt(strtok2.nextToken()));
+
+    pMDD = new DirichletDiscreteDistribution(classes, alphas);
+    vector<string> v = pMDD->getParameters().getParameterNames();
+
+    for (size_t i = 0; i < v.size(); i++)
+    {
+      unparsedParameterValues[v[i]] = TextTools::toString(pMDD->getParameterValue(pMDD->getParameterNameWithoutNamespace(v[i])));
+    }
+  }
+  else
+    throw Exception("Unknown multiple distribution name: " + distName);
+
+  return pMDD;
+}
+
+/******************************************************************************/
+
+DiscreteDistribution* PhylogeneticsApplicationTools::getRateDistribution(
+  map<string, string>& params,
+  const string& suffix,
+  bool suffixIsOptional,
+  bool verbose) throw (Exception)
+{
+  string distDescription = ApplicationTools::getStringParameter("rate_distribution", params, "Constant()", suffix, suffixIsOptional);
+
+  string distName;
+  map<string, string> args;
+  KeyvalTools::parseProcedure(distDescription, distName, args);
+
+  BppORateDistributionFormat bIO(true);
+  auto_ptr<DiscreteDistribution> rDist(bIO.read(distDescription, true));
+
+  if (verbose)
+  {
+    ApplicationTools::displayResult("Rate distribution", distName);
+    ApplicationTools::displayResult("Number of classes", TextTools::toString(rDist->getNumberOfCategories()));
+  }
+
+  return rDist.release();
+}
+
+
+/*************************************************************/
+/*****  OPTIMIZATORS *****************************************/
+/*************************************************************/
+
+/******************************************************************************/
+
+TreeLikelihood* PhylogeneticsApplicationTools::optimizeParameters(
+  TreeLikelihood* tl,
+  const ParameterList& parameters,
+  std::map<std::string, std::string>& params,
+  const std::string& suffix,
+  bool suffixIsOptional,
+  bool verbose)
+throw (Exception)
+{
+  string optimization = ApplicationTools::getStringParameter("optimization", params, "FullD(derivatives=Newton)", suffix, suffixIsOptional, false);
+  if (optimization == "None")
+    return tl;
+  string optName;
+  map<string, string> optArgs;
+  KeyvalTools::parseProcedure(optimization, optName, optArgs);
+
+  unsigned int optVerbose = ApplicationTools::getParameter<unsigned int>("optimization.verbose", params, 2, suffix, suffixIsOptional);
+
+  string mhPath = ApplicationTools::getAFilePath("optimization.message_handler", params, false, false, suffix, suffixIsOptional);
+  OutputStream* messageHandler =
+    (mhPath == "none") ? 0 :
+    (mhPath == "std") ? ApplicationTools::message :
+    new StlOutputStream(new ofstream(mhPath.c_str(), ios::out));
+  if (verbose)
+    ApplicationTools::displayResult("Message handler", mhPath);
+
+  string prPath = ApplicationTools::getAFilePath("optimization.profiler", params, false, false, suffix, suffixIsOptional);
+  OutputStream* profiler =
+    (prPath == "none") ? 0 :
+    (prPath == "std") ? ApplicationTools::message :
+    new StlOutputStream(new ofstream(prPath.c_str(), ios::out));
+  if (profiler)
+    profiler->setPrecision(20);
+  if (verbose)
+    ApplicationTools::displayResult("Profiler", prPath);
+
+  bool scaleFirst = ApplicationTools::getBooleanParameter("optimization.scale_first", params, false, suffix, suffixIsOptional, false);
+  if (scaleFirst)
+  {
+    // We scale the tree before optimizing each branch length separately:
+    if (verbose)
+      ApplicationTools::displayMessage("Scaling the tree before optimizing each branch length separately.");
+    double tolerance = ApplicationTools::getDoubleParameter("optimization.scale_first.tolerance", params, .0001, suffix, suffixIsOptional, true);
+    if (verbose)
+      ApplicationTools::displayResult("Scaling tolerance", TextTools::toString(tolerance));
+    int nbEvalMax = ApplicationTools::getIntParameter("optimization.scale_first.max_number_f_eval", params, 1000000, suffix, suffixIsOptional, true);
+    if (verbose)
+      ApplicationTools::displayResult("Scaling max # f eval", TextTools::toString(nbEvalMax));
+    OptimizationTools::optimizeTreeScale(
+      tl,
+      tolerance,
+      nbEvalMax,
+      messageHandler,
+      profiler);
+    if (verbose)
+      ApplicationTools::displayResult("New tree likelihood", -tl->getValue());
+  }
+
+  // Should I ignore some parameters?
+  ParameterList parametersToEstimate = parameters;
+  string paramListDesc = ApplicationTools::getStringParameter("optimization.ignore_parameter", params, "", suffix, suffixIsOptional, false);
+  if (paramListDesc.length() == 0)
+    paramListDesc = ApplicationTools::getStringParameter("optimization.ignore_parameters", params, "", suffix, suffixIsOptional, false);
+  StringTokenizer st(paramListDesc, ",");
+  while (st.hasMoreToken())
+  {
+    try
+    {
+      string param = st.nextToken();
+      if (param == "BrLen")
+      {
+        vector<string> vs = tl->getBranchLengthsParameters().getParameterNames();
+        parametersToEstimate.deleteParameters(vs);
+        if (verbose)
+          ApplicationTools::displayResult("Parameter ignored", string("Branch lengths"));
+      }
+      else if (param == "Ancient")
+      {
+        NonHomogeneousTreeLikelihood* nhtl = dynamic_cast<NonHomogeneousTreeLikelihood*>(tl);
+        if (!nhtl)
+          ApplicationTools::displayWarning("The 'Ancient' parameters do not exist in homogeneous models, and will be ignored.");
+        else
+        {
+          vector<string> vs = nhtl->getRootFrequenciesParameters().getParameterNames();
+          parametersToEstimate.deleteParameters(vs);
+        }
+        if (verbose)
+          ApplicationTools::displayResult("Parameter ignored", string("Root frequencies"));
+      }
+      else if (param.find("*") != string::npos)
+      {
+        vector<string> vs;
+        for (size_t j = 0; j < parametersToEstimate.size(); j++)
+        {
+          StringTokenizer stj(param, "*", true, false);
+          size_t pos1, pos2;
+          string parn = parametersToEstimate[j].getName();
+          bool flag(true);
+          string g = stj.nextToken();
+          pos1 = parn.find(g);
+          if (pos1 != 0)
+            flag = false;
+          pos1 += g.length();
+          while (flag && stj.hasMoreToken())
+          {
+            g = stj.nextToken();
+            pos2 = parn.find(g, pos1);
+            if (pos2 == string::npos)
+            {
+              flag = false;
+              break;
+            }
+            pos1 = pos2 + g.length();
+          }
+          if (flag &&
+              ((g.length() == 0) || (pos1 == parn.length()) || (parn.rfind(g) == parn.length() - g.length())))
+            vs.push_back(parn);
+        }
+
+        for (vector<string>::iterator it = vs.begin(); it != vs.end(); it++)
+        {
+          parametersToEstimate.deleteParameter(*it);
+          if (verbose)
+            ApplicationTools::displayResult("Parameter ignored", *it);
+        }
+      }
+      else
+      {
+        parametersToEstimate.deleteParameter(param);
+        if (verbose)
+          ApplicationTools::displayResult("Parameter ignored", param);
+      }
+    }
+    catch (ParameterNotFoundException& pnfe)
+    {
+      ApplicationTools::displayWarning("Parameter '" + pnfe.getParameter() + "' not found, and so can't be ignored!");
+    }
+  }
+
+  unsigned int nbEvalMax = ApplicationTools::getParameter<unsigned int>("optimization.max_number_f_eval", params, 1000000, suffix, suffixIsOptional);
+  if (verbose)
+    ApplicationTools::displayResult("Max # ML evaluations", TextTools::toString(nbEvalMax));
+
+  double tolerance = ApplicationTools::getDoubleParameter("optimization.tolerance", params, .000001, suffix, suffixIsOptional);
+  if (verbose)
+    ApplicationTools::displayResult("Tolerance", TextTools::toString(tolerance));
+
+  // Backing up or restoring?
+  auto_ptr<BackupListener> backupListener;
+  string backupFile = ApplicationTools::getAFilePath("optimization.backup.file", params, false, false);
+  if (backupFile != "none")
+  {
+    ApplicationTools::displayResult("Parameters will be backup to", backupFile);
+    backupListener.reset(new BackupListener(backupFile));
+    if (FileTools::fileExists(backupFile))
+    {
+      ApplicationTools::displayMessage("A backup file was found! Try to restore parameters from previous run...");
+      ifstream bck(backupFile.c_str(), ios::in);
+      vector<string> lines = FileTools::putStreamIntoVectorOfStrings(bck);
+      double fval = TextTools::toDouble(lines[0].substr(5));
+      ParameterList pl = tl->getParameters();
+      for (size_t l = 1; l < lines.size(); ++l)
+      {
+        if (!TextTools::isEmpty(lines[l]))
+        {
+          StringTokenizer stp(lines[l], "=");
+          if (stp.numberOfRemainingTokens() != 2)
+          {
+            cerr << "Corrupted backup file!!!" << endl;
+            cerr << "at line " << l << ": " << lines[l] << endl;
+          }
+          string pname  = stp.nextToken();
+          string pvalue = stp.nextToken();
+          size_t p = pl.whichParameterHasName(pname);
+          pl.setParameter(p, AutoParameter(pl[p]));
+          pl[p].setValue(TextTools::toDouble(pvalue));
+        }
+      }
+      bck.close();
+      tl->setParameters(pl);
+      if (abs(tl->getValue() - fval) > 0.000001)
+        throw Exception("Incorrect likelihood value after restoring, from backup file. Remove backup file and start from scratch :s");
+      ApplicationTools::displayResult("Restoring log-likelihood", -fval);
+    }
+  }
+
+  // There it goes...
+  bool optimizeTopo = ApplicationTools::getBooleanParameter("optimization.topology", params, false, suffix, suffixIsOptional, false);
+  if (verbose)
+    ApplicationTools::displayResult("Optimize topology", optimizeTopo ? "yes" : "no");
+  string nniMethod = ApplicationTools::getStringParameter("optimization.topology.algorithm_nni.method", params, "phyml", suffix, suffixIsOptional, false);
+  string nniAlgo;
+  if (nniMethod == "fast")
+  {
+    nniAlgo = NNITopologySearch::FAST;
+  }
+  else if (nniMethod == "better")
+  {
+    nniAlgo = NNITopologySearch::BETTER;
+  }
+  else if (nniMethod == "phyml")
+  {
+    nniAlgo = NNITopologySearch::PHYML;
+  }
+  else
+    throw Exception("Unknown NNI algorithm: '" + nniMethod + "'.");
+
+
+  string order = ApplicationTools::getStringParameter("derivatives", optArgs, "Newton", "", true, false);
+  string optMethodDeriv;
+  if (order == "Gradient")
+  {
+    optMethodDeriv = OptimizationTools::OPTIMIZATION_GRADIENT;
+  }
+  else if (order == "Newton")
+  {
+    optMethodDeriv = OptimizationTools::OPTIMIZATION_NEWTON;
+  }
+  else if (order == "BFGS")
+  {
+    optMethodDeriv = OptimizationTools::OPTIMIZATION_BFGS;
+  }
+  else
+    throw Exception("Unknown derivatives algorithm: '" + order + "'.");
+  if (verbose)
+    ApplicationTools::displayResult("Optimization method", optName);
+  if (verbose)
+    ApplicationTools::displayResult("Algorithm used for derivable parameters", order);
+
+  // See if we should reparametrize:
+  bool reparam = ApplicationTools::getBooleanParameter("optimization.reparametrization", params, false);
+  if (verbose)
+    ApplicationTools::displayResult("Reparametrization", (reparam ? "yes" : "no"));
+
+  // See if we should use a molecular clock constraint:
+  string clock = ApplicationTools::getStringParameter("optimization.clock", params, "None", "", true, false);
+  if (clock != "None" && clock != "Global")
+    throw Exception("Molecular clock option not recognized, should be one of 'Global' or 'None'.");
+  bool useClock = (clock == "Global");
+  if (useClock && optimizeTopo)
+    throw Exception("PhylogeneticsApplicationTools::optimizeParameters. Cannot optimize topology with a molecular clock.");
+  if (verbose)
+    ApplicationTools::displayResult("Molecular clock", clock);
+
+  unsigned int n = 0;
+  if ((optName == "D-Brent") || (optName == "D-BFGS"))
+  {
+    // Uses Newton-Brent method or Newton-BFGS method
+    string optMethodModel;
+    if (optName == "D-Brent")
+      optMethodModel = OptimizationTools::OPTIMIZATION_BRENT;
+    else
+      optMethodModel = OptimizationTools::OPTIMIZATION_BFGS;
+
+    unsigned int nstep = ApplicationTools::getParameter<unsigned int>("nstep", optArgs, 1, "", true, false);
+
+    if (optimizeTopo)
+    {
+      bool optNumFirst = ApplicationTools::getBooleanParameter("optimization.topology.numfirst", params, true, suffix, suffixIsOptional, false);
+      unsigned int topoNbStep = ApplicationTools::getParameter<unsigned int>("optimization.topology.nstep", params, 1, "", true, false);
+      double tolBefore = ApplicationTools::getDoubleParameter("optimization.topology.tolerance.before", params, 100, suffix, suffixIsOptional);
+      double tolDuring = ApplicationTools::getDoubleParameter("optimization.topology.tolerance.during", params, 100, suffix, suffixIsOptional);
+      tl = OptimizationTools::optimizeTreeNNI(
+        dynamic_cast<NNIHomogeneousTreeLikelihood*>(tl), parametersToEstimate,
+        optNumFirst, tolBefore, tolDuring, nbEvalMax, topoNbStep, messageHandler, profiler,
+        reparam, optVerbose, optMethodDeriv, nstep, nniAlgo);
+    }
+
+    if (verbose && nstep > 1)
+      ApplicationTools::displayResult("# of precision steps", TextTools::toString(nstep));
+    parametersToEstimate.matchParametersValues(tl->getParameters());
+    n = OptimizationTools::optimizeNumericalParameters(
+      dynamic_cast<DiscreteRatesAcrossSitesTreeLikelihood*>(tl), parametersToEstimate,
+      backupListener.get(), nstep, tolerance, nbEvalMax, messageHandler, profiler, reparam, optVerbose, optMethodDeriv, optMethodModel);
+  }
+  else if (optName == "FullD")
+  {
+    // Uses Newton-raphson algorithm with numerical derivatives when required.
+
+    if (optimizeTopo)
+    {
+      bool optNumFirst = ApplicationTools::getBooleanParameter("optimization.topology.numfirst", params, true, suffix, suffixIsOptional, false);
+      unsigned int topoNbStep = ApplicationTools::getParameter<unsigned int>("optimization.topology.nstep", params, 1, "", true, false);
+      double tolBefore = ApplicationTools::getDoubleParameter("optimization.topology.tolerance.before", params, 100, suffix, suffixIsOptional);
+      double tolDuring = ApplicationTools::getDoubleParameter("optimization.topology.tolerance.during", params, 100, suffix, suffixIsOptional);
+      tl = OptimizationTools::optimizeTreeNNI2(
+        dynamic_cast<NNIHomogeneousTreeLikelihood*>(tl), parametersToEstimate,
+        optNumFirst, tolBefore, tolDuring, nbEvalMax, topoNbStep, messageHandler, profiler,
+        reparam, optVerbose, optMethodDeriv, nniAlgo);
+    }
+
+    parametersToEstimate.matchParametersValues(tl->getParameters());
+    n = OptimizationTools::optimizeNumericalParameters2(
+      dynamic_cast<DiscreteRatesAcrossSitesTreeLikelihood*>(tl), parametersToEstimate,
+      backupListener.get(), tolerance, nbEvalMax, messageHandler, profiler, reparam, useClock, optVerbose, optMethodDeriv);
+  }
+  else
+    throw Exception("Unknown optimization method: " + optName);
+
+  string finalMethod = ApplicationTools::getStringParameter("optimization.final", params, "none", suffix, suffixIsOptional, true);
+  Optimizer* finalOptimizer  = 0;
+  if (finalMethod == "none")
+  {}
+  else if (finalMethod == "simplex")
+  {
+    finalOptimizer = new DownhillSimplexMethod(tl);
+  }
+  else if (finalMethod == "powell")
+  {
+    finalOptimizer = new PowellMultiDimensions(tl);
+  }
+  else
+    throw Exception("Unknown final optimization method: " + finalMethod);
+
+  if (finalOptimizer)
+  {
+    parametersToEstimate.matchParametersValues(tl->getParameters());
+    if (verbose)
+      ApplicationTools::displayResult("Final optimization step", finalMethod);
+    finalOptimizer->setProfiler(profiler);
+    finalOptimizer->setMessageHandler(messageHandler);
+    finalOptimizer->setMaximumNumberOfEvaluations(nbEvalMax);
+    finalOptimizer->getStopCondition()->setTolerance(tolerance);
+    finalOptimizer->setVerbose(verbose);
+    finalOptimizer->setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO);
+    finalOptimizer->init(parametersToEstimate);
+    finalOptimizer->optimize();
+    n += finalOptimizer->getNumberOfEvaluations();
+    delete finalOptimizer;
+  }
+
+  if (verbose)
+    ApplicationTools::displayResult("Performed", TextTools::toString(n) + " function evaluations.");
+  if (backupFile != "none")
+  {
+    remove(backupFile.c_str());
+  }
+  return tl;
+}
+
+/******************************************************************************/
+
+void PhylogeneticsApplicationTools::optimizeParameters(
+  DiscreteRatesAcrossSitesClockTreeLikelihood* tl,
+  const ParameterList& parameters,
+  map<string, string>& params,
+  const string& suffix,
+  bool suffixIsOptional,
+  bool verbose)
+throw (Exception)
+{
+  string optimization = ApplicationTools::getStringParameter("optimization", params, "FullD(derivatives=Newton)", suffix, suffixIsOptional, false);
+  if (optimization == "None")
+    return;
+  string optName;
+  map<string, string> optArgs;
+  KeyvalTools::parseProcedure(optimization, optName, optArgs);
+
+  unsigned int optVerbose = ApplicationTools::getParameter<unsigned int>("optimization.verbose", params, 2, suffix, suffixIsOptional);
+
+  string mhPath = ApplicationTools::getAFilePath("optimization.message_handler", params, false, false, suffix, suffixIsOptional);
+  OutputStream* messageHandler =
+    (mhPath == "none") ? 0 :
+    (mhPath == "std") ? ApplicationTools::message :
+    new StlOutputStream(new ofstream(mhPath.c_str(), ios::out));
+  if (verbose)
+    ApplicationTools::displayResult("Message handler", mhPath);
+
+  string prPath = ApplicationTools::getAFilePath("optimization.profiler", params, false, false, suffix, suffixIsOptional);
+  OutputStream* profiler =
+    (prPath == "none") ? 0 :
+    (prPath == "std") ? ApplicationTools::message :
+    new StlOutputStream(new ofstream(prPath.c_str(), ios::out));
+  if (profiler)
+    profiler->setPrecision(20);
+  if (verbose)
+    ApplicationTools::displayResult("Profiler", prPath);
+
+  ParameterList parametersToEstimate = parameters;
+
+  // Should I ignore some parameters?
+  string paramListDesc = ApplicationTools::getStringParameter("optimization.ignore_parameter", params, "", suffix, suffixIsOptional, false);
+  StringTokenizer st(paramListDesc, ",");
+  while (st.hasMoreToken())
+  {
+    try
+    {
+      string param = st.nextToken();
+      if (param == "BrLen")
+      {
+        vector<string> vs = tl->getBranchLengthsParameters().getParameterNames();
+        parametersToEstimate.deleteParameters(vs);
+        if (verbose)
+          ApplicationTools::displayResult("Parameter ignored", string("Branch lengths"));
+      }
+      else if (param == "Ancient")
+      {
+        NonHomogeneousTreeLikelihood* nhtl = dynamic_cast<NonHomogeneousTreeLikelihood*>(tl);
+        if (!nhtl)
+          ApplicationTools::displayWarning("The 'Ancient' parameters do not exist in homogeneous models, and will be ignored.");
+        else
+        {
+          vector<string> vs = nhtl->getRootFrequenciesParameters().getParameterNames();
+          parametersToEstimate.deleteParameters(vs);
+        }
+        if (verbose)
+          ApplicationTools::displayResult("Parameter ignored", string("Root frequencies"));
+      }
+      else
+      {
+        parametersToEstimate.deleteParameter(param);
+        if (verbose)
+          ApplicationTools::displayResult("Parameter ignored", param);
+      }
+    }
+    catch (ParameterNotFoundException& pnfe)
+    {
+      ApplicationTools::displayError("Parameter '" + pnfe.getParameter() + "' not found, and so can't be ignored!");
+    }
+  }
+
+  unsigned int nbEvalMax = ApplicationTools::getParameter<unsigned int>("optimization.max_number_f_eval", params, 1000000, suffix, suffixIsOptional);
+  if (verbose)
+    ApplicationTools::displayResult("Max # ML evaluations", TextTools::toString(nbEvalMax));
+
+  double tolerance = ApplicationTools::getDoubleParameter("optimization.tolerance", params, .000001, suffix, suffixIsOptional);
+  if (verbose)
+    ApplicationTools::displayResult("Tolerance", TextTools::toString(tolerance));
+
+  string order  = ApplicationTools::getStringParameter("derivatives", optArgs, "Gradient", "", true, false);
+  string optMethod, derMethod;
+  if (order == "Gradient")
+  {
+    optMethod = OptimizationTools::OPTIMIZATION_GRADIENT;
+  }
+  else if (order == "Newton")
+  {
+    optMethod = OptimizationTools::OPTIMIZATION_NEWTON;
+  }
+  else
+    throw Exception("Option '" + order + "' is not known for 'optimization.method.derivatives'.");
+  if (verbose)
+    ApplicationTools::displayResult("Optimization method", optName);
+  if (verbose)
+    ApplicationTools::displayResult("Algorithm used for derivable parameters", order);
+
+  // Backing up or restoring?
+  auto_ptr<BackupListener> backupListener;
+  string backupFile = ApplicationTools::getAFilePath("optimization.backup.file", params, false, false);
+  if (backupFile != "none")
+  {
+    ApplicationTools::displayResult("Parameters will be backup to", backupFile);
+    backupListener.reset(new BackupListener(backupFile));
+    if (FileTools::fileExists(backupFile))
+    {
+      ApplicationTools::displayMessage("A backup file was found! Try to restore parameters from previous run...");
+      ifstream bck(backupFile.c_str(), ios::in);
+      vector<string> lines = FileTools::putStreamIntoVectorOfStrings(bck);
+      double fval = TextTools::toDouble(lines[0].substr(5));
+      ParameterList pl = tl->getParameters();
+      for (size_t l = 1; l < lines.size(); ++l)
+      {
+        if (!TextTools::isEmpty(lines[l]))
+        {
+          StringTokenizer stp(lines[l], "=");
+          if (stp.numberOfRemainingTokens() != 2)
+          {
+            cerr << "Corrupted backup file!!!" << endl;
+            cerr << "at line " << l << ": " << lines[l] << endl;
+          }
+          string pname  = stp.nextToken();
+          string pvalue = stp.nextToken();
+          size_t p = pl.whichParameterHasName(pname);
+          pl.setParameter(p, AutoParameter(pl[p]));
+          pl[p].setValue(TextTools::toDouble(pvalue));
+        }
+      }
+      bck.close();
+      tl->setParameters(pl);
+      if (abs(tl->getValue() - fval) > 0.000001)
+        throw Exception("Incorrect likelihood value after restoring, from backup file. Remove backup file and start from scratch :s");
+      ApplicationTools::displayResult("Restoring log-likelihood", -fval);
+    }
+  }
+
+  size_t n = 0;
+  if (optName == "D-Brent")
+  {
+    // Uses Newton-Brent method:
+    unsigned int nstep = ApplicationTools::getParameter<unsigned int>("nstep", optArgs, 1, "", true, false);
+    if (verbose && nstep > 1)
+      ApplicationTools::displayResult("# of precision steps", TextTools::toString(nstep));
+    n = OptimizationTools::optimizeNumericalParametersWithGlobalClock(
+      tl,
+      parametersToEstimate,
+      backupListener.get(),
+      nstep,
+      tolerance,
+      nbEvalMax,
+      messageHandler,
+      profiler,
+      optVerbose,
+      optMethod);
+  }
+  else if (optName == "FullD")
+  {
+    // Uses Newton-raphson alogrithm with numerical derivatives when required.
+    n = OptimizationTools::optimizeNumericalParametersWithGlobalClock2(
+      tl,
+      parametersToEstimate,
+      backupListener.get(),
+      tolerance,
+      nbEvalMax,
+      messageHandler,
+      profiler,
+      optVerbose,
+      optMethod);
+  }
+  else
+    throw Exception("Unknown optimization method: " + optName);
+
+  string finalMethod = ApplicationTools::getStringParameter("optimization.final", params, "none", suffix, suffixIsOptional, false);
+  Optimizer* finalOptimizer  = 0;
+  if (finalMethod == "none")
+  {}
+  else if (finalMethod == "simplex")
+  {
+    finalOptimizer = new DownhillSimplexMethod(tl);
+  }
+  else if (finalMethod == "powell")
+  {
+    finalOptimizer = new PowellMultiDimensions(tl);
+  }
+  else
+    throw Exception("Unknown final optimization method: " + finalMethod);
+
+  if (finalOptimizer)
+  {
+    parametersToEstimate.matchParametersValues(tl->getParameters());
+    ApplicationTools::displayResult("Final optimization step", finalMethod);
+    finalOptimizer->setProfiler(profiler);
+    finalOptimizer->setMessageHandler(messageHandler);
+    finalOptimizer->setMaximumNumberOfEvaluations(nbEvalMax);
+    finalOptimizer->getStopCondition()->setTolerance(tolerance);
+    finalOptimizer->setVerbose(verbose);
+    finalOptimizer->setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO);
+    finalOptimizer->init(parametersToEstimate);
+    finalOptimizer->optimize();
+    n += finalOptimizer->getNumberOfEvaluations();
+    delete finalOptimizer;
+  }
+
+  if (verbose)
+    ApplicationTools::displayResult("Performed", TextTools::toString(n) + " function evaluations.");
+  if (backupFile != "none")
+  {
+    remove(backupFile.c_str());
+  }
+}
+
+/******************************************************************************/
+
+void PhylogeneticsApplicationTools::checkEstimatedParameters(const ParameterList& pl)
+{
+  for (size_t i = 0; i < pl.size(); ++i)
+  {
+    const Constraint* constraint = pl[i].getConstraint();
+    if (constraint)
+    {
+      double value = pl[i].getValue();
+      if (!constraint->isCorrect(value - 1e-6) || !constraint->isCorrect(value + 1e-6))
+      {
+        ApplicationTools::displayWarning("This parameter has a value close to the boundary: " + pl[i].getName() + "(" + TextTools::toString(value) + ").");
+      }
+    }
+  }
+}
+
+
+/*************************************************************/
+/**************  OUTPUT **************************************/
+/*************************************************************/
+
+/******************************************************************************/
+
+void PhylogeneticsApplicationTools::writeTree(
+  const TreeTemplate<Node>& tree,
+  map<string, string>& params,
+  const string& prefix,
+  const string& suffix,
+  bool suffixIsOptional,
+  bool verbose,
+  bool checkOnly) throw (Exception)
+{
+  string format = ApplicationTools::getStringParameter(prefix + "tree.format", params, "Newick", suffix, suffixIsOptional, false);
+  string file = ApplicationTools::getAFilePath(prefix + "tree.file", params, true, false, suffix, suffixIsOptional);
+  OTree* treeWriter;
+  if (format == "Newick")
+    treeWriter = new Newick();
+  else if (format == "Nexus")
+    treeWriter = new NexusIOTree();
+  else if (format == "NHX")
+    treeWriter = new Nhx(false);
+  else
+    throw Exception("Unknown format for tree writing: " + format);
+  if (!checkOnly)
+    treeWriter->write(tree, file, true);
+  delete treeWriter;
+  if (verbose)
+    ApplicationTools::displayResult("Wrote tree to file ", file);
+}
+
+/******************************************************************************/
+
+void PhylogeneticsApplicationTools::writeTrees(
+  const vector<Tree*>& trees,
+  map<string, string>& params,
+  const string& prefix,
+  const string& suffix,
+  bool suffixIsOptional,
+  bool verbose,
+  bool checkOnly) throw (Exception)
+{
+  string format = ApplicationTools::getStringParameter(prefix + "trees.format", params, "Newick", suffix, suffixIsOptional, false);
+  string file = ApplicationTools::getAFilePath(prefix + "trees.file", params, true, false, suffix, suffixIsOptional);
+  OMultiTree* treeWriter;
+  if (format == "Newick")
+    treeWriter = new Newick();
+  else if (format == "Nexus")
+    treeWriter = new NexusIOTree();
+  else if (format == "NHX")
+    treeWriter = new Nhx();
+  else
+    throw Exception("Unknow format for tree writing: " + format);
+  if (!checkOnly)
+    treeWriter->write(trees, file, true);
+  delete treeWriter;
+  if (verbose)
+    ApplicationTools::displayResult("Wrote trees to file ", file);
+}
+
+/******************************************************************************/
+
+void PhylogeneticsApplicationTools::printParameters(const SubstitutionModel* model, OutputStream& out)
+{
+  out << "model=";
+  map<string, string> globalAliases;
+  vector<string> writtenNames;
+  BppOSubstitutionModelFormat bIO(BppOSubstitutionModelFormat::ALL, true, true, true, false);
+  bIO.write(*model, out, globalAliases, writtenNames);
+  out.endLine();
+}
+
+/******************************************************************************/
+
+void PhylogeneticsApplicationTools::printParameters(const SubstitutionModelSet* modelSet, OutputStream& out)
+{
+  (out << "nonhomogeneous=general").endLine();
+  (out << "nonhomogeneous.number_of_models=" << modelSet->getNumberOfModels()).endLine();
+
+  // Get the parameter links:
+  map< size_t, vector<string> > modelLinks; // for each model index, stores the list of global parameters.
+  map< string, set<size_t> > parameterLinks; // for each parameter name, stores the list of model indices, wich should be sorted.
+  vector<string> writtenNames;
+  ParameterList pl = modelSet->getParameters();
+  ParameterList plroot = modelSet->getRootFrequenciesParameters();
+  for (size_t i = 0; i < pl.size(); i++)
+  {
+    if (!plroot.hasParameter(pl[i].getName()))
+    {
+      string name = pl[i].getName();
+      vector<size_t> models = modelSet->getModelsWithParameter(name);
+      for (size_t j = 0; j < models.size(); ++j)
+      {
+        modelLinks[models[j]].push_back(name);
+        parameterLinks[name].insert(models[j]);
+      }
+    }
+  }
+
+  // Loop over all models:
+  for (size_t i = 0; i < modelSet->getNumberOfModels(); i++)
+  {
+    const SubstitutionModel* model = modelSet->getModel(i);
+
+    // First get the global aliases for this model:
+    map<string, string> globalAliases;
+    vector<string> names = modelLinks[i];
+    for (size_t j = 0; j < names.size(); j++)
+    {
+      const string name = names[j];
+      if (parameterLinks[name].size() > 1)
+      {
+        // there is a global alias here
+        if (*parameterLinks[name].begin() != i) // Otherwise, this is the 'reference' value
+        {
+          globalAliases[modelSet->getParameterModelName(name)] = "model" + TextTools::toString((*parameterLinks[name].begin()) + 1) + "." + modelSet->getParameterModelName(name);
+        }
+      }
+    }
+
+    // Now print it:
+    writtenNames.clear();
+    out.endLine() << "model" << (i + 1) << "=";
+    BppOSubstitutionModelFormat bIOsm(BppOSubstitutionModelFormat::ALL, true, true, true, false);
+    bIOsm.write(*model, out, globalAliases, writtenNames);
+    out.endLine();
+    vector<int> ids = modelSet->getNodesWithModel(i);
+    out << "model" << (i + 1) << ".nodes_id=" << ids[0];
+    for (size_t j = 1; j < ids.size(); ++j)
+    {
+      out << "," << ids[j];
+    }
+    out.endLine();
+  }
+
+  // Root frequencies:
+  out.endLine();
+  (out << "# Root frequencies:").endLine();
+  out << "nonhomogeneous.root_freq=";
+
+  BppOFrequenciesSetFormat bIO(BppOFrequenciesSetFormat::ALL, false);
+  bIO.write(modelSet->getRootFrequenciesSet(), out, writtenNames);
+}
+
+/******************************************************************************/
+
+void PhylogeneticsApplicationTools::printParameters(const DiscreteDistribution* rDist, OutputStream& out)
+{
+  out << "rate_distribution=";
+  map<string, string> globalAliases;
+  vector<string> writtenNames;
+  const BppORateDistributionFormat* bIO = new BppORateDistributionFormat(true);
+
+  bIO->write(*rDist, out, globalAliases, writtenNames);
+  delete bIO;
+  out.endLine();
+}
+
+/************************
+ * Substitution Mapping *
+ ************************/
+
+SubstitutionCount* PhylogeneticsApplicationTools::getSubstitutionCount(
+  const Alphabet* alphabet,
+  const SubstitutionModel* model,
+  map<string, string>& params,
+  string suffix)
+{
+  SubstitutionCount* substitutionCount = 0;
+  string nijtOption;
+  map<string, string> nijtParams;
+  string nijtText = ApplicationTools::getStringParameter("nijt", params, "Uniformization", suffix, true);
+  KeyvalTools::parseProcedure(nijtText, nijtOption, nijtParams);
+
+  if (nijtOption == "Laplace")
+  {
+    int trunc = ApplicationTools::getIntParameter("trunc", nijtParams, 10, suffix, true);
+    substitutionCount = new LaplaceSubstitutionCount(model, trunc);
+  }
+  else if (nijtOption == "Uniformization")
+  {
+    string weightOption = ApplicationTools::getStringParameter("weight", nijtParams, "None", "", true, false);
+    AlphabetIndex2* weights = SequenceApplicationTools::getAlphabetIndex2(alphabet, weightOption, "Substitution weight scheme:");
+    substitutionCount = new UniformizationSubstitutionCount(model, new TotalSubstitutionRegister(alphabet), weights);
+  }
+  else if (nijtOption == "Decomposition")
+  {
+    string weightOption = ApplicationTools::getStringParameter("weight", nijtParams, "None", "", true, false);
+    AlphabetIndex2* weights = SequenceApplicationTools::getAlphabetIndex2(alphabet, weightOption, "Substitution weight scheme:");
+    const ReversibleSubstitutionModel* revModel = dynamic_cast<const ReversibleSubstitutionModel*>(model);
+    if (revModel)
+      substitutionCount = new DecompositionSubstitutionCount(revModel, new TotalSubstitutionRegister(alphabet), weights);
+    else
+      throw Exception("Decomposition method can only be used with reversible substitution models.");
+  }
+  else if (nijtOption == "Naive")
+  {
+    string weightOption = ApplicationTools::getStringParameter("weight", nijtParams, "None", "", true, false);
+    AlphabetIndex2* weights = SequenceApplicationTools::getAlphabetIndex2(alphabet, weightOption, "Substitution weight scheme:");
+    substitutionCount = new NaiveSubstitutionCount(new TotalSubstitutionRegister(alphabet), false, weights);
+  }
+  else if (nijtOption == "Label")
+  {
+    substitutionCount = reinterpret_cast<SubstitutionCount*>(new LabelSubstitutionCount(alphabet));
+  }
+  else if (nijtOption == "ProbOneJump")
+  {
+    substitutionCount = reinterpret_cast<SubstitutionCount*>(new OneJumpSubstitutionCount(model));
+  }
+  else
+  {
+    ApplicationTools::displayError("Invalid option '" + nijtOption + ", in 'nijt' parameter.");
+    exit(-1);
+  }
+  ApplicationTools::displayResult("Substitution count procedure", nijtOption);
+
+  // Send results:
+  return substitutionCount;
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/App/PhylogeneticsApplicationTools.h b/src/Bpp/Phyl/App/PhylogeneticsApplicationTools.h
new file mode 100644
index 0000000..7872ee9
--- /dev/null
+++ b/src/Bpp/Phyl/App/PhylogeneticsApplicationTools.h
@@ -0,0 +1,630 @@
+//
+// File: PhylogeneticsApplicationTools.h
+// Created by: Julien Dutheil
+// Created on: Fri Oct 21 16:49 2005
+// from old file ApplicationTools.h created on Sun Dec 14 09:36:26 2003
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _PHYLOGENETICSAPPLICATIONTOOLS_H_
+#define _PHYLOGENETICSAPPLICATIONTOOLS_H_
+
+#include "../Tree.h"
+#include "../Model/SubstitutionModel.h"
+#include "../Model/SubstitutionModelSet.h"
+#include "../Model/MixedSubstitutionModelSet.h"
+#include "../Model/MarkovModulatedSubstitutionModel.h"
+#include "../Likelihood/HomogeneousTreeLikelihood.h"
+#include "../Likelihood/ClockTreeLikelihood.h"
+#include "../Mapping/SubstitutionCount.h"
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Text/StringTokenizer.h>
+#include <Bpp/Io/OutputStream.h>
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+#include <Bpp/Numeric/Prob/MultipleDiscreteDistribution.h>
+#include <Bpp/Numeric/Function/Optimizer.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SiteContainer.h>
+#include <Bpp/Seq/Container/VectorSiteContainer.h>
+
+// From the STL:
+#include <string>
+#include <map>
+
+namespace bpp
+{
+
+
+  /**
+   * @brief This class provides some common tools for applications.
+   *
+   * The functions parse some option file, create corresponding objects and send
+   * a pointer toward it.
+   * 
+   * The option files are supposed to follow this simple format:
+   * @code
+   * parameterName = parameterContent
+   * @endcode
+   * with one parameter per line.
+   *
+   * @see ApplicationTools
+   */
+  class PhylogeneticsApplicationTools
+  {
+  
+  public:
+    PhylogeneticsApplicationTools();
+    virtual ~PhylogeneticsApplicationTools();
+  
+
+    /**
+     * @brief Build a Tree object according to options.
+     *
+     * See the Bio++ Program Suite manual for a description of available options.
+     *
+     * @param params  The attribute map where options may be found.
+     * @param prefix  A prefix to be applied to each attribute name.
+     * @param suffix  A suffix to be applied to each attribute name.
+     * @param suffixIsOptional Tell if the suffix is absolutely required.
+     * @param verbose Print some info to the 'message' output stream.
+     * @return A new Tree object according to the specified options.
+     * @throw Exception if an error occured.
+     */
+    static Tree* getTree(
+                         std::map<std::string, std::string>& params,
+                         const std::string& prefix = "input.",
+                         const std::string& suffix = "",
+                         bool suffixIsOptional = true,
+                         bool verbose = true) throw (Exception);
+ 
+    /**
+     * @brief Build a list ofTree objects according to options.
+     *
+     * See the Bio++ Program Suite manual for a description of available options.
+     *
+     * @param params  The attribute map where options may be found.
+     * @param prefix  A prefix to be applied to each attribute name.
+     * @param suffix  A suffix to be applied to each attribute name.
+     * @param suffixIsOptional Tell if the suffix is absolutely required.
+     * @param verbose Print some info to the 'message' output stream.
+     * @return A new vector of Tree objects according to the specified options.
+     * @throw Exception if an error occured.
+     */
+    static std::vector<Tree*> getTrees(
+                                       std::map<std::string, std::string>& params,
+                                       const std::string& prefix = "input.",
+                                       const std::string& suffix = "",
+                                       bool suffixIsOptional = true,
+                                       bool verbose = true) throw (Exception);
+  
+    /**
+     * @brief Build a SubstitutionModel object according to options.
+     *
+     * Creates a new substitution model object according to model description syntax
+     * (see the Bio++ Progam Suite manual for a detailed description of this syntax). The
+     * function also parses the parameter values and set them accordingly.
+     *
+     * @param alphabet The alphabet to use in the model.
+     * @param data     A pointer toward the SiteContainer for which the substitution model is designed.
+     *                 The alphabet associated to the data must be of the same type as the one specified for the model.
+     *                 May be equal to NULL, but in this case use_observed_freq option will be unavailable.
+     * @param params   The attribute map where options may be found.
+     * @param suffix   A suffix to be applied to each attribute name.
+     * @param suffixIsOptional Tell if the suffix is absolutely required.
+     * @param verbose Print some info to the 'message' output stream.
+     * @return A new SubstitutionModel object according to options specified.
+     * @throw Exception if an error occured.
+     */
+    static SubstitutionModel* getSubstitutionModel(
+                                                   const Alphabet* alphabet,
+                                                   const SiteContainer* data, 
+                                                   std::map<std::string, std::string>& params,
+                                                   const std::string& suffix = "",
+                                                   bool suffixIsOptional = true,
+                                                   bool verbose = true) throw (Exception);
+  
+
+    /**
+     * @brief Set parameter initial values of a given model in a set according to options.
+     *
+     * Parameters actually depends on the model passed as argument.
+     * See getSubstitutionModelSet for more information.
+     *
+     * This function is mainly for internal usage, you're probably looking for the getSubstitutionModel or getSubstitutionModelSet function.
+     *
+     * @param model                   The model to set.
+     * @param unparsedParameterValues A map that contains all the model parameters
+     *                                names and their corresponding unparsed value, if they were found.
+     * @param modelPrefix The prefix to use to record prameters from this model.
+     * @param data   A pointer toward the SiteContainer for which the substitution model is designed.
+     *               The alphabet associated to the data must be of the same type as the one specified for the model.
+     *               May be equal to NULL, but in this case use_observed_freq option will be unavailable.
+     * @param existingParams (in/out) A map with already existing value that have been found in previous calls, and may be recalled here.
+     *                       New parameters found here will be added.
+     * @param specificParams (out) Parameters specific to this model will be recorded here.
+     * @param sharedParams (out) remote parameters will be recorded here.
+     * @param verbose Print some info to the 'message' output stream.
+     * @throw Exception if an error occured.
+     */
+    static void setSubstitutionModelParametersInitialValuesWithAliases(
+        SubstitutionModel& model,
+        std::map<std::string, std::string>& unparsedParameterValues,
+        const std::string& modelPrefix,
+        const SiteContainer* data,
+        std::map<std::string, double>& existingParams,
+        std::vector<std::string>& specificParams,
+        std::vector<std::string>& sharedParams,
+        bool verbose) throw (Exception);
+
+    /**
+     * @brief Get A FrequenciesSet object for root frequencies (NH models) according to options.
+     *
+     * @param alphabet The alpabet to use.
+     * @param data      A pointer toward the SiteContainer for which the substitution model is designed.
+     *                  The alphabet associated to the data must be of the same type as the one specified for the model.
+     *                  May be equal to NULL, but in this cas use_observed_freq option will be unavailable.
+     * @param params    The attribute map where options may be found.
+     * @param rateFreqs A vector of rate catégories frequencies in case of a Markov Modulated Markov Model.
+     *                  Ignored if a vector with size 0 is passed.
+     * @param suffix    A suffix to be applied to each attribute name.
+     * @param suffixIsOptional Tell if the suffix is absolutely required.
+     * @param verbose   Print some info to the 'message' output stream.
+     * @return A new FrequenciesSet object according to options specified.
+     * @throw Exception if an error occured.
+     */
+    static FrequenciesSet* getRootFrequenciesSet(
+        const Alphabet* alphabet,
+        const SiteContainer* data, 
+        std::map<std::string, std::string>& params,
+        const std::vector<double>& rateFreqs,
+        const std::string& suffix = "",
+        bool suffixIsOptional = true,
+        bool verbose = true) throw (Exception);
+
+    /**
+     * @brief Get A FrequenciesSet object according to options.
+     *
+     * @param alphabet The alpabet to use.
+     * @param freqDescription A string in the keyval syntaxe describing the frequency set to use.:if expand("%") == ""|browse confirm w|else|confirm w|endif
+     * 
+     * @param data      A pointer toward the SiteContainer for which the substitution model is designed.
+     *                  The alphabet associated to the data must be of the same type as the one specified for the model.
+     *                  May be equal to NULL, but in this cas use_observed_freq option will be unavailable.
+     * @param rateFreqs A vector of rate catégories frequencies in case of a Markov Modulated Markov Model.
+     *                  Ignored if a vector with size 0 is passed.
+     * @param verbose   Print some info to the 'message' output stream.
+     * @return A new FrequenciesSet object according to options specified.
+     * @throw Exception if an error occured.
+     */
+    static FrequenciesSet* getFrequenciesSet(
+        const Alphabet* alphabet,
+        const std::string& freqDescription,
+        const SiteContainer* data, 
+        const std::vector<double>& rateFreqs,
+        bool verbose = true)
+      throw (Exception);
+
+    /**
+     * @brief Gets a SubstitutionModelSet object according to options.
+     *
+     * See setSubstitutionModelSet and setMixedSubstitutionModelSet
+     * methods.
+     */
+     static SubstitutionModelSet* getSubstitutionModelSet(
+                                        const Alphabet* alphabet,
+                                        const SiteContainer* data, 
+                                        std::map<std::string, std::string>& params,
+                                        const std::string& suffix = "",
+                                        bool suffixIsOptional = true,
+                                        bool verbose = true);    
+
+     /**
+     * @brief Sets a SubstitutionModelSet object according to options.
+     *
+     * This model set is meant to be used with non-homogeneous substitution models of sequence evolution.
+     *
+     * Recognized options are:
+     * - number_of_models: the number of distinct SubstitutionModel to use.
+     *
+     * Then, for each of the models, the following information must be provided:
+     * - model1='model name(parameters'='value',...)
+     * Model names and parameters follow the same syntaxe as for the getSubstitutionModel method.
+     * - model1.nodes='list of nodes id, separated by comas'.
+     * And then
+     * - model2=...
+     * etc.
+     *
+     * All models must be fully specified, and at the end of the description, all nodes must be attributed to a model,
+     * otherwise an exception is thrown.
+     * 
+     * Finally, this is also allowed for models to share one or several parameters.
+     * for instance:
+     * @code
+     * model1=T92(kappa=2.0, theta=0.5)
+     * model2=T92(kappa=model1.kappa, theta=0.5)
+     * @endcode
+     * In this case model1 and model2 with have their own and independent theta parameter, but only one kappa parameter will be used for both models.
+     * Note that
+     * @code
+     * model1=T92(kappa=2.0, theta=0.5)
+     * model1.nodes=1,2,3
+     * model2=T92(kappa= model1.kappa, theta=model1.theta)
+     * model2.nodes=4,5,6
+     * @endcode
+     * is equivalent to
+     * @code
+     * model1=T92(kappa=2.0, theta=0.5)
+     * model1.nodes=1,2,3,4,5,6
+     * @endcode
+     * but will require more memory and use more CPU, since some calculations will be performed twice.
+     *
+     * @param modelSet The modified SubstitutionModelSet object according to options specified.
+     * @param alphabet The alpabet to use in all models.
+     * @param data     A pointer toward the SiteContainer for which the substitution model is designed.
+     *                  The alphabet associated to the data must be of the same type as the one specified for the model.
+     *                 May be equal to NULL, but in this cas use_observed_freq option will be unavailable.
+     * @param params   The attribute map where options may be found.
+     * @param suffix   A suffix to be applied to each attribute name.
+     * @param suffixIsOptional Tell if the suffix is absolutely required.
+     * @param verbose Print some info to the 'message' output stream.
+     * @throw Exception if an error occured.
+     */
+    static void setSubstitutionModelSet(
+                                        SubstitutionModelSet& modelSet,
+                                        const Alphabet* alphabet,
+                                        const SiteContainer* data, 
+                                        std::map<std::string, std::string>& params,
+                                        const std::string& suffix = "",
+                                        bool suffixIsOptional = true,
+                                        bool verbose = true);
+    
+    /**
+     * @brief Complete a MixedSubstitutionModelSet object according to
+     * options, given this model has already been filled through
+     * setSubstitutionModelSet method.
+     *
+     * In addition, this method builds the allowed combinations of
+     * submodels of the different mixed models.
+     *
+     * If none combination is given, then all possible submodels
+     * combinations will be considered.
+     *
+     * The submodels dependencies are given a sets of combinations of
+     * the mixed variables of the mixed models. For instance, if we
+     * have:
+     *
+     * @code
+     * model1=MixedModel(model=T92(kappa=Gamma(n=4), theta=0.5))
+     * model2=MixedModel(model=T92(kappa=Gaussian(n=5), theta=Beta(n=3)))
+     * @endcode
+     *
+     * In this case model1 is a mixture of 4 T92 submodels and model2
+     * a mixture of 15 T92 submodels. These submodels are denoted with
+     * the parameter name and the class number. For example, the
+     * submodels of model1 are denoted model1[kappa_1], ...,
+     * model1[kappa_4], and the submodels of model2 are denoted
+     * model2[kappa_1,theta_1], ..., model2[kappa_5, theta_3].
+     * Additionnaly, for instance, model2[kappa_2] denotes all the
+     * submodels whose description has kappa_2.
+     *
+     * By default, when switching from model1 to model2, a site is
+     * allowed to switch between any submodel of model1 and any
+     * submodel of model2. If the only allowed combination is that a
+     * site follows submodels model1(kappa_1) and
+     * model2(kappa_3,theta_2), it is denoted:
+     *
+     * @code
+     * site.allowedpaths= model1[kappa_1] & model2[kappa_3,theta_2]
+     * @endcode
+     *
+     * With additional combination saying that a site can follow
+     * submodels model1[kappa_2] and any submodel of model2[kappa_3]
+     * is denoted:
+     *
+     * @code
+     * site.allowedpaths= model1[kappa_1] & model2[kappa_3,theta_2] |
+     *                    model1[kappa_2] & model2[kappa_3]
+     * @endcode
+     *
+     * See MixedSubstitutionModelSet description for further
+     * information.
+     *
+     * @param mixedModelSet The modified MixedSubstitutionModelSet object according to options specified.
+     * @param alphabet The alpabet to use in all models.
+     * @param data     A pointer toward the SiteContainer for which the substitution model is designed.
+     *                  The alphabet associated to the data must be of the same type as the one specified for the model.
+     *                 May be equal to NULL, but in this cas use_observed_freq option will be unavailable.
+     * @param params   The attribute map where options may be found.
+     * @param suffix   A suffix to be applied to each attribute name.
+     * @param suffixIsOptional Tell if the suffix is absolutely required.
+     * @param verbose Print some info to the 'message' output stream.
+     * @throw Exception if an error occured.
+     */
+    
+    static void completeMixedSubstitutionModelSet(
+                                             MixedSubstitutionModelSet& mixedModelSet,
+                                             const Alphabet* alphabet,
+                                             const SiteContainer* data, 
+                                             std::map<std::string, std::string>& params,
+                                             const std::string& suffix = "",
+                                             bool suffixIsOptional = true,
+                                             bool verbose = true);
+
+    /**
+     * @brief Build a multi-dimension distribution as a
+     * MultipleDiscreteDistribution object with default parameter
+     * values according to a keyval description.
+     *
+     * Check the Bio++ Program Suite documentation for a description of the syntax.
+     * It is mainly for internal usage, you're probably looking for the getRateDistribution function.
+     *
+     * @param distDescription         A string describing the model in the keyval syntax.
+     * @param unparsedParameterValues [out] a map that will contain all the distribution parameters
+     *                                names and their corresponding unparsed value, if they were found.
+     * @param verbose                 Print some info to the 'message' output stream.
+     * @return A new MultipleDiscreteDistribution object according to options specified.
+     * @throw Exception if an error occured.
+     */
+    
+    static MultipleDiscreteDistribution* getMultipleDistributionDefaultInstance(
+                                                                        const std::string& distDescription,
+                                                                        std::map<std::string, std::string>& unparsedParameterValues,
+                                                                        bool verbose = true);
+
+    /**
+     * @brief Build a DiscreteDistribution object according to options.
+     *
+     * Creates a new rate distribution object according to distribution description syntax
+     * (see the Bio++ Progam Suite manual for a detailed description of this syntax). The
+     * function also parses the parameter values and set them accordingly.
+     *
+     * @param params  The attribute map where options may be found.
+     * @param suffix  A suffix to be applied to each attribute name.
+     * @param suffixIsOptional Tell if the suffix is absolutely required.
+     * @param verbose Print some info to the 'message' output stream.
+     * @return A new DiscreteDistribution object according to options specified.
+     * @throw Exception if an error occured.
+     */
+    static DiscreteDistribution* getRateDistribution(
+        std::map<std::string, std::string>& params,
+        const std::string& suffix = "",
+        bool suffixIsOptional = true,
+        bool verbose = true)
+      throw (Exception);
+      
+    /**
+     * @brief Optimize parameters according to options.
+     *
+     * Options used are:
+     * - optimization = Tell if optimization must be performed.
+     * - optimization.message_handler = [std, file_path]
+     *   A path to a specific path (existing will be overwritten) or std for use
+     *   of the standard output.
+     * - optimization.profiler = [std, file_path], idem for the profiling (history
+     *   of all functions evaluations).
+     * - optimization.max_number_f_eval = The maximum number of function evaluation.
+     * - optimization.tolerance = The tolerance parameter (when to stop the optimization).
+     * - optimization.scale_first = Tell if we must scale the tree first.
+     * - optimization.ignore_parameter = A coma-separated list of parameter
+     *   names to ignore in the optimizing process.
+     * - optimization.method = [DB|fullD] Algorithm to use: Derivatives+Brent or full derivatives, with numerical derivatives when required.
+     * - optimization.method.derivatives = [gradient|newton] Use Conjugate Grandient or Newton-Rhaphson algorithm.
+     * - optimization.final = [none|simplex|powell] Perform a downhill simplex or a Powell multidimensions optimization
+     * - optimization.topology = Tell if we must optimize tree topology. Toplogy estimation uses the DB algorithm with Newton-Raphson during estimation.
+     *   The previous options will be used only for final estimation of numerical parameters.
+     * Options depending on other options:
+     * - If optimization.scale_first is set to true:
+     *   - optimization.scale_first.tolerance = The tolerance of the scaling alogrithm.
+     *   - optimization.scale_first.max_number_f_eval = the maximum number of function evaluations
+     *     for the scaling algorithm.
+     * - optimization.method_DB.nstep = number of progressive steps to use in DB algorithm.
+     * - optimization.topology.algorithm = [nni] algorithm to use (for now, only Nearest Neighbor Interchanges (NNI) are implemented). 
+     * - optimization.topology.algorithm_nni.method = [fast,better,phyml]
+     * - optimization.topology.nstep = Estimate numerical parameters every 'n' NNI rounds.
+     * - optimization.topology.numfirst = Tell if numerical parameters must be estimated prior to topology search.
+     * - optimization.topology.tolerance.before = Numerical parameters estimation prior to topology search.
+     * - optimization.topology.tolerance.during = Numerical parameters estimation during topology search.
+     *
+     * @param tl               The TreeLikelihood function to optimize.
+     * @param parameters       The initial list of parameters to optimize.
+     *                         Use tl->getIndependentParameters() in order to estimate all parameters.
+     * @param params           The attribute map where options may be found.
+     * @param suffix           A suffix to be applied to each attribute name.
+     * @param suffixIsOptional Tell if the suffix is absolutely required.
+     * @param verbose          Print some info to the 'message' output stream.
+     * @throw Exception        Any exception that may happen during the optimization process.
+     * @return A pointer toward the final likelihood object.
+     * This pointer may be the same as passed in argument (tl), but in some cases the algorithm
+     * clone this object. We may change this bahavior in the future...
+     * You hence should write something like
+     * @code
+     * tl = PhylogeneticsApplicationTools::optimizeParameters(tl, ...);
+     * @endcode
+     */
+    static TreeLikelihood* optimizeParameters(
+        TreeLikelihood* tl,
+        const ParameterList& parameters,
+        std::map<std::string, std::string>& params,
+        const std::string& suffix = "",
+        bool suffixIsOptional = true,
+        bool verbose = true)
+      throw (Exception);
+    
+    /**
+     * @brief Optimize parameters according to options, with a molecular clock.
+     *
+     * Options used are:
+     * - optimization = Tell if optimization must be performed.
+     * - optimization.message_handler = [std, file_path]
+     *   A path to a specific path (existing will be overwritten) or std for use
+     *   of the standard output.
+     * - optimization.profiler = [std, file_path], idem for the profiling (history
+     *   of all functions evaluations).
+     * - optimization.max_number_f_eval = The maximum number of function evaluation.
+     * - optimization.tolerance = The tolerance parameter (when to stop the optimization).
+     * - optimization.ignore_parameter = A coma-separated list of parameter
+     *   names to ignore in the optimizing process.
+     * - optimization.method = [DB|fullD] Algorithm to use: Derivatives+Brent or full derivatives, with numerical derivatives when required.
+     * - optimization.method.derivatives = [gradient|newton] Use Conjugate Grandient or Newton-Rhaphson algorithm.
+     * - optimization.final = [none|simplex|powell] Perform a downhill simplex or a Powell multidimensions optimization
+     * - optimization.method_DB.nstep = number of progressive steps to use in DB algorithm.
+     *
+     * @param tl               The ClockTreeLikelihood function to optimize.
+     * @param parameters       The initial list of parameters to optimize.
+     *                         Use tl->getIndependentParameters() in order to estimate all parameters.
+     * @param params           The attribute map where options may be found.
+     * @param suffix           A suffix to be applied to each attribute name.
+     * @param suffixIsOptional Tell if the suffix is absolutely required.
+     * @param verbose          Print some info to the 'message' output stream.
+     * @throw Exception        Any exception that may happen during the optimization process.
+     */
+    static void optimizeParameters(
+        DiscreteRatesAcrossSitesClockTreeLikelihood* tl,
+        const ParameterList& parameters,
+        std::map<std::string, std::string>& params,
+        const std::string& suffix = "",
+        bool suffixIsOptional = true,
+        bool verbose = true)
+      throw (Exception);
+    
+    /**
+     * @brief Check if parameter values are close to their definition boundary.
+     *
+     * This allows the detection of potential optimization issues.
+     * A warning message will be output for each problematic parameter.
+     *
+     * @param pl A list of parameters. Parameters without constraint will be ignored.
+     */
+    static void checkEstimatedParameters(const ParameterList& pl);
+
+    /**
+     * @brief Get a SubstitutionCount instance.
+     *
+     * @param alphabet The alphabet to use.
+     * @param model The model to use.
+     * @param params The attribute map where options may be found.
+     * @param suffix Optional suffix for command name.
+     */
+    static SubstitutionCount* getSubstitutionCount(
+        const Alphabet* alphabet,
+        const SubstitutionModel* model,
+        map<string, string>& params,
+        string suffix = "");
+   
+    /**
+     * @brief Write a tree according to options.
+     *
+     * See the Bio++ Program Suite manual for a descriptio of all available options.
+     *
+     * @param tree    The tree to write.
+     * @param params  The attribute map where options may be found.
+     * @param prefix  A prefix to be applied to each attribute name.
+     * @param suffix  A suffix to be applied to each attribute name.
+     * @param suffixIsOptional Tell if the suffix is absolutely required.
+     * @param verbose Print some info to the 'message' output stream.
+     * @param checkOnly If this parameter is set to true, then all options are
+     * checked and error messages sent, but no file is written.
+     * @throw Exception if an error occured.
+     */
+    static void writeTree(
+        const TreeTemplate<Node>& tree,
+        std::map<std::string, std::string>& params,
+        const std::string& prefix = "output.",
+        const std::string& suffix = "",
+        bool suffixIsOptional = true,
+        bool verbose = true,
+        bool checkOnly = false) throw (Exception);
+    
+    /**
+     * @brief Write a tree according to options.
+     *
+     * See the Bio++ Program Suite manual for a descriptio of all available options.
+     *
+     * @param trees   The trees to write.
+     * @param params  The attribute map where options may be found.
+     * @param prefix  A prefix to be applied to each attribute name.
+     * @param suffix  A suffix to be applied to each attribute name.
+     * @param suffixIsOptional Tell if the suffix is absolutely required.
+     * @param verbose Print some info to the 'message' output stream.
+     * @param checkOnly If this parameter is set to true, then all options are
+     * checked and error messages sent, but no file is written.
+     * @throw Exception if an error occured.
+     */
+    static void writeTrees(
+        const std::vector<Tree*>& trees,
+        std::map<std::string, std::string>& params,
+        const std::string& prefix = "output.",
+        const std::string& suffix = "",
+        bool suffixIsOptional = true,
+        bool verbose = true,
+        bool checkOnly = false) throw (Exception);
+
+
+    
+    /**
+     * @brief Output a SubstitutionModel description to a file.
+     *
+     * @param model The model to serialize.
+     * @param out   The stream where to print.
+     */
+    static void printParameters(const SubstitutionModel* model, OutputStream& out);
+
+
+
+    /**
+     * @brief Output a SubstitutionModelSet description to a file.
+     *
+     * @param modelSet The model set to serialize.
+     * @param out      The stream where to print.
+     */
+    static void printParameters(const SubstitutionModelSet* modelSet, OutputStream& out);
+
+
+
+    /**
+     * @brief Output a DiscreteDistribution description to a file.
+     *
+     * @param rDist The rate distribution to serialize.
+     * @param out   The stream where to print.
+     */
+    static void printParameters(const DiscreteDistribution* rDist, OutputStream& out);
+
+  };
+
+} //end of namespace bpp.
+
+#endif  //_PHYLOGENETICSAPPLICATIONTOOLS_H_
+
diff --git a/src/Bpp/Phyl/BipartitionList.cpp b/src/Bpp/Phyl/BipartitionList.cpp
new file mode 100644
index 0000000..c4f06eb
--- /dev/null
+++ b/src/Bpp/Phyl/BipartitionList.cpp
@@ -0,0 +1,827 @@
+//
+// File: BipartitionList.cpp
+// Created by: Nicolas Galtier and Julien Dutheil
+// Created on: Tue Apr 13 15:09 2007
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "BipartitionList.h"
+#include "BipartitionTools.h"
+
+#include "TreeTemplate.h"
+
+#include <Bpp/Exceptions.h>
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Io/FileTools.h>
+#include <Bpp/Numeric/Random/RandomTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/Alphabet.h>
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+#include <climits> // defines CHAR_BIT
+
+using namespace std;
+
+/****************************************************************/
+/* utilitary classes required for sorting elements/bipartitions */
+/****************************************************************/
+
+class StringAndInt
+{
+public:
+  int ind;
+  string str;
+
+public:
+  StringAndInt() : ind(0),
+    str() {}
+};
+
+bool operator<(StringAndInt sai1, StringAndInt sai2)
+{
+  if (sai1.str < sai2.str)
+    return true;
+  return false;
+}
+
+/******************************************************************************/
+
+class IntAndInt
+{
+public:
+  size_t ind;
+  int val;
+};
+
+bool operator<(IntAndInt iai1, IntAndInt iai2)
+{
+  if (iai1.val < iai2.val)
+    return true;
+  return false;
+}
+
+
+/******************************************************************************/
+
+BipartitionList::BipartitionList(const Tree& tr, bool sorted, std::vector<int>* index) :
+  bitBipartitionList_(),
+  elements_(),
+  sorted_(sorted)
+{
+  size_t nbbip;
+
+  elements_ = tr.getLeavesNames();
+
+  if (tr.isRooted())
+    nbbip = tr.getNumberOfNodes() - 2;
+  else
+    nbbip = tr.getNumberOfNodes() - 1;
+
+  if (sorted)
+    std::sort(elements_.begin(), elements_.end());
+
+  size_t lword  = BipartitionTools::LWORD;
+  size_t nbword = (elements_.size() + lword - 1) / lword;
+  size_t nbint  = nbword * lword / (CHAR_BIT * sizeof(int));
+
+  for (size_t i = 0; i < nbbip; i++)
+  {
+    bitBipartitionList_.push_back(new int[nbint]);
+    for (size_t j = 0; j < nbint; j++)
+    {
+      bitBipartitionList_[i][j] = 0;
+    }
+  }
+
+  size_t cpt = 0;
+  vector<string> underlyingNames;
+  const Tree* tree = &tr;
+  const TreeTemplate<Node>* ttree = dynamic_cast<const TreeTemplate<Node>*>(tree);
+  if (ttree)
+  {
+    // Gain some time...
+    buildBitBipartitions(ttree->getRootNode(), bitBipartitionList_, elements_, &cpt, index);
+  }
+  else
+  {
+    TreeTemplate<Node> tmp(tr);
+    buildBitBipartitions(tmp.getRootNode(), bitBipartitionList_, elements_, &cpt, index);
+  }
+}
+
+/******************************************************************************/
+
+BipartitionList::BipartitionList(
+  const std::vector<std::string>& elements,
+  const std::vector<int*>& bitBipL) :
+  bitBipartitionList_(),
+  elements_(elements),
+  sorted_()
+{
+  size_t lword  = BipartitionTools::LWORD;
+  size_t nbword = (elements.size() + lword - 1) / lword;
+  size_t nbint  = nbword * lword / (CHAR_BIT * sizeof(int));
+
+  for (size_t i = 0; i < bitBipL.size(); i++)
+  {
+    bitBipartitionList_.push_back(new int[nbint]);
+    for (size_t j = 0; j < nbint; j++)
+    {
+      bitBipartitionList_[i][j] = bitBipL[i][j];
+    }
+  }
+
+  vector<string> cpelements_ = elements;
+  std::sort(cpelements_.begin(), cpelements_.end());
+  if (cpelements_ == elements)
+    sorted_ = true;
+  else
+    sorted_ = false;
+}
+
+/******************************************************************************/
+
+BipartitionList::BipartitionList(const BipartitionList& bipL) :
+  bitBipartitionList_(),
+  elements_(bipL.elements_),
+  sorted_(bipL.sorted_)
+{
+  size_t lword  = BipartitionTools::LWORD;
+  size_t nbword = (bipL.getNumberOfElements() + lword - 1) / lword;
+  size_t nbint  = nbword * lword / (CHAR_BIT * sizeof(int));
+
+  bitBipartitionList_.resize(bipL.getNumberOfBipartitions());
+  vector<int*> bitBipL = bipL.getBitBipartitionList();
+  for (size_t i = 0; i < bipL.getNumberOfBipartitions(); i++)
+  {
+    bitBipartitionList_[i] = new int[nbint];
+    for (size_t j = 0; j < nbint; j++)
+    {
+      bitBipartitionList_[i][j] = bitBipL[i][j];
+    }
+  }
+}
+
+/******************************************************************************/
+
+BipartitionList& BipartitionList::operator=(const BipartitionList& bipL)
+{
+  size_t lword  = BipartitionTools::LWORD;
+  size_t nbword = (bipL.getNumberOfElements() + lword - 1) / lword;
+  size_t nbint  = nbword * lword / (CHAR_BIT * sizeof(int));
+
+  for (size_t i = 0; i < bitBipartitionList_.size(); i++)
+  {
+    delete[] bitBipartitionList_[i];
+  }
+  bitBipartitionList_.resize(bipL.getNumberOfBipartitions());
+  vector<int*> bitBipL = bipL.getBitBipartitionList();
+  for (size_t i = 0; i < bipL.getNumberOfBipartitions(); i++)
+  {
+    bitBipartitionList_[i] = new int[nbint];
+    for (size_t j = 0; j < nbint; j++)
+    {
+      bitBipartitionList_[i][j] = bitBipL[i][j];
+    }
+  }
+
+  elements_ = bipL.elements_;
+  sorted_   = bipL.sorted_;
+  return *this;
+}
+
+/******************************************************************************/
+
+BipartitionList::~BipartitionList()
+{
+  for (size_t i = 0; i < bitBipartitionList_.size(); i++)
+  {
+    delete[] bitBipartitionList_[i];
+  }
+}
+
+/******************************************************************************/
+
+map<string, bool> BipartitionList::getBipartition(size_t i) const throw (Exception)
+{
+  map<string, bool> bip;
+
+  if (i >= bitBipartitionList_.size())
+    throw Exception("Bipartition index exceeds BipartitionList size");
+
+  for (size_t j = 0; j < elements_.size(); j++)
+  {
+    if (BipartitionTools::testBit(bitBipartitionList_[i], static_cast<int>(j)))
+      bip[elements_[j]] = true;
+    else
+      bip[elements_[j]] = false;
+  }
+  return bip;
+}
+
+/******************************************************************************/
+
+int* BipartitionList::getBitBipartition(size_t i) throw (Exception)
+{
+  if (i >= bitBipartitionList_.size())
+    throw Exception("Bipartition index exceeds BipartitionList size");
+
+  return bitBipartitionList_[i];
+}
+
+/******************************************************************************/
+
+bool BipartitionList::haveSameElementsThan(map<string, bool>& bipart) const
+{
+  vector<string> elements = elements_;
+  vector<string> keys;
+
+  map<string, bool>::iterator it;
+
+  for (it = bipart.begin(); it != bipart.end(); it++)
+  {
+    keys.push_back(it->first);
+  }
+
+  std::sort(elements.begin(), elements.end());
+  std::sort(keys.begin(), keys.end());
+
+  if (elements == keys)
+    return true;
+  return false;
+}
+
+/******************************************************************************/
+
+void BipartitionList::addBipartition(map<string, bool>& bipart, bool checkElements) throw (Exception)
+{
+  if (checkElements && !BipartitionList::haveSameElementsThan(bipart))
+    throw Exception("Distinct bipartition element sets");
+
+  size_t lword  = BipartitionTools::LWORD;
+  size_t nbword = (elements_.size() + lword - 1) / lword;
+  size_t nbint  = nbword * lword / (CHAR_BIT * sizeof(int));
+  bitBipartitionList_.push_back(new int[nbint]);
+  size_t ind    = bitBipartitionList_.size() - 1;
+  for (size_t j = 0; j < nbint; j++)
+  {
+    bitBipartitionList_[ind][j] = 0;
+  }
+
+  for (size_t i = 0; i < elements_.size(); i++)
+  {
+    if (bipart[elements_[i]] == true)
+      BipartitionTools::bit1(bitBipartitionList_[ind], static_cast<int>(i));
+    else
+      BipartitionTools::bit0(bitBipartitionList_[ind], static_cast<int>(i));
+  }
+}
+
+/******************************************************************************/
+
+void BipartitionList::deleteBipartition(size_t i) throw (Exception)
+{
+  if (i >= bitBipartitionList_.size())
+    throw Exception("Bipartition index exceeds BipartitionList size");
+
+  delete[] bitBipartitionList_[i];
+  bitBipartitionList_.erase(bitBipartitionList_.begin() + i);
+}
+
+/******************************************************************************/
+
+bool BipartitionList::containsBipartition(map<string, bool>& bipart, bool checkElements) const throw (Exception)
+{
+  size_t i, j;
+  bool dac, padac;
+
+  if (checkElements && !BipartitionList::haveSameElementsThan(bipart))
+    throw Exception("Distinct bipartition element sets");
+
+  for (i = 0; i < bitBipartitionList_.size(); i++)
+  {
+    dac = padac = false;
+    for (j = 0; j < elements_.size(); j++)
+    {
+      if (BipartitionTools::testBit(bitBipartitionList_[i], static_cast<int>(j)))
+      {
+        if (bipart[elements_[j]])
+          dac = true;
+        else
+          padac = true;
+      }
+      else
+      {
+        if (bipart[elements_[j]])
+          padac = true;
+        else
+          dac = true;
+      }
+      if (dac && padac)
+        break;
+    }
+    if (j == elements_.size())
+      return true;
+  }
+  return false;
+}
+
+/******************************************************************************/
+
+bool BipartitionList::areIdentical(size_t k1, size_t k2) const throw (Exception)
+{
+  bool dac, padac;
+
+  if (k1 >= bitBipartitionList_.size())
+    throw Exception("Bipartition index exceeds BipartitionList size");
+  if (k2 >= bitBipartitionList_.size())
+    throw Exception("Bipartition index exceeds BipartitionList size");
+
+  dac = padac = false;
+  for (size_t j = 0; j < elements_.size(); j++)
+  {
+    if (BipartitionTools::testBit(bitBipartitionList_[k1], static_cast<int>(j)))
+    {
+      if (BipartitionTools::testBit(bitBipartitionList_[k2], static_cast<int>(j)))
+        dac = true;
+      else
+        padac = true;
+    }
+    else
+    {
+      if (BipartitionTools::testBit(bitBipartitionList_[k2], static_cast<int>(j)))
+        padac = true;
+      else
+        dac = true;
+    }
+    if (dac && padac)
+      return false;
+  }
+  return true;
+}
+
+/******************************************************************************/
+
+bool BipartitionList::areCompatible(size_t k1, size_t k2) const throw (Exception)
+{
+  bool uu, uz, zu, zz;
+
+  if (k1 >= bitBipartitionList_.size())
+    throw Exception("Bipartition index exceeds BipartitionList size");
+  if (k2 >= bitBipartitionList_.size())
+    throw Exception("Bipartition index exceeds BipartitionList size");
+
+  uu = uz = zu = zz = false;
+
+  for (size_t j = 0; j < elements_.size(); j++)
+  {
+    if (BipartitionTools::testBit(bitBipartitionList_[k1], static_cast<int>(j)))
+    {
+      if (BipartitionTools::testBit(bitBipartitionList_[k2], static_cast<int>(j)))
+        uu = true;
+      else
+        uz = true;
+    }
+    else
+    {
+      if (BipartitionTools::testBit(bitBipartitionList_[k2], static_cast<int>(j)))
+        zu = true;
+      else
+        zz = true;
+    }
+    if (uu && uz && zu && zz)
+      return false;
+  }
+
+  return true;
+}
+
+/******************************************************************************/
+
+bool BipartitionList::areAllCompatible() const
+{
+  for (size_t i = 0; i < bitBipartitionList_.size(); i++)
+  {
+    for (size_t j = i + 1; j < bitBipartitionList_.size(); j++)
+    {
+      if (!BipartitionList::areCompatible(i, j))
+        return false;
+    }
+  }
+  return true;
+}
+
+/******************************************************************************/
+
+bool BipartitionList::areAllCompatibleWith(map<string, bool>& bipart, bool checkElements) const throw (Exception)
+{
+  if (checkElements && !haveSameElementsThan(bipart))
+    throw Exception("Distinct bipartition element sets");
+  size_t nbBip = bitBipartitionList_.size();
+  const_cast<BipartitionList*>(this)->addBipartition(bipart, false);
+
+  for (size_t i = 0; i < nbBip; i++)
+  {
+    if (!areCompatible(i, nbBip))
+    {
+      const_cast<BipartitionList*>(this)->deleteBipartition(nbBip);
+      return false;
+    }
+  }
+  const_cast<BipartitionList*>(this)->deleteBipartition(nbBip);
+  return true;
+}
+
+/******************************************************************************/
+
+void BipartitionList::sortElements()
+{
+  vector<StringAndInt> relements_;
+  StringAndInt sai;
+  size_t nbbip;
+
+  for (size_t i = 0; i < elements_.size(); i++)
+  {
+    sai.str = elements_[i];
+    sai.ind = static_cast<int>(i);
+    relements_.push_back(sai);
+  }
+
+  std::sort(relements_.begin(), relements_.end());
+
+  for (size_t i = 0; i < elements_.size(); i++)
+  {
+    elements_[i] = relements_[i].str;
+  }
+
+  nbbip = bitBipartitionList_.size();
+  bitBipartitionList_.resize(2 * nbbip);
+  size_t lword  = BipartitionTools::LWORD;
+  size_t nbword = (elements_.size() + lword - 1) / lword;
+  size_t nbint  = nbword * lword / (CHAR_BIT * sizeof(int));
+
+  for (size_t j = nbbip; j < 2 * nbbip; j++)
+  {
+    bitBipartitionList_[j] = new int[nbint];
+    for (size_t k = 0; k < nbint; k++)
+    {
+      bitBipartitionList_[j][k] = 0;
+    }
+    for (size_t i = 0; i < elements_.size(); i++)
+    {
+      if (BipartitionTools::testBit(bitBipartitionList_[j - nbbip], relements_[i].ind))
+        BipartitionTools::bit1(bitBipartitionList_[j], static_cast<int>(i));
+      else
+        BipartitionTools::bit0(bitBipartitionList_[j], static_cast<int>(i));
+    }
+  }
+
+  for (size_t j = 0; j < nbbip; j++)
+  {
+    delete[] bitBipartitionList_[j];
+  }
+
+  bitBipartitionList_.erase(bitBipartitionList_.begin(), bitBipartitionList_.begin() + nbbip);
+  sorted_ = true;
+}
+
+/******************************************************************************/
+
+size_t BipartitionList::getPartitionSize(size_t k) const throw (Exception)
+{
+  size_t size = 0;
+  if (k >= bitBipartitionList_.size())
+    throw Exception("Bipartition index exceeds BipartitionList size");
+
+  for (size_t i = 0; i < elements_.size(); i++)
+  {
+    if (BipartitionTools::testBit(bitBipartitionList_[k], static_cast<int>(i)))
+      size++;
+  }
+
+  if (size <= elements_.size() / 2)
+    return size;
+  else
+    return elements_.size() - size;
+}
+
+/******************************************************************************/
+
+void BipartitionList::removeTrivialBipartitions()
+{
+  size_t size = bitBipartitionList_.size();
+  for (size_t i = size; i > 0; i--)
+  {
+    if (BipartitionList::getPartitionSize(i - 1) < 2)
+      BipartitionList::deleteBipartition(i - 1);
+  }
+}
+
+/******************************************************************************/
+
+void BipartitionList::addTrivialBipartitions(bool checkExisting)
+{
+  map<string, bool> bip;
+
+  for (size_t i = 0; i < elements_.size(); i++)
+  {
+    bip[elements_[i]] = false;
+  }
+  for (size_t i = 0; i < elements_.size(); i++)
+  {
+    bip[elements_[i]] = true;
+    if (checkExisting && BipartitionList::containsBipartition(bip, false))
+      continue;
+    BipartitionList::addBipartition(bip, false);
+    bip[elements_[i]] = false;
+  }
+}
+
+/******************************************************************************/
+
+void BipartitionList::sortByPartitionSize()
+{
+  vector<int*> sortedBitBipL;
+  vector<IntAndInt> iaiVec;
+  IntAndInt iai;
+
+  for (size_t i = 0; i < bitBipartitionList_.size(); i++)
+  {
+    iai.ind = i;
+    iai.val = static_cast<int>(BipartitionList::getPartitionSize(i));
+    iaiVec.push_back(iai);
+  }
+
+  std::sort(iaiVec.begin(), iaiVec.end());
+
+  for (size_t i = 0; i < bitBipartitionList_.size(); i++)
+  {
+    sortedBitBipL.push_back(bitBipartitionList_[iaiVec[i].ind]);
+  }
+
+  bitBipartitionList_ = sortedBitBipL;
+}
+
+/******************************************************************************/
+
+void BipartitionList::flip(size_t k) throw (Exception)
+{
+  if (k >= bitBipartitionList_.size())
+    throw Exception("Bipartition index exceeds BipartitionList size");
+  size_t lword = BipartitionTools::LWORD;
+  size_t nbword = (elements_.size() + lword - 1) / lword;
+  size_t nbint = nbword * lword / (CHAR_BIT * sizeof(int));
+  int* flipbip = new int[nbint];
+  for (size_t i = 0; i < nbint; i++)
+  {
+    flipbip[i] = 0;
+  }
+  BipartitionTools::bitNot(flipbip, bitBipartitionList_[k], nbint);
+  delete[] bitBipartitionList_[k];
+  bitBipartitionList_[k] = flipbip;
+}
+
+/******************************************************************************/
+
+void BipartitionList::removeRedundantBipartitions()
+{
+  bool deletion = true;
+
+  while (deletion)
+  {
+    deletion = false;
+    for (size_t i = 0; i < bitBipartitionList_.size(); i++)
+    {
+      for (size_t j = i + 1; j < bitBipartitionList_.size(); j++)
+      {
+        if (BipartitionList::areIdentical(i, j))
+        {
+          BipartitionList::deleteBipartition(j);
+          deletion = true;
+          break;
+        }
+      }
+      if (deletion)
+        break;
+    }
+  }
+}
+
+/******************************************************************************/
+
+TreeTemplate<Node>* BipartitionList::toTree() const throw (Exception)
+{
+  BipartitionList* sortedBipL;
+  vector<int*> sortedBitBipL;
+  int* bip;
+  vector<Node*> vecNd, sonNd;
+  vector<bool> alive;
+  size_t lword, nbword, nbint, ii;
+
+  /* check, copy and prepare bipartition list */
+
+  if (!BipartitionList::areAllCompatible())
+    throw Exception("Trying to build a tree from incompatible bipartitions");
+
+  sortedBipL = dynamic_cast<BipartitionList*>(clone());
+  for (size_t i = 0; i < sortedBipL->getNumberOfBipartitions(); i++)
+  {
+    if (sortedBipL->getPartitionSize(i) > sortedBipL->getNumberOfElements() / 2)
+      sortedBipL->flip(i);
+  }
+  sortedBipL->sortByPartitionSize();
+  sortedBipL->removeRedundantBipartitions();
+  sortedBitBipL = sortedBipL->getBitBipartitionList();
+
+  for (size_t i = 0; i < sortedBipL->getNumberOfBipartitions(); i++)
+  {
+    alive.push_back(true);
+  }
+  vecNd.resize(sortedBipL->getNumberOfBipartitions() + 1);
+  lword  = BipartitionTools::LWORD;
+  nbword = (elements_.size() + lword - 1) / lword;
+  nbint  = nbword * lword / (CHAR_BIT * sizeof(int));
+  bip    = new int[1]; bip[0] = 0;
+
+  /* main loop: create one node per bipartition */
+  for (size_t i = 0; i < sortedBipL->getNumberOfBipartitions(); i++)
+  {
+    if (sortedBipL->getPartitionSize(i) == 1)
+    { // terminal
+      for (size_t j = 0; j < sortedBipL->getNumberOfElements(); j++)
+      {
+        if (BipartitionTools::testBit(sortedBitBipL[i], static_cast<int>(j)))
+        {
+          vecNd[i] = new Node(elements_[j]);
+          break;
+        }
+      }
+    }
+    else
+    { // internal
+      sonNd.clear();
+      for (size_t j = 0; j < i; j++)
+      {
+        if (alive[j])
+        {
+          for (ii = 0; ii < nbint; ii++)
+          {
+            BipartitionTools::bitOr(bip, sortedBitBipL[j] + ii, sortedBitBipL[i] + ii, 1);
+            if (bip[0] != sortedBitBipL[i][ii])
+              break;
+          }
+          if (ii == nbint)
+          {
+            sonNd.push_back(vecNd[j]);
+            alive[j] = false;
+          }
+        }
+      }
+      vecNd[i] = new Node();
+      for (size_t k = 0; k < sonNd.size(); k++)
+      {
+        vecNd[i]->addSon(sonNd[k]);
+      }
+    }
+  }
+
+  /* create last node, which joins alive bipartitions = fatherless nodes */
+  Node* rootNd = new Node();
+  for (size_t i = 0; i < sortedBipL->getNumberOfBipartitions(); i++)
+  {
+    if (alive[i])
+      rootNd->addSon(vecNd[i]);
+  }
+
+  /* construct tree and return */
+  TreeTemplate<Node>* tr = new TreeTemplate<Node>(rootNd);
+  tr->resetNodesId();
+  delete sortedBipL;
+  return tr;
+}
+
+/******************************************************************************/
+
+vector<string> BipartitionList::buildBitBipartitions(const Node* nd, vector<int*>& bitbip, const vector<string>& elements, size_t* cpt, vector<int>* index) const
+{
+  vector<string> underelements_, retelements_;
+
+  if (nd->getNumberOfSons() == 0)
+    underelements_.push_back(nd->getName());
+
+  for (size_t i = 0; i < nd->getNumberOfSons(); i++)
+  {
+    retelements_ = BipartitionList::buildBitBipartitions(nd->getSon(i), bitbip, elements, cpt, index);
+    for (size_t j = 0; j < retelements_.size(); j++)
+    {
+      underelements_.push_back(retelements_[j]);
+    }
+  }
+
+  if (!nd->hasFather())
+    return underelements_;  // root node
+
+  if (!nd->getFather()->hasFather())
+  {
+    size_t nbrootson = nd->getFather()->getNumberOfSons();
+    if (nbrootson == 2 && nd == nd->getFather()->getSon(1))
+      return underelements_;  // son 2 of root node when root node has 2 sons
+  }
+
+  bool ones;
+  if (underelements_.size() <= elements.size() / 2)
+    ones = true;
+  else
+    ones = false;
+
+  for (size_t i = 0; i < elements.size(); i++)
+  {
+    if (ones)
+      BipartitionTools::bit0(bitbip[*cpt], static_cast<int>(i));
+    else
+      BipartitionTools::bit1(bitbip[*cpt], static_cast<int>(i));
+  }
+
+  for (size_t i = 0; i < underelements_.size(); i++)
+  {
+    size_t taxa_ind = 0;
+    while (underelements_[i] != elements[taxa_ind])
+      taxa_ind++;
+    if (ones)
+      BipartitionTools::bit1(bitbip[*cpt], static_cast<int>(taxa_ind));
+    else
+      BipartitionTools::bit0(bitbip[*cpt], static_cast<int>(taxa_ind));
+  }
+
+  (*cpt)++;
+
+  if (index)
+    index->push_back(nd->getId());
+
+  return underelements_;
+}
+
+/******************************************************************************/
+
+RowMatrix<int> BipartitionList::toMatrix() const
+{
+  vector< map<string, bool> > bipl;
+  for (size_t i = 0; i < getNumberOfBipartitions(); i++)
+  {
+    bipl.push_back(getBipartition(i));
+  }
+
+  vector<string> el = getElementNames();
+
+  RowMatrix<int> mat(el.size(), getNumberOfBipartitions());
+
+  for (size_t j = 0; j < el.size(); j++)
+  {
+    for (size_t i = 0; i < getNumberOfBipartitions(); i++)
+    {
+      mat(j, i) = bipl[i][el[j]];
+    }
+  }
+  return mat;
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/BipartitionList.h b/src/Bpp/Phyl/BipartitionList.h
new file mode 100644
index 0000000..db1b24c
--- /dev/null
+++ b/src/Bpp/Phyl/BipartitionList.h
@@ -0,0 +1,234 @@
+//
+// File: BipartitionList.h
+// Created by: Nicolas Galtier and Julien Dutheil
+// Created on: Tue Apr 13 15:09 2007
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use,
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info".
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability.
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or
+data to be ensured and,  more generally, to use and operate it in the
+same conditions as regards security.
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _BIPARTITIONLIST_H_
+#define _BIPARTITIONLIST_H_
+
+#include "Tree.h"
+
+#include <Bpp/Utils/MapTools.h>
+#include <Bpp/Numeric/Matrix/Matrix.h>
+
+// From the STL:
+#include <map>
+#include <algorithm>
+
+namespace bpp
+{
+
+class Node;
+template<class N> class TreeTemplate;
+
+/**
+ * @brief This class deals with the bipartitions defined by trees
+ *
+ * Any branch of a tree defines a bipartition, i.e. two non-overlapping subsets of leaves
+ * whose union is the whole set of leaves. A tree topology can therefore be represented by
+ * the list of bipartitions its branches define - the so-called matrix representation.
+ * Coding trees this way is useful for comparing topologies, calculating topological distances,
+ * producing consensus trees or super-trees, calculating bootstrap support.
+ *
+ * A BipartitionList includes a set of element names (typically leaf names) and a vector of arrays of bits
+ * (int*, not bitsets, are used to allow for dynamic memory allocation). Each array of bit codes for one bipartition.
+ * Each bit in an array of bit corresponds to one element, so the order of element names matter.
+ * Bits set to zero versus bits set to one define the two partitions of elements.
+ * A BipartitionList is called sorted if its elements (leaf names) are in alphabetic order (recommended).
+ *
+ * BipartitionList objects are typically created from a tree, in which case elements are leaf names.
+ * Note that BipartitionList is an unrooted object: a rooted or unrooted versions of the same tree will
+ * yield the same BipartitionList in which the root location is ignored. Bipartitions can be accessed as
+ * arrays of bits (e.g. getBitBipartition), or as map<string, bool>, in which keys are leaf names and
+ * true/false values define the two partitions (e.g. getBipartition, addBipartition).
+ *
+ * @see Tree
+ * @see BipartitionTools
+ * @see TreeTools
+ */
+class BipartitionList:
+  public virtual Clonable
+{
+  private:
+
+    std::vector<int*> bitBipartitionList_;
+    std::vector<std::string> elements_;
+    bool sorted_;
+
+  public:
+
+    /**
+     * @brief The main contructor
+     *
+     * @param tr The tree to be coded as bipartitions
+     * @param sorted Tells whether leave names should be alphabetically sorted (recommended)
+     * @param index An output optional vector to keep trace of the nodes id underlying each bipartition.
+     */
+    BipartitionList(const Tree& tr, bool sorted = true, std::vector<int>* index = 0);
+
+    /**
+     * @brief An alternative constructor in which elements and bipartitions are passed directly
+     *
+     * @param elements Leaf names
+     * @param bipl The list of bit-encoded bipartitions
+     */
+    BipartitionList(const std::vector<std::string>& elements, const std::vector<int*>& bipl);
+
+    /**
+     * @brief Copy-constructor
+     */
+    BipartitionList(const BipartitionList& bipl);
+
+    /**
+     * @brief Assignment operator
+     */
+    BipartitionList& operator=(const BipartitionList& bipl);
+
+    virtual ~BipartitionList();
+
+#ifndef NO_VIRTUAL_COV
+    BipartitionList*
+#else
+    Clonable*
+#endif
+    clone() const { return new BipartitionList(*this); }
+
+  public:
+
+    size_t getNumberOfElements() const { return elements_.size(); }
+
+    const std::vector<std::string>& getElementNames() const { return elements_; }
+
+    size_t getNumberOfBipartitions() const { return bitBipartitionList_.size(); }
+
+    const std::vector<int*> & getBitBipartitionList() const { return bitBipartitionList_; }
+
+    std::map<std::string, bool> getBipartition(size_t i) const throw (Exception);
+
+    int* getBitBipartition(size_t i) throw (Exception);
+
+    bool haveSameElementsThan(std::map<std::string, bool>& bipart) const;
+
+    void addBipartition(std::map<std::string, bool>& bipart, bool checkElements = 1) throw(Exception);
+
+    void deleteBipartition(size_t i) throw(Exception);
+
+    bool isSorted() const { return sorted_; }
+
+    void sortElements();
+
+    bool containsBipartition(std::map<std::string, bool>& bipart, bool checkElements = 1) const throw(Exception);
+
+    bool areIdentical(size_t k1, size_t k2) const throw(Exception);
+
+    void removeRedundantBipartitions();
+
+    /**
+     * @brief Tells whether 2 bipartitions from the list are compatible
+     *
+     * Let A=A1|A2 and B=B1|B2 be two bipartitions (such that A1 U A2 = B1 U B2 = set of leaves)
+     * A and B are said compatible if (A1 contains B1 and B2 contains A2) or (A1 contains B2
+     * and B1 contains A2) or (B1 contains A1 and A2 contains B2) or (B2 contains A1 and A2
+     * contains B1). Only compatible bipartitions can belong to the same tree.
+     */
+    bool areCompatible(size_t k1, size_t k2) const throw(Exception);
+
+    /**
+     * @brief Tells whether all bipartitions in the list are compatible with each other
+     */
+    bool areAllCompatible() const;
+
+    /**
+     * @brief Tells whether all bipartitions in the list are compatible with a given bipartition
+     *
+     * @param bipart A map representing a bipartition.
+     * @param checkElements Check the correspondance of element sets or not.
+     */
+    bool areAllCompatibleWith(std::map<std::string, bool>& bipart, bool checkElements = true) const throw (Exception);
+
+    /**
+     * @brief Removes bipartitions corresponding to external branches (1 vs n-1)
+     */
+    void removeTrivialBipartitions();
+
+    /**
+     * @brief Adds bipartitions corresponding to external branches if missing
+     */
+    void addTrivialBipartitions(bool checkExisting);
+
+
+    /**
+     * @brief Replaces ones by zeros and zeros by ones in the ith bipartition
+     */
+    void flip(size_t i) throw(Exception);
+
+    /**
+     * @brief Returns the size of the smallest of the two partitions (e.g. 1 for external branches)
+     */
+    size_t getPartitionSize(size_t i) const throw(Exception);
+
+    /**
+     * @brief Sort bipartitions by partition size
+     */
+    void sortByPartitionSize();
+
+    /**
+     * @brief Translate into a tree
+     */
+    TreeTemplate<Node>* toTree() const throw(Exception);
+
+    /**
+     * @brief Create a matrix representation of the bifurcations.
+     *
+     * Each row corresponds to an element, each column to a bipartition.
+     *
+     * NB: using RowMatrix<bool> leads to unexplained compilation error...
+     *
+     * @return A boolean matrix.
+     */
+    RowMatrix<int> toMatrix() const;
+
+  private:
+
+    std::vector<std::string> buildBitBipartitions(const Node* nd, std::vector<int*>& bitbip, const std::vector<std::string> & elements, size_t* cpt, std::vector<int>* index) const;
+
+};
+
+} //end of namespace bpp.
+
+#endif //_BIPARTITIONLIST_H_
+
diff --git a/src/Bpp/Phyl/BipartitionTools.cpp b/src/Bpp/Phyl/BipartitionTools.cpp
new file mode 100644
index 0000000..a387082
--- /dev/null
+++ b/src/Bpp/Phyl/BipartitionTools.cpp
@@ -0,0 +1,329 @@
+//
+// File: BipartitionTools.cpp
+// Created by: Nicolas Galtier & Julien Dutheil
+// Created on: Tue Apr 13 15:09 2007
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "BipartitionList.h"
+#include "BipartitionTools.h"
+#include "TreeTemplate.h"
+
+#include <Bpp/Exceptions.h>
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Io/FileTools.h>
+
+// From SeqLib
+#include <Bpp/Seq/Alphabet/DNA.h>
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+
+using namespace bpp;
+
+// From STL
+#include <iostream>
+#include <algorithm>
+#include <limits.h> // defines CHAR_BIT
+
+using namespace std;
+
+/******************************************************************************/
+
+size_t BipartitionTools::LWORD = CHAR_BIT * sizeof(int);
+
+/******************************************************************************/
+
+/* functions dealing with int* seen as arrays of bits */
+/* (provided by Manolo Gouy) */
+
+void BipartitionTools::bit1(int* plist, int num)
+{
+  // num--;
+  plist += (num / LWORD);
+  *plist |= (1 << (num % LWORD));
+}
+
+/******************************************************************************/
+
+void BipartitionTools::bit0(int* plist, int num)
+{
+  // num--;
+  plist += (num / LWORD);
+  *plist &=  ~(1 << (num % LWORD));
+}
+
+/******************************************************************************/
+
+void BipartitionTools::bitAnd(int* listet, int* list1, int* list2, size_t len)
+{
+  for (size_t i = 0; i < len; i++)
+  {
+    listet[i] = list1[i] & list2[i];
+  }
+}
+
+/******************************************************************************/
+
+void BipartitionTools::bitOr(int* listou, int* list1, int* list2, size_t len)
+{
+  for (size_t i = 0; i < len; i++)
+  {
+    listou[i] = list1[i] | list2[i];
+  }
+}
+
+/******************************************************************************/
+
+void BipartitionTools::bitNot(int* listnon, int* list, size_t len)
+{
+  for (size_t i = 0; i < len; i++)
+  {
+    listnon[i] = ~list[i];
+  }
+}
+
+/******************************************************************************/
+bool BipartitionTools::testBit(int* plist, int num)
+{
+  // num--;
+  plist += (num / LWORD);
+  return (*plist) & (1 << (num % LWORD));
+}
+
+/******************************************************************************/
+
+BipartitionList* BipartitionTools::buildBipartitionPair(
+  const BipartitionList& bipartL1, size_t i1,
+  const BipartitionList& bipartL2, size_t i2,
+  bool checkElements) throw (Exception)
+{
+  vector<int*> bitBipL1, bitBipL2, twoBitBipL;
+  vector<string> elements;
+
+  if (i1 >= bipartL1.getNumberOfBipartitions())
+    throw Exception("Bipartition index exceeds BipartitionList size");
+  if (i2 >= bipartL2.getNumberOfBipartitions())
+    throw Exception("Bipartition index exceeds BipartitionList size");
+
+  if (checkElements && !VectorTools::haveSameElements(bipartL1.getElementNames(), bipartL2.getElementNames()))
+    throw Exception("Distinct bipartition element sets");
+
+  /* get sorted bit bipartition lists */
+  /* (if input is sorted: easy; otherwise: first copy, then sort) */
+
+  if (bipartL1.isSorted())
+  {
+    elements = bipartL1.getElementNames();
+    bitBipL1 = bipartL1.getBitBipartitionList();
+  }
+  else
+  {
+    BipartitionList provBipartL(bipartL1.getElementNames(), bipartL1.getBitBipartitionList());
+    provBipartL.sortElements();
+    elements = provBipartL.getElementNames();
+    bitBipL1 = provBipartL.getBitBipartitionList();
+  }
+
+  if (bipartL2.isSorted())
+  {
+    bitBipL2 = bipartL2.getBitBipartitionList();
+  }
+  else
+  {
+    BipartitionList provBipartL(bipartL2.getElementNames(), bipartL2.getBitBipartitionList());
+    provBipartL.sortElements();
+    bitBipL2 = provBipartL.getBitBipartitionList();
+  }
+
+  /* create a new BipartitionList with just the two focal bipartitions */
+
+  twoBitBipL.push_back(bitBipL1[i1]);
+  twoBitBipL.push_back(bitBipL2[i2]);
+  BipartitionList* twoBipL = new BipartitionList(elements, twoBitBipL);
+  return twoBipL;
+}
+
+/******************************************************************************/
+
+bool BipartitionTools::areIdentical(
+  const BipartitionList& bipartL1, size_t i1,
+  const BipartitionList& bipartL2, size_t i2,
+  bool checkElements)
+{
+  BipartitionList* twoBipL = buildBipartitionPair(bipartL1, i1, bipartL2, i2, checkElements);
+  bool test = twoBipL->areIdentical(0, 1);
+  delete twoBipL;
+  return test;
+}
+
+/******************************************************************************/
+
+bool BipartitionTools::areCompatible(
+  const BipartitionList& bipartL1, size_t i1,
+  const BipartitionList& bipartL2, size_t i2,
+  bool checkElements)
+{
+  BipartitionList* twoBipL = buildBipartitionPair(bipartL1, i1, bipartL2, i2, checkElements);
+  bool test = twoBipL->areCompatible(0, 1);
+  delete twoBipL;
+  return test;
+}
+
+/******************************************************************************/
+
+BipartitionList* BipartitionTools::mergeBipartitionLists(
+  const vector<BipartitionList*>& vecBipartL,
+  bool checkElements) throw (Exception)
+{
+  vector<string> elements;
+  vector<int*> mergedBitBipL;
+  int* provBitBip;
+  BipartitionList* mergedBipL;
+
+  if (vecBipartL.size() == 0)
+    throw Exception("Empty vector passed");
+
+  if (checkElements)
+  {
+    for (size_t i = 1; i < vecBipartL.size(); i++)
+    {
+      if (!VectorTools::haveSameElements(vecBipartL[0]->getElementNames(), vecBipartL[0]->getElementNames()))
+        throw Exception("BipartitionTools::mergeBipartitionLists. Distinct bipartition element sets");
+    }
+  }
+
+  size_t lword  = BipartitionTools::LWORD;
+  size_t nbword = (vecBipartL[0]->getElementNames().size() + lword - 1) / lword;
+  size_t nbint  = nbword * lword / (CHAR_BIT * sizeof(int));
+
+  elements = vecBipartL[0]->getElementNames();
+  if (!vecBipartL[0]->isSorted())
+    std::sort(elements.begin(), elements.end());
+
+  for (size_t i = 0; i < vecBipartL.size(); i++)
+  {
+    vector<int*> bitBipL;
+    if (vecBipartL[i]->isSorted())
+    {
+      bitBipL = vecBipartL[i]->getBitBipartitionList();
+    }
+    else
+    {
+      // We don't need the extra recopy here, do we?
+      // BipartitionList provBipartL(BipartitionList(vecBipartL[i]->getElementNames(), vecBipartL[i]->getBitBipartitionList()));
+      BipartitionList provBipartL(vecBipartL[i]->getElementNames(), vecBipartL[i]->getBitBipartitionList());
+      provBipartL.sortElements();
+      bitBipL = provBipartL.getBitBipartitionList();
+    }
+    for (size_t j = 0; j < bitBipL.size(); j++)
+    {
+      provBitBip = new int[nbint];
+      for (size_t k = 0; k < nbint; k++)
+      {
+        provBitBip[k] = bitBipL[j][k];
+      }
+      mergedBitBipL.push_back(provBitBip);
+    }
+  }
+
+  mergedBipL = new BipartitionList(elements, mergedBitBipL);
+  return mergedBipL;
+}
+
+/******************************************************************************/
+
+VectorSiteContainer* BipartitionTools::MRPEncode(
+  const vector<BipartitionList*>& vecBipartL) throw (Exception)
+{
+  vector<string> all_elements;
+  map<string, bool> bip;
+  vector<string> bip_elements;
+  const DNA* alpha = &AlphabetTools::DNA_ALPHABET;
+  vector<string> sequences;
+
+  if (vecBipartL.size() == 0)
+    throw Exception("Empty vector passed");
+
+  vector< vector<string> > vecElementLists;
+  for (size_t i = 0; i < vecBipartL.size(); i++)
+  {
+    vecElementLists.push_back(vecBipartL[i]->getElementNames());
+  }
+
+  all_elements = VectorTools::vectorUnion(vecElementLists);
+
+  sequences.resize(all_elements.size());
+
+  for (size_t i = 0; i < vecBipartL.size(); i++)
+  {
+    for (size_t j = 0; j < vecBipartL[i]->getNumberOfBipartitions(); j++)
+    {
+      bip = vecBipartL[i]->getBipartition(j);
+      bip_elements = MapTools::getKeys(bip);
+
+      for (size_t k = 0; k < all_elements.size(); k++)
+      {
+        if (VectorTools::contains(bip_elements, all_elements[k]))
+        {
+          if (bip[all_elements[k]])
+            sequences[k].push_back('C');
+          else
+            sequences[k].push_back('A');
+        }
+        else
+          sequences[k].push_back('N');
+      }
+    }
+  }
+
+  vector<const Sequence*> vec_sequences;
+  for (size_t i = 0; i < all_elements.size(); i++)
+  {
+    const Sequence* seq = new BasicSequence(all_elements[i], sequences[i], alpha);
+    vec_sequences.push_back(seq);
+  }
+
+  VectorSequenceContainer vec_seq_cont(vec_sequences, alpha);
+  for (size_t i = 0; i < all_elements.size(); i++)
+  {
+    delete vec_sequences[i];
+  }
+
+  VectorSiteContainer* vec_site_cont = new VectorSiteContainer(vec_seq_cont);
+
+  return vec_site_cont;
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/BipartitionTools.h b/src/Bpp/Phyl/BipartitionTools.h
new file mode 100644
index 0000000..f9e0dba
--- /dev/null
+++ b/src/Bpp/Phyl/BipartitionTools.h
@@ -0,0 +1,171 @@
+//
+// File: BipartitionTools.h
+// Created by: Nicolas Galtier & Julien Dutheil
+// Created on: Tue Apr 13 15:09 2007
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _BIPARTITIONTOOLS_H_
+#define _BIPARTITIONTOOLS_H_
+
+#include "BipartitionList.h"
+
+// From bpp-seq:
+#include <Bpp/Seq/Container/VectorSiteContainer.h>
+
+namespace bpp
+{
+/**
+ * @brief This class provides tools related to the BipartitionList class
+ *
+ * BipartitionTools includes functions dealing with dynamic arrays of bits
+ * and tools for dealing with bipartitions from distinct lists.
+ *
+ * @see Tree
+ * @see BipartitionList
+ * @see TreeTools
+ */
+class BipartitionTools
+{
+public:
+  /**
+   * @brief
+   *
+   * Unit length (in bits) of arrays of bits. Must be a multiple of CHAR_BIT*sizeof(int).
+   * Default value is 64.
+   */
+  static size_t LWORD;
+
+public:
+  BipartitionTools() {}
+  virtual ~BipartitionTools() {}
+
+public:
+  /**
+   * @brief Sets bit number num of bit array list to one
+   *
+   * Note that no control of memory allocation is made
+   */
+  static void bit1(int* list, int num);
+
+  /**
+   * @brief Sets bit number num of bit array plist to zero
+   *
+   * Note that no control of memory allocation is made
+   */
+  static void bit0(int* list, int num);
+
+  /**
+   * @brief bit-wise logical AND between two arrays of bits
+   *
+   * (1 AND 1 = 1; 1 AND 0 = 0 AND 1 = 0 AND 0 = 0)
+   *
+   * Note that no control of memory allocation is made
+   *
+   * param list1 first array of bit
+   * param list2 second array of bit
+   * param listet resulting array of bit
+   * param len number of int over which the operation is performed
+   */
+  static void bitAnd(int* listet, int* list1, int* list2, size_t len);
+
+  /**
+   * @brief bit-wise logical OR between two arrays of bits
+   *
+   * (1 OR 1 = 1 OR 0 = 0 OR 1 = 1; 0 OR 0 = 0)
+   *
+   * Note that no control of memory allocation is made
+   *
+   * param list1 first array of bit
+   * param list2 second array of bit
+   * param listou resulting array of bit
+   * param len number of int over which the operation is performed
+   */
+  static void bitOr(int* listou, int* list1, int* list2, size_t len);
+
+  /**
+   * @brief bit-wise logical NOT
+   *
+   * (NOT 1 = 0; NOT 0 = 1)
+   *
+   * Note that no control of memory allocation is made
+   *
+   * param list input array of bit
+   * param listnot resulting array of bit
+   * param len number of int over which the operation is performed
+   */
+  static void bitNot(int* listnon, int* list, size_t len);
+
+  /**
+   * @brief Tells whether bit number num in bit array list is one
+   */
+  static bool testBit(int* list, int num);
+
+  /**
+   * @brief Makes one BipartitionList out of several
+   *
+   * The input BipartitionList objects must share the same set of elements. This will be checked or not
+   * depending on checkElements
+   */
+  static BipartitionList* mergeBipartitionLists(const std::vector<BipartitionList*>& vecBipartL, bool checkElements = true) throw (Exception);
+
+  /**
+   * @brief Construct a BipartitionList containing two bipartitions taken from distinct input lists
+   */
+  static BipartitionList* buildBipartitionPair(const BipartitionList& bipartL1, size_t i1, const BipartitionList& bipartL2, size_t i2, bool checkElements = true) throw (Exception);
+
+  /**
+   * @brief Tells whether two bipartitions from distinct lists are identical
+   */
+  static bool areIdentical(const BipartitionList& bipart1, size_t i1, const BipartitionList& bipart2, size_t i2, bool checkElements = true);
+
+  /**
+   * @brief Tells whether two bipartitions from distinct lists are compatible
+   */
+  static bool areCompatible(const BipartitionList& bipart1, size_t i1, const BipartitionList& bipart2, size_t i2, bool checkElements = true);
+
+  /**
+   * @brief Create a sequence data set corresponding to the Matrix Representation of the input BipartitionList objects
+   *
+   * The input BipartitionList objects can have distinct sets of elements - missing data will be represented as 'N'.
+   * The output alignment (DNA sequences including only A, C and N)) is ready for maximum parsimony analysis
+   * according to the MRP supertree method.
+   */
+  static VectorSiteContainer* MRPEncode(const std::vector<BipartitionList*>& vecBipartL) throw (Exception);
+};
+} // end of namespace bpp.
+
+#endif // _BIPARTITIONTOOLS_H_
+
diff --git a/src/Bpp/Phyl/Distance/AbstractAgglomerativeDistanceMethod.cpp b/src/Bpp/Phyl/Distance/AbstractAgglomerativeDistanceMethod.cpp
new file mode 100755
index 0000000..8c04ca9
--- /dev/null
+++ b/src/Bpp/Phyl/Distance/AbstractAgglomerativeDistanceMethod.cpp
@@ -0,0 +1,121 @@
+//
+// File: AbstractAgglomerativeDistanceMethod.cpp
+// Created by: Julien Dutheil
+//             Vincent Ranwez
+// Created on: Wed jun 22 10:00 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "AbstractAgglomerativeDistanceMethod.h"
+#include "../Node.h"
+
+#include <Bpp/App/ApplicationTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+
+using namespace std;
+
+void AbstractAgglomerativeDistanceMethod::setDistanceMatrix(const DistanceMatrix& matrix)
+{
+  matrix_ = matrix;
+  currentNodes_.clear();
+  if (tree_) delete tree_;
+}
+    
+void AbstractAgglomerativeDistanceMethod::computeTree() throw (Exception)
+{
+  // Initialization:
+  for (size_t i = 0; i < matrix_.size(); ++i)
+  {
+    currentNodes_[i] = getLeafNode(static_cast<int>(i), matrix_.getName(i));
+  }
+  int idNextNode = static_cast<int>(matrix_.size());
+  vector<double> newDist(matrix_.size());
+  
+  // Build tree:
+  while (currentNodes_.size() > (rootTree_ ? 2 : 3))
+  {
+    if (verbose_)
+      ApplicationTools::displayGauge(matrix_.size() - currentNodes_.size(), matrix_.size() - (rootTree_ ? 2 : 3) - 1);
+    vector<size_t> bestPair = getBestPair();
+    vector<double> distances = computeBranchLengthsForPair(bestPair);
+    Node* best1 = currentNodes_[bestPair[0]];
+    Node* best2 = currentNodes_[bestPair[1]];
+    // Distances may be used by getParentNodes (PGMA for instance).
+    best1->setDistanceToFather(distances[0]);
+    best2->setDistanceToFather(distances[1]);
+    Node* parent = getParentNode(idNextNode, best1, best2);
+    idNextNode++;
+    for (map<size_t, Node *>::iterator i = currentNodes_.begin(); i != currentNodes_.end(); i++)
+    {
+      size_t id = i->first;
+      if (id != bestPair[0] && id != bestPair[1])
+      {
+        assert (id < newDist.size()); //DEBUG
+        newDist[id] = computeDistancesFromPair(bestPair, distances, id);
+      }
+      else
+      {
+        newDist[id] = 0;
+      }
+    }
+    // Actualize currentNodes_:
+    currentNodes_[bestPair[0]] = parent;
+    currentNodes_.erase(bestPair[1]);
+    for (map<size_t, Node *>::iterator i = currentNodes_.begin(); i != currentNodes_.end(); i++)
+    {
+      size_t id = i->first;
+      matrix_(bestPair[0], id) = matrix_(id, bestPair[0]) = newDist[id];
+    }  
+  }
+  finalStep(idNextNode);
+}
+
+Node* AbstractAgglomerativeDistanceMethod::getLeafNode(int id, const std::string& name)
+{
+  return new Node(id, name);
+}
+
+Node* AbstractAgglomerativeDistanceMethod::getParentNode(int id, Node* son1, Node* son2)
+{
+  Node* parent = new Node(id);
+  parent->addSon(son1);
+  parent->addSon(son2);
+  return parent;
+}
+
diff --git a/src/Bpp/Phyl/Distance/AbstractAgglomerativeDistanceMethod.h b/src/Bpp/Phyl/Distance/AbstractAgglomerativeDistanceMethod.h
new file mode 100755
index 0000000..a404c7e
--- /dev/null
+++ b/src/Bpp/Phyl/Distance/AbstractAgglomerativeDistanceMethod.h
@@ -0,0 +1,230 @@
+//
+// File: AbstractAgglomerativeDistanceMethod.h
+// Created by: Julien Dutheil
+//             Vincent Ranwez
+// Created on: Wed jun 22 10:00 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _ABSTRACTAGGLOMERATIVEDISTANCEMETHOD_H_
+#define _ABSTRACTAGGLOMERATIVEDISTANCEMETHOD_H_
+
+#include "DistanceMethod.h"
+#include "../Node.h"
+#include "../TreeTemplate.h"
+
+// From the STL:
+#include <map>
+
+namespace bpp
+{
+
+/**
+ * @brief Partial implementation of the AgglomerativeDistanceMethod interface.
+ *
+ * This class provides a DistanceMatrix object for computations, and a map
+ * with pivot indices and a pointer toward the corresponding subtree.
+ *
+ * Several methods, commons to several algorithm are provided.
+ */
+class AbstractAgglomerativeDistanceMethod:
+  public virtual AgglomerativeDistanceMethod
+{
+	protected:
+		DistanceMatrix matrix_;
+		Tree* tree_;
+
+    std::map<size_t, Node*> currentNodes_;
+    bool verbose_;
+    bool rootTree_;
+	
+	public:
+		//AbstractAgglomerativeDistanceMethod() :
+    //  matrix_(0), tree_(0), currentNodes_(), verbose_(true), rootTree_(false) {}
+
+		AbstractAgglomerativeDistanceMethod(bool verbose = true, bool rootTree = false) :
+      matrix_(0), tree_(0), currentNodes_(), verbose_(verbose), rootTree_(rootTree) {}
+		
+    AbstractAgglomerativeDistanceMethod(const DistanceMatrix& matrix, bool verbose = true, bool rootTree = false) :
+      matrix_(0), tree_(0), currentNodes_(), verbose_(verbose), rootTree_(rootTree)
+    {
+      setDistanceMatrix(matrix);
+    }
+
+		virtual ~AbstractAgglomerativeDistanceMethod()
+    {
+      if (tree_)
+        delete tree_;
+    }
+    
+    AbstractAgglomerativeDistanceMethod(const AbstractAgglomerativeDistanceMethod& a) :
+      matrix_(a.matrix_), tree_(0), currentNodes_(), verbose_(a.verbose_), rootTree_(a.rootTree_)
+    {
+      // Hard copy of inner tree:
+      if (a.tree_)
+        tree_ = new TreeTemplate<Node>(* a.tree_);
+    }
+
+    AbstractAgglomerativeDistanceMethod& operator=(const AbstractAgglomerativeDistanceMethod& a)
+    {
+      matrix_ = a.matrix_;
+      // Hard copy of inner tree:
+      if (a.tree_)
+        tree_ = new TreeTemplate<Node>(* a.tree_);
+      else tree_ = 0;
+      currentNodes_.clear();
+      verbose_ = a.verbose_;
+      rootTree_ = a.rootTree_;
+      return *this;
+    }
+
+	public:
+		virtual void setDistanceMatrix(const DistanceMatrix& matrix);
+
+    /**
+     * @brief Get the computed tree, if there is one.
+     *
+     * @return A copy of the computed tree if there is one, 0 otherwise.
+     */
+    virtual
+#if defined(NO_VIRTUAL_COV)
+		Tree *
+#else
+		TreeTemplate<Node> * 
+#endif
+		getTree() const
+    {
+    	//Node * root = TreeTools::cloneSubtree<Node>(* dynamic_cast<TreeTemplate<Node> *>(tree_) -> getRootNode());
+	    //return new TreeTemplate<Node>(* root);
+      return tree_ == 0 ? 0 : new TreeTemplate<Node>(*tree_);
+    }
+		
+    /**
+     * @brief Compute the tree corresponding to the distance matrix.
+     *
+     * This method implements the following algorithm:
+     * 1) Build all leaf nodes (getLeafNode method)
+     * 2) Get the best pair to agglomerate (getBestPair method)
+     * 3) Compute the branch lengths for this pair (computeBranchLengthsForPair method)
+     * 4) Build the parent node of the pair (getParentNode method)
+     * 5) For each remaining node, update distances from the pair (computeDistancesFromPair method)
+     * 6) Return to step 2 while there are more than 3 remaining nodes.
+     * 7) Perform the final step, and send a rooted or unrooted tree.
+     */
+		virtual void computeTree() throw (Exception);
+
+    void setVerbose(bool yn) { verbose_ = yn; }
+    bool isVerbose() const { return verbose_; }
+
+	protected:
+    /**
+     * @name Specific methods.
+     *
+     * @{
+     */
+
+    /**
+     * @brief Get the best pair of nodes to agglomerate.
+     *
+     * Define the criterion to chose the next pair of nodes to agglomerate.
+     * This criterion uses the matrix_ distance matrix.
+     *
+     * @return A size 2 vector with the indices of the nodes.
+     * @throw Exception If an error occured.
+     */
+		virtual std::vector<size_t> getBestPair() throw (Exception) = 0;
+		
+    /**
+     * @brief Compute the branch lengths for two nodes to agglomerate.
+     *
+     * @code
+     * +---l1-----N1
+     * |
+     * +---l2-----N2
+     * @endcode
+     * This method compute l1 and l2 given N1 and N2.
+     *
+     * @param pair The indices of the nodes to be agglomerated.
+     * @return A size 2 vector with branch lengths.
+     */
+    virtual std::vector<double> computeBranchLengthsForPair(const std::vector<size_t> & pair) = 0;
+
+    /**
+     * @brief Actualizes the distance matrix according to a given pair and the corresponding branch lengths.
+     *
+     * @param pair The indices of the nodes to be agglomerated.
+     * @param branchLengths The corresponding branch lengths.
+     * @param pos The index of the node whose distance ust be updated.
+     * @return The distance between the 'pos' node and the agglomerated pair.
+     */
+		virtual double computeDistancesFromPair(const std::vector<size_t>& pair, const std::vector<double>& branchLengths, size_t pos) = 0;
+		
+    /**
+     * @brief Method called when there ar eonly three remaining node to agglomerate, and creates the root node of the tree.
+     *
+     * @param idRoot The id of the root node.
+     */
+    virtual void finalStep(int idRoot) = 0;
+
+    /**
+     * @brief Get a leaf node.
+     *
+     * Create a new node with the given id and name.
+     *
+     * @param id The id of the node.
+     * @param name The name of the node.
+     * @return A pointer toward a new node object.
+     */
+		virtual Node* getLeafNode(int id, const std::string& name);
+
+    /**
+     * @brief Get an inner node.
+     *
+     * Create a new node with the given id, and set its sons.
+     *
+     * @param id The id of the node.
+     * @param son1 The first son of the node.
+     * @param son2 The second son of the node.
+     * @return A pointer toward a new node object.
+     */
+		virtual Node* getParentNode(int id, Node * son1, Node * son2);
+    /** @} */
+		
+};
+
+} //end of namespace bpp.
+
+#endif //_ABSTRACTAGGLOMERATIVEDISTANCEMETHOD_H_
+
diff --git a/src/Bpp/Phyl/Distance/BioNJ.cpp b/src/Bpp/Phyl/Distance/BioNJ.cpp
new file mode 100644
index 0000000..060d73c
--- /dev/null
+++ b/src/Bpp/Phyl/Distance/BioNJ.cpp
@@ -0,0 +1,130 @@
+//
+// File: BioNJ.h
+// Created by: Vincent Ranwez
+// Created on: Tue Apr 11 14:23 2006
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "BioNJ.h"
+#include "../Tree.h"
+
+#include <Bpp/App/ApplicationTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <cmath>
+#include <iostream>
+
+using namespace std;
+
+double BioNJ::computeDistancesFromPair(const vector<size_t>& pair, const vector<double>& branchLengths, size_t pos)
+{
+  return positiveLengths_ ?
+         std::max(lambda_ * (matrix_(pair[0], pos) - branchLengths[0]) + (1 - lambda_) * (matrix_(pair[1], pos) - branchLengths[1]), 0.)
+         :          lambda_ * (matrix_(pair[0], pos) - branchLengths[0]) + (1 - lambda_) * (matrix_(pair[1], pos) - branchLengths[1]);
+}
+
+void BioNJ::computeTree() throw (Exception)
+{
+  // Initialization:
+  for (size_t i = 0; i < matrix_.size(); i++)
+  {
+    currentNodes_[i] = getLeafNode(static_cast<int>(i), matrix_.getName(i));
+  }
+  int idNextNode = static_cast<int>(matrix_.size());
+  vector<double> newDist(matrix_.size());
+  vector<double> newVar(matrix_.size());
+
+  // Build tree:
+  while (currentNodes_.size() > (rootTree_ ? 2 : 3))
+  {
+    if (verbose_)
+      ApplicationTools::displayGauge(matrix_.size() - currentNodes_.size(), matrix_.size() - (rootTree_ ? 2 : 3) - 1);
+    vector<size_t> bestPair = getBestPair();
+    vector<double> distances = computeBranchLengthsForPair(bestPair);
+    Node* best1 = currentNodes_[bestPair[0]];
+    Node* best2 = currentNodes_[bestPair[1]];
+    // Distances may be used by getParentNodes (PGMA for instance).
+    best1->setDistanceToFather(distances[0]);
+    best2->setDistanceToFather(distances[1]);
+    Node* parent = getParentNode(idNextNode++, best1, best2);
+    // compute lambda
+    lambda_ = 0;
+    if (variance_(bestPair[0], bestPair[1]) == 0)
+      lambda_ = .5;
+    else
+    {
+      for (map<size_t, Node*>::iterator i = currentNodes_.begin(); i != currentNodes_.end(); i++)
+      {
+        size_t id = i->first;
+        if (id != bestPair[0] && id != bestPair[1])
+          lambda_ += (variance_(bestPair[1], id) - variance_(bestPair[0], id));
+      }
+      double div = 2 * static_cast<double>(currentNodes_.size() - 2) * variance_(bestPair[0], bestPair[1]);
+      lambda_ /= div;
+      lambda_ += .5;
+    }
+    if (lambda_ < 0.)
+      lambda_ = 0.;
+    if (lambda_ > 1.)
+      lambda_ = 1.;
+
+    for (map<size_t, Node*>::iterator i = currentNodes_.begin(); i != currentNodes_.end(); i++)
+    {
+      size_t id = i->first;
+      if (id != bestPair[0] && id != bestPair[1])
+      {
+        newDist[id] = computeDistancesFromPair(bestPair, distances, id);
+        newVar[id] = lambda_ * variance_(bestPair[0], id) + (1 - lambda_) * variance_(bestPair[1], id) - lambda_ * (1 - lambda_) * variance_(bestPair[0], bestPair[1]);
+      }
+      else
+      {
+        newDist[id] = 0;
+      }
+    }
+    // Actualize currentNodes_:
+    currentNodes_[bestPair[0]] = parent;
+    currentNodes_.erase(bestPair[1]);
+    for (map<size_t, Node*>::iterator i = currentNodes_.begin(); i != currentNodes_.end(); i++)
+    {
+      size_t id = i->first;
+      matrix_(  bestPair[0], id) =    matrix_(id, bestPair[0]) = newDist[id];
+      variance_(bestPair[0], id) =  variance_(id, bestPair[0]) = newVar[id];
+    }
+  }
+  finalStep(idNextNode);
+}
+
diff --git a/src/Bpp/Phyl/Distance/BioNJ.h b/src/Bpp/Phyl/Distance/BioNJ.h
new file mode 100644
index 0000000..0c44f89
--- /dev/null
+++ b/src/Bpp/Phyl/Distance/BioNJ.h
@@ -0,0 +1,112 @@
+//
+// File: BioNJ.cpp
+// Created by: Vincent Ranwez
+// Created on: Tue Apr 11 14:23 2006
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _BIONJ_H_
+#define _BIONJ_H_
+
+#include "NeighborJoining.h"
+
+namespace bpp
+{
+/**
+ * @brief The BioNJ distance method.
+ *
+ * Reference:
+ * Gascuel O.
+ * BIONJ: an improved version of the NJ algorithm based on a simple model of sequence data.
+ * Mol Biol Evol. 1997 Jul;14(7):685-95.
+ */
+class BioNJ :
+  public NeighborJoining
+{
+private:
+  DistanceMatrix variance_;
+  double lambda_;
+
+public:
+  /**
+   * @brief Create a new BioNJ object instance and compute a tree from a distance matrix.
+   *
+   * @param rooted Tell if the output tree should be rooted.
+   * @param positiveLengths Tell if negative lengths should be avoided.
+   * @param verbose Allow to display extra information, like progress bars.
+   */
+  BioNJ(bool rooted = false, bool positiveLengths = false, bool verbose = true) :
+    NeighborJoining(rooted, positiveLengths, verbose),
+    variance_(0),
+    lambda_(0) {}
+
+  /**
+   * @brief Create a new BioNJ object instance and compute a tree from a distance matrix.
+   *
+   * @param matrix Input distance matrix.
+   * @param rooted Tell if the output tree should be rooted.
+   * @param positiveLengths Tell if negative lengths should be avoided.
+   * @param verbose Allow to display extra information, like progress bars.
+   */
+  BioNJ(const DistanceMatrix& matrix, bool rooted = false, bool positiveLengths = false, bool verbose = true) throw (Exception) :
+    NeighborJoining(rooted, positiveLengths, verbose),
+    // Use the default constructor, because the other one call computeTree.
+    variance_(matrix),
+    lambda_(0)
+  {
+    setDistanceMatrix(matrix);
+    outputPositiveLengths(positiveLengths);
+    computeTree();
+  }
+
+  BioNJ* clone() const { return new BioNJ(*this); }
+
+  virtual ~BioNJ() {}
+
+public:
+  std::string getName() const { return "BioNJ"; }
+
+  void setDistanceMatrix(const DistanceMatrix& matrix)
+  {
+    NeighborJoining::setDistanceMatrix(matrix);
+    variance_ = matrix;
+  }
+  void computeTree() throw (Exception);
+  double computeDistancesFromPair(const std::vector<size_t>& pair, const std::vector<double>& branchLengths, size_t pos);
+};
+} // end of namespace bpp.
+
+#endif // _BIONJ_H_
+
diff --git a/src/Bpp/Phyl/Distance/DistanceEstimation.cpp b/src/Bpp/Phyl/Distance/DistanceEstimation.cpp
new file mode 100755
index 0000000..e578e11
--- /dev/null
+++ b/src/Bpp/Phyl/Distance/DistanceEstimation.cpp
@@ -0,0 +1,695 @@
+//
+// File: DistanceEstimation.cpp
+// Created by: Julien Dutheil
+//             Vincent Ranwez
+// Created on: Wed jun 08 10:39 2005
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "DistanceEstimation.h"
+#include "../Tree.h"
+#include "../PatternTools.h"
+#include "../SitePatterns.h"
+
+// From bpp-core:
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Numeric/AutoParameter.h>
+
+// From bpp-seq:
+#include <Bpp/Seq/SiteTools.h>
+#include <Bpp/Seq/Sequence.h>
+#include <Bpp/Seq/Container/AlignedSequenceContainer.h>
+#include <Bpp/Seq/DistanceMatrix.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <vector>
+#include <string>
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+
+/******************************************************************************/
+
+TwoTreeLikelihood::TwoTreeLikelihood(
+    const std::string& seq1, const std::string& seq2,
+    const SiteContainer& data,
+    SubstitutionModel* model,
+    DiscreteDistribution* rDist,
+    bool verbose) throw (Exception) :
+  AbstractDiscreteRatesAcrossSitesTreeLikelihood(rDist, verbose),
+  shrunkData_(0), seqnames_(2), model_(model), brLenParameters_(), pxy_(), dpxy_(), d2pxy_(),
+  rootPatternLinks_(), rootWeights_(), nbSites_(0), nbClasses_(0), nbStates_(0), nbDistinctSites_(0),
+  rootLikelihoods_(), rootLikelihoodsS_(), rootLikelihoodsSR_(), dLikelihoods_(), d2Likelihoods_(),
+  leafLikelihoods1_(), leafLikelihoods2_(),
+  minimumBrLen_(0.000001), brLenConstraint_(0), brLen_(0)
+{
+  seqnames_[0] = seq1;
+  seqnames_[1] = seq2;
+  data_ = PatternTools::getSequenceSubset(data, seqnames_);
+  if (data_->getAlphabet()->getAlphabetType()
+      != model_->getAlphabet()->getAlphabetType())
+    throw AlphabetMismatchException("TwoTreeTreeLikelihood::TwoTreeTreeLikelihood. Data and model must have the same alphabet type.",
+                                    data_->getAlphabet(),
+                                    model_->getAlphabet());
+
+  nbSites_   = data_->getNumberOfSites();
+  nbClasses_ = rateDistribution_->getNumberOfCategories();
+  nbStates_  = model_->getNumberOfStates();
+  if (verbose)
+    ApplicationTools::displayMessage("Double-Recursive Homogeneous Tree Likelihood");
+
+  // Initialize root patterns:
+  SitePatterns pattern(data_);
+  shrunkData_       = pattern.getSites();
+  rootWeights_      = pattern.getWeights();
+  rootPatternLinks_ = pattern.getIndices();
+  nbDistinctSites_  = shrunkData_->getNumberOfSites();
+  if (verbose)
+    ApplicationTools::displayResult("Number of distinct sites", TextTools::toString(nbDistinctSites_));
+
+  // Init _likelihoods:
+  if (verbose) ApplicationTools::displayTask("Init likelihoods arrays recursively");
+  // Clone data for more efficiency on sequences access:
+  const SiteContainer* sequences = new AlignedSequenceContainer(*shrunkData_);
+  initTreeLikelihoods(*sequences);
+  delete sequences;
+
+  brLen_ = minimumBrLen_;
+  brLenConstraint_ = new IntervalConstraint(1, minimumBrLen_, true);
+
+  if (verbose) ApplicationTools::displayTaskDone();
+}
+
+/******************************************************************************/
+
+TwoTreeLikelihood::TwoTreeLikelihood(const TwoTreeLikelihood& lik) :
+  AbstractDiscreteRatesAcrossSitesTreeLikelihood(lik),
+  shrunkData_        (dynamic_cast<SiteContainer*>(lik.shrunkData_->clone())),
+  seqnames_          (lik.seqnames_),
+  model_             (lik.model_),
+  brLenParameters_   (lik.brLenParameters_),
+  pxy_               (lik.pxy_),
+  dpxy_              (lik.dpxy_),
+  d2pxy_             (lik.d2pxy_),
+  rootPatternLinks_  (lik.rootPatternLinks_),
+  rootWeights_       (lik.rootWeights_),
+  nbSites_           (lik.nbSites_),
+  nbClasses_         (lik.nbClasses_),
+  nbStates_          (lik.nbStates_),
+  nbDistinctSites_   (lik.nbDistinctSites_),
+  rootLikelihoods_   (lik.rootLikelihoods_),
+  rootLikelihoodsS_  (lik.rootLikelihoodsS_),
+  rootLikelihoodsSR_ (lik.rootLikelihoodsSR_),
+  dLikelihoods_      (lik.dLikelihoods_),
+  d2Likelihoods_     (lik.d2Likelihoods_),
+  leafLikelihoods1_  (lik.leafLikelihoods1_),
+  leafLikelihoods2_  (lik.leafLikelihoods2_),
+  minimumBrLen_      (lik.minimumBrLen_),
+  brLenConstraint_   (dynamic_cast<Constraint*>(brLenConstraint_->clone())),
+  brLen_             (lik.brLen_)
+{}
+
+/******************************************************************************/
+
+TwoTreeLikelihood& TwoTreeLikelihood::operator=(const TwoTreeLikelihood& lik)
+{
+  AbstractDiscreteRatesAcrossSitesTreeLikelihood::operator=(lik);
+  shrunkData_        = dynamic_cast<SiteContainer*>(lik.shrunkData_->clone());
+  seqnames_          = lik.seqnames_;
+  model_             = lik.model_;
+  brLenParameters_   = lik.brLenParameters_;
+  pxy_               = lik.pxy_;
+  dpxy_              = lik.dpxy_;
+  d2pxy_             = lik.d2pxy_;
+  rootPatternLinks_  = lik.rootPatternLinks_;
+  rootWeights_       = lik.rootWeights_;
+  nbSites_           = lik.nbSites_;
+  nbClasses_         = lik.nbClasses_;
+  nbStates_          = lik.nbStates_;
+  nbDistinctSites_   = lik.nbDistinctSites_;
+  rootLikelihoods_   = lik.rootLikelihoods_;
+  rootLikelihoodsS_  = lik.rootLikelihoodsS_;
+  rootLikelihoodsSR_ = lik.rootLikelihoodsSR_;
+  dLikelihoods_      = lik.dLikelihoods_;
+  d2Likelihoods_     = lik.d2Likelihoods_;
+  leafLikelihoods1_  = lik.leafLikelihoods1_;
+  leafLikelihoods2_  = lik.leafLikelihoods2_;
+  minimumBrLen_      = lik.minimumBrLen_;
+  brLenConstraint_   = dynamic_cast<Constraint*>(brLenConstraint_->clone());
+  brLen_             = lik.brLen_;
+  return *this;
+}
+
+/******************************************************************************/
+
+TwoTreeLikelihood::~TwoTreeLikelihood()
+{
+  delete shrunkData_;
+  if (brLenConstraint_) delete brLenConstraint_;
+}
+
+/******************************************************************************/
+
+void TwoTreeLikelihood::initialize() throw (Exception)
+{
+  initParameters();
+  initialized_ = true;
+  fireParameterChanged(getParameters());
+}
+
+/******************************************************************************/
+
+ParameterList TwoTreeLikelihood::getBranchLengthsParameters() const
+{
+  if (!initialized_) throw Exception("TwoTreeLikelihood::getBranchLengthsParameters(). Object is not initialized.");
+  return brLenParameters_.getCommonParametersWith(getParameters());
+}
+
+/******************************************************************************/
+
+ParameterList TwoTreeLikelihood::getSubstitutionModelParameters() const
+{
+  if (!initialized_) throw Exception("TwoTreeLikelihood::getSubstitutionModelParameters(). Object is not initialized.");
+  return model_->getParameters().getCommonParametersWith(getParameters());
+}
+
+/******************************************************************************/
+
+double TwoTreeLikelihood::getLikelihood() const
+{
+  double l = 1.;
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    l *= std::pow(rootLikelihoodsSR_[i], (int)rootWeights_[i]);
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+double TwoTreeLikelihood::getLogLikelihood() const
+{
+  double ll = 0;
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    ll += rootWeights_[i] * log(rootLikelihoodsSR_[i]);
+  }
+  return ll;
+}
+
+/******************************************************************************/
+
+double TwoTreeLikelihood::getLikelihoodForASite(size_t site) const
+{
+  return rootLikelihoodsSR_[rootPatternLinks_[site]];
+}
+
+/******************************************************************************/
+
+double TwoTreeLikelihood::getLogLikelihoodForASite(size_t site) const
+{
+  return log(rootLikelihoodsSR_[rootPatternLinks_[site]]);
+}
+
+/******************************************************************************/
+
+double TwoTreeLikelihood::getLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  return rootLikelihoodsS_[rootPatternLinks_[site]][rateClass];
+}
+
+/******************************************************************************/
+
+double TwoTreeLikelihood::getLogLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  return log(rootLikelihoodsS_[rootPatternLinks_[site]][rateClass]);
+}
+
+/******************************************************************************/
+
+double TwoTreeLikelihood::getLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const
+{
+  return rootLikelihoods_[rootPatternLinks_[site]][rateClass][state];
+}
+
+/******************************************************************************/
+
+double TwoTreeLikelihood::getLogLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const
+{
+  return log(rootLikelihoods_[rootPatternLinks_[site]][rateClass][state]);
+}
+
+/******************************************************************************/
+
+void TwoTreeLikelihood::initParameters()
+{
+  // Reset parameters:
+  resetParameters_();
+
+  // Branch lengths:
+  initBranchLengthsParameters();
+  addParameters_(brLenParameters_);
+
+  // Substitution model:
+  addParameters_(model_->getIndependentParameters());
+
+  // Rate distribution:
+  addParameters_(rateDistribution_->getIndependentParameters());
+}
+
+/******************************************************************************/
+
+void TwoTreeLikelihood::applyParameters() throw (Exception)
+{
+  // Apply branch length:
+  brLen_ = getParameterValue("BrLen");
+  // Apply substitution model parameters:
+  model_->matchParametersValues(getParameters());
+  // Apply rate distribution parameters:
+  rateDistribution_->matchParametersValues(getParameters());
+}
+
+/******************************************************************************/
+
+void TwoTreeLikelihood::initBranchLengthsParameters()
+{
+  if (brLen_ < minimumBrLen_)
+  {
+   ApplicationTools::displayWarning("Branch length is too small: " + TextTools::toString(brLen_) + ". Value is set to " + TextTools::toString(minimumBrLen_));
+    brLen_ = minimumBrLen_;
+  }
+  brLenParameters_.reset();
+  brLenParameters_.addParameter(Parameter("BrLen", brLen_, brLenConstraint_));
+}
+
+/******************************************************************************/
+
+void TwoTreeLikelihood::setParameters(const ParameterList& parameters)
+throw (ParameterNotFoundException, ConstraintException)
+{
+  setParametersValues(parameters);
+}
+
+/******************************************************************************/
+
+void TwoTreeLikelihood::fireParameterChanged(const ParameterList& params)
+{
+  applyParameters();
+
+  // For now we ignore the parameter that changed and we recompute all arrays...
+
+  // Computes all pxy and pyx once for all:
+  pxy_.resize(nbClasses_);
+  for (size_t c = 0; c < nbClasses_; c++)
+  {
+    VVdouble* pxy_c = &pxy_[c];
+    pxy_c->resize(nbStates_);
+    RowMatrix<double> Q = model_->getPij_t(brLen_ * rateDistribution_->getCategory(c));
+    for (size_t x = 0; x < nbStates_; x++)
+    {
+      Vdouble* pxy_c_x = &(*pxy_c)[x];
+      pxy_c_x->resize(nbStates_);
+      for (size_t y = 0; y < nbStates_; y++)
+      {
+        (*pxy_c_x)[y] = Q(x, y);
+      }
+    }
+  }
+
+  if (computeFirstOrderDerivatives_)
+  {
+    // Computes all dpxy/dt once for all:
+    dpxy_.resize(nbClasses_);
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      VVdouble* dpxy_c = &dpxy_[c];
+      dpxy_c->resize(nbStates_);
+      double rc = rateDistribution_->getCategory(c);
+      RowMatrix<double> dQ = model_->getdPij_dt(brLen_ * rc);
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        Vdouble* dpxy_c_x = &(*dpxy_c)[x];
+        dpxy_c_x->resize(nbStates_);
+        for (size_t y = 0; y < nbStates_; y++)
+        {
+          (*dpxy_c_x)[y] = rc * dQ(x, y);
+        }
+      }
+    }
+  }
+
+  if (computeSecondOrderDerivatives_)
+  {
+    // Computes all d2pxy/dt2 once for all:
+    d2pxy_.resize(nbClasses_);
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      VVdouble* d2pxy_c = &d2pxy_[c];
+      d2pxy_c->resize(nbStates_);
+      double rc = rateDistribution_->getCategory(c);
+      RowMatrix<double> d2Q = model_->getd2Pij_dt2(brLen_ * rc);
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        Vdouble* d2pxy_c_x = &(*d2pxy_c)[x];
+        d2pxy_c_x->resize(nbStates_);
+        for (size_t y = 0; y < nbStates_; y++)
+        {
+          (*d2pxy_c_x)[y] = rc * rc * d2Q(x, y);
+        }
+      }
+    }
+  }
+
+  computeTreeLikelihood();
+  if (computeFirstOrderDerivatives_)
+  {
+    computeTreeDLikelihood();
+  }
+  if (computeSecondOrderDerivatives_)
+  {
+    computeTreeD2Likelihood();
+  }
+}
+
+/******************************************************************************/
+
+double TwoTreeLikelihood::getValue() const
+throw (Exception)
+{
+  return -getLogLikelihood();
+}
+
+/******************************************************************************/
+
+void TwoTreeLikelihood::initTreeLikelihoods(const SequenceContainer& sequences) throw (Exception)
+{
+  const Sequence* seq1 = &sequences.getSequence(seqnames_[0]);
+  const Sequence* seq2 = &sequences.getSequence(seqnames_[1]);
+  leafLikelihoods1_.resize(nbDistinctSites_);
+  leafLikelihoods2_.resize(nbDistinctSites_);
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+   Vdouble* leafLikelihoods1_i = &leafLikelihoods1_[i];
+   Vdouble* leafLikelihoods2_i = &leafLikelihoods2_[i];
+   leafLikelihoods1_i->resize(nbStates_);
+   leafLikelihoods2_i->resize(nbStates_);
+   int state1 = seq1->getValue(i);
+   int state2 = seq2->getValue(i);
+    for (size_t s = 0; s < nbStates_; s++)
+    {
+      // Leaves likelihood are set to 1 if the char correspond to the site in the sequence,
+      // otherwise value set to 0:
+      try
+      {
+        (*leafLikelihoods1_i)[s] = model_->getInitValue(s, state1);
+        (*leafLikelihoods2_i)[s] = model_->getInitValue(s, state2);
+      }
+      catch (SequenceNotFoundException& snfe)
+      {
+        throw SequenceNotFoundException("TwoTreeLikelihood::initTreelikelihoods. Leaf name in tree not found in site conainer: ", snfe.getSequenceId());
+      }
+    }
+  }
+
+  // Initialize likelihood vector:
+  rootLikelihoods_.resize(nbDistinctSites_);
+  rootLikelihoodsS_.resize(nbDistinctSites_);
+  rootLikelihoodsSR_.resize(nbDistinctSites_);
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    VVdouble* rootLikelihoods_i = &rootLikelihoods_[i];
+    Vdouble* rootLikelihoodsS_i = &rootLikelihoodsS_[i];
+    rootLikelihoods_i->resize(nbClasses_);
+    rootLikelihoodsS_i->resize(nbClasses_);
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* rootLikelihoods_i_c = &(*rootLikelihoods_i)[c];
+      rootLikelihoods_i_c->resize(nbStates_);
+      for (size_t s = 0; s < nbStates_; s++)
+      {
+        (*rootLikelihoods_i_c)[s] = 1.; // All likelihoods are initialized to 1.
+      }
+    }
+  }
+
+  // Initialize d and d2 likelihoods:
+  dLikelihoods_.resize(nbDistinctSites_);
+  d2Likelihoods_.resize(nbDistinctSites_);
+}
+
+/******************************************************************************/
+
+void TwoTreeLikelihood::computeTreeLikelihood()
+{
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    VVdouble* rootLikelihoods_i = &rootLikelihoods_[i];
+    Vdouble* leafLikelihoods1_i = &leafLikelihoods1_[i];
+    Vdouble* leafLikelihoods2_i = &leafLikelihoods2_[i];
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* rootLikelihoods_i_c = &(*rootLikelihoods_i)[c];
+      VVdouble* pxy_c = &pxy_[c];
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        Vdouble* pxy_c_x = &(*pxy_c)[x];
+        double l = 0;
+        double l1 = (*leafLikelihoods1_i)[x];
+        for (size_t y = 0; y < nbStates_; y++)
+        {
+          double l2 = (*leafLikelihoods2_i)[y];
+          l += l1 * l2 * (*pxy_c_x)[y];
+        }
+        (*rootLikelihoods_i_c)[x] = l;
+      }
+    }
+  }
+
+  Vdouble fr = model_->getFrequencies();
+  Vdouble p = rateDistribution_->getProbabilities();
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    // For each site in the sequence,
+    VVdouble* rootLikelihoods_i = &rootLikelihoods_[i];
+    Vdouble* rootLikelihoodsS_i = &rootLikelihoodsS_[i];
+    rootLikelihoodsSR_[i] = 0;
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      (*rootLikelihoodsS_i)[c] = 0;
+      // For each rate classe,
+      Vdouble* rootLikelihoods_i_c = &(*rootLikelihoods_i)[c];
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        // For each initial state,
+        (*rootLikelihoodsS_i)[c] += fr[x] * (*rootLikelihoods_i_c)[x];
+      }
+      rootLikelihoodsSR_[i] += p[c] * (*rootLikelihoodsS_i)[c];
+    }
+  }
+}
+
+/******************************************************************************/
+
+void TwoTreeLikelihood::computeTreeDLikelihood()
+{
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    Vdouble* leafLikelihoods1_i = &leafLikelihoods1_[i];
+    Vdouble* leafLikelihoods2_i = &leafLikelihoods2_[i];
+    double dli = 0;
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      VVdouble* dpxy_c = &dpxy_[c];
+      double dlic = 0;
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        Vdouble* dpxy_c_x = &(*dpxy_c)[x];
+        double l1 = (*leafLikelihoods1_i)[x];
+        double dlicx = 0;
+        for (size_t y = 0; y < nbStates_; y++)
+        {
+          double l2 = (*leafLikelihoods2_i)[y];
+          dlicx += l1 * l2 * (*dpxy_c_x)[y];
+        }
+        dlic += dlicx * model_->freq(x);
+      }
+      dli += dlic * rateDistribution_->getProbability(c);
+    }
+    dLikelihoods_[i] = dli / rootLikelihoodsSR_[i];
+  }
+}
+
+/******************************************************************************/
+
+void TwoTreeLikelihood::computeTreeD2Likelihood()
+{
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    Vdouble* leafLikelihoods1_i = &leafLikelihoods1_[i];
+    Vdouble* leafLikelihoods2_i = &leafLikelihoods2_[i];
+    double d2li = 0;
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      VVdouble* d2pxy_c = &d2pxy_[c];
+      double d2lic = 0;
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        Vdouble* d2pxy_c_x = &(*d2pxy_c)[x];
+        double l1 = (*leafLikelihoods1_i)[x];
+        double d2licx = 0;
+        for (size_t y = 0; y < nbStates_; y++)
+        {
+          double l2 = (*leafLikelihoods2_i)[y];
+          d2licx += l1 * l2 * (*d2pxy_c_x)[y];
+        }
+        d2lic += d2licx * model_->freq(x);
+      }
+      d2li += d2lic * rateDistribution_->getProbability(c);
+    }
+    d2Likelihoods_[i] = d2li / rootLikelihoodsSR_[i];
+  }
+}
+
+/******************************************************************************/
+
+double TwoTreeLikelihood::getFirstOrderDerivative(const string& variable) const
+throw (Exception)
+{
+  if (!hasParameter(variable))
+    throw ParameterNotFoundException("TwoTreeLikelihood::getFirstOrderDerivative().", variable);
+  if (getRateDistributionParameters().hasParameter(variable))
+  {
+    cout << "DEBUB: WARNING!!! Derivatives respective to rate distribution parameter are not implemented." << endl;
+    return log(-1.);
+  }
+  if (getSubstitutionModelParameters().hasParameter(variable))
+  {
+    cout << "DEBUB: WARNING!!! Derivatives respective to substitution model parameters are not implemented." << endl;
+    return log(-1.);
+  }
+
+  //
+  // Computation for branch lengths:
+  //
+
+  // Get the node with the branch whose length must be derivated:
+  double d = 0;
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    d += rootWeights_[i] * dLikelihoods_[i];
+  }
+  return -d;
+}
+
+/******************************************************************************/
+
+double TwoTreeLikelihood::getSecondOrderDerivative(const string& variable) const
+throw (Exception)
+{
+  if (!hasParameter(variable))
+    throw ParameterNotFoundException("TwoTreeLikelihood::getSecondOrderDerivative().", variable);
+  if (getRateDistributionParameters().hasParameter(variable))
+  {
+    cout << "DEBUB: WARNING!!! Derivatives respective to rate distribution parameter are not implemented." << endl;
+    return log(-1.);
+  }
+  if (getSubstitutionModelParameters().hasParameter(variable))
+  {
+    cout << "DEBUB: WARNING!!! Derivatives respective to substitution model parameters are not implemented." << endl;
+    return log(-1.);
+  }
+
+  //
+  // Computation for branch lengths:
+  //
+
+  // Get the node with the branch whose length must be derivated:
+  double d2 = 0;
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    d2 += rootWeights_[i] * (d2Likelihoods_[i] - pow(dLikelihoods_[i], 2));
+  }
+  return -d2;
+}
+
+/******************************************************************************/
+
+void DistanceEstimation::computeMatrix() throw (NullPointerException)
+{
+  size_t n = sites_->getNumberOfSequences();
+  vector<string> names = sites_->getSequencesNames();
+  if (dist_ != 0) delete dist_;
+  dist_ = new DistanceMatrix(names);
+  optimizer_->setVerbose(static_cast<size_t>(max(static_cast<int>(verbose_) - 2, 0)));
+  for (size_t i = 0; i < n; i++)
+  {
+    (*dist_)(i, i) = 0;
+    if (verbose_ == 1)
+    {
+      ApplicationTools::displayGauge(i, n - 1, '=');
+    }
+    for (size_t j = i + 1; j < n; j++)
+    {
+      if (verbose_ > 1)
+      {
+        ApplicationTools::displayGauge(j - i - 1, n - i - 2, '=');
+      }
+      TwoTreeLikelihood* lik =
+        new TwoTreeLikelihood(names[i], names[j], *sites_, model_.get(), rateDist_.get(), verbose_ > 3);
+      lik->initialize();
+      lik->enableDerivatives(true);
+      size_t d = SymbolListTools::getNumberOfDistinctPositions(sites_->getSequence(i), sites_->getSequence(j));
+      size_t g = SymbolListTools::getNumberOfPositionsWithoutGap(sites_->getSequence(i), sites_->getSequence(j));
+      lik->setParameterValue("BrLen", g == 0 ? lik->getMinimumBranchLength() : std::max(lik->getMinimumBranchLength(), static_cast<double>(d) / static_cast<double>(g)));
+      // Optimization:
+      optimizer_->setFunction(lik);
+      optimizer_->setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO);
+      ParameterList params = lik->getBranchLengthsParameters();
+      params.addParameters(parameters_);
+      optimizer_->init(params);
+      optimizer_->optimize();
+      // Store results:
+      (*dist_)(i, j) = (*dist_)(j, i) = lik->getParameterValue("BrLen");
+      delete lik;
+    }
+    if (verbose_ > 1 && ApplicationTools::message) ApplicationTools::message->endLine();
+  }
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Distance/DistanceEstimation.h b/src/Bpp/Phyl/Distance/DistanceEstimation.h
new file mode 100755
index 0000000..911da5d
--- /dev/null
+++ b/src/Bpp/Phyl/Distance/DistanceEstimation.h
@@ -0,0 +1,544 @@
+//
+// File: DistanceEstimation.h
+// Created by: Julien Dutheil
+//             Vincent Ranwez
+// Created on: Wed jun 08 10:39 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _DISTANCEESTIMATION_H_
+#define _DISTANCEESTIMATION_H_
+
+#include "../Model/SubstitutionModel.h"
+#include "../Likelihood/AbstractTreeLikelihood.h"
+#include "../Likelihood/DRHomogeneousTreeLikelihood.h"
+#include "../Likelihood/PseudoNewtonOptimizer.h"
+
+#include <Bpp/Clonable.h>
+#include <Bpp/Numeric/ParameterList.h>
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+#include <Bpp/Numeric/Function/Optimizer.h>
+#include <Bpp/Numeric/Function/SimpleMultiDimensions.h>
+#include <Bpp/Numeric/Function/MetaOptimizer.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+namespace bpp
+{
+
+/**
+ * @brief This class is a simplified version of DRHomogeneousTreeLikelihood for 2-Trees.
+ */
+class TwoTreeLikelihood:
+  public AbstractDiscreteRatesAcrossSitesTreeLikelihood  
+{
+  private:
+    SiteContainer* shrunkData_;
+    std::vector<std::string> seqnames_;
+    SubstitutionModel* model_;
+    ParameterList brLenParameters_;
+    
+    mutable VVVdouble pxy_;
+
+    mutable VVVdouble dpxy_;
+
+    mutable VVVdouble d2pxy_;
+
+    /**
+     * @brief As previous, but for the global container.
+     *
+     * The size of this vector is equal to the number of sites in the container,
+     * each element corresponds to a site in the container and points to the
+     * corresponding column in the likelihood array of the root node.
+     * If the container contains no repeated site, there will be a strict
+     * equivalence between each site and the likelihood array of the root node.
+     * However, if this is not the case, some pointers may point toward the same
+     * element in the likelihood array.
+     */
+    std::vector<size_t> rootPatternLinks_;
+
+    /**
+     * @brief The frequency of each site.
+     */
+    std::vector<unsigned int> rootWeights_;
+
+    //some values we'll need:
+    size_t nbSites_,         //the number of sites in the container
+           nbClasses_,       //the number of rate classes
+           nbStates_,        //the number of states in the alphabet
+           nbDistinctSites_; //the number of distinct sites in the container
+
+    mutable VVVdouble rootLikelihoods_;
+    mutable VVdouble rootLikelihoodsS_;
+    mutable Vdouble rootLikelihoodsSR_;
+    mutable Vdouble dLikelihoods_;
+    mutable Vdouble d2Likelihoods_;
+    mutable VVdouble leafLikelihoods1_, leafLikelihoods2_;
+  
+    double minimumBrLen_;
+    Constraint* brLenConstraint_;
+    double brLen_;
+
+  public:
+    TwoTreeLikelihood(
+      const std::string& seq1, const std::string& seq2,  
+      const SiteContainer& data,
+      SubstitutionModel* model,
+      DiscreteDistribution* rDist,
+      bool verbose)  throw (Exception);
+
+    TwoTreeLikelihood(const TwoTreeLikelihood& lik);
+    
+    TwoTreeLikelihood& operator=(const TwoTreeLikelihood& lik);
+
+    TwoTreeLikelihood* clone() const { return new TwoTreeLikelihood(*this); } 
+
+    virtual ~TwoTreeLikelihood();
+
+  public:
+
+    /**
+     * @name The TreeLikelihood interface.
+     *
+     * Other methods are implemented in the AbstractTreeLikelihood class.
+     *
+     * @{
+     */
+    TreeLikelihoodData* getLikelihoodData() throw (NotImplementedException)
+    {
+      throw NotImplementedException("TwoTreeLikelihood::getLikelihoodData.");
+    }
+    const TreeLikelihoodData* getLikelihoodData() const throw (NotImplementedException)
+    {
+      throw NotImplementedException("TwoTreeLikelihood::getLikelihoodData.");
+    }  
+    double getLikelihood() const;
+    double getLogLikelihood() const;
+    double getLikelihoodForASite (size_t site) const;
+    double getLogLikelihoodForASite(size_t site) const;
+    ParameterList getBranchLengthsParameters() const;
+    ParameterList getSubstitutionModelParameters() const;
+    SubstitutionModel* getSubstitutionModel(int nodeId, size_t siteIndex) throw (NodeNotFoundException) { return model_; }
+    const SubstitutionModel* getSubstitutionModel(int nodeId, size_t siteIndex) const throw (NodeNotFoundException) { return model_; }
+    const std::vector<double>& getRootFrequencies(size_t siteIndex) const { return model_->getFrequencies(); }
+    size_t getSiteIndex(size_t site) const throw (IndexOutOfBoundsException) { return rootPatternLinks_[site]; }
+    /**
+     * @brief This method is not applicable for this object.
+     */
+    VVVdouble getTransitionProbabilitiesPerRateClass(int nodeId, size_t siteIndex) const { return pxy_; }
+    void setData(const SiteContainer& sites) throw (Exception) {}
+    void initialize() throw(Exception);
+    /** @} */
+
+    /**
+     * @name The DiscreteRatesAcrossSites interface implementation:
+     *
+     * @{
+     */
+    double getLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+    double getLogLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+    double getLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const;
+    double getLogLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const;
+    /** @} */
+
+    /**
+     * @brief Get the substitution model used for the computation.
+     *
+     * @return A const pointer toward the substitution model of this instance.
+     */
+    const SubstitutionModel* getSubstitutionModel() const { return model_; }
+    
+    /**
+     * @brief Get the substitution model used for the computation.
+     *
+     * @return A pointer toward the substitution model of this instance.
+     */
+    SubstitutionModel* getSubstitutionModel() { return model_; }
+
+    ConstBranchModelIterator* getNewBranchModelIterator(int nodeId) const throw (NotImplementedException)
+    {
+      throw NotImplementedException("TwoTreeLikelihood::getNewBranchSiteModelIterator. This class does not (yet) provide support for partition models.");
+    }
+
+    ConstSiteModelIterator* getNewSiteModelIterator(size_t siteIndex) const throw (NotImplementedException)
+    {
+      throw NotImplementedException("TwoTreeLikelihood::getNewSiteModelIterator. This class is for inner use only and does not provide site model iterators.");
+    }
+
+    
+
+    /**
+     * @brief Implements the Function interface.
+     *
+     * Update the parameter list and call the applyParameters() method.
+     * Then compute the likelihoods at each node (computeLikelihood() method)
+     * and call the getLogLikelihood() method.
+     *
+     * If a subset of the whole parameter list is passed to the function,
+     * only these parameters are updated and the other remain constant (i.e.
+     * equal to their last value).
+     *
+     * @param parameters The parameter list to pass to the function.
+     */
+    void setParameters(const ParameterList& parameters) throw (ParameterNotFoundException, ConstraintException);
+    double getValue() const throw(Exception);
+    
+    /**
+     * @name DerivableFirstOrder interface.
+     *
+     * @{
+     */
+    double getFirstOrderDerivative(const std::string& variable) const throw (Exception);
+    /** @{ */
+
+    /**
+     * @name DerivableSecondOrder interface.
+     *
+     * @{
+     */
+    double getSecondOrderDerivative(const std::string& variable) const throw (Exception);
+    double getSecondOrderDerivative(const std::string& variable1, const std::string& variable2) const throw (Exception) { return 0; } // Not implemented for now.
+    /** @} */
+
+    virtual void initBranchLengthsParameters();
+
+    virtual void setMinimumBranchLength(double minimum)
+    {
+      minimumBrLen_ = minimum;
+      if (brLenConstraint_) delete brLenConstraint_;
+      brLenConstraint_ = new IntervalConstraint(1, minimumBrLen_, true);
+      initBranchLengthsParameters();
+    }
+
+    virtual double getMinimumBranchLength() const { return minimumBrLen_; }
+
+  protected:
+    
+    /**
+     * @brief This method initializes the leaves according to a sequence container.
+     *
+     * Here the container shrunkData_ is used.
+     * Likelihood is set to 1 for the state corresponding to the sequence site,
+     * otherwise it is set to 0.
+     *
+     * The two likelihood arrays are initialized according to alphabet
+     * size and sequences length, and filled with 1.
+     *
+     * NB: This method is recursive.
+     *
+     * @param sequences The sequence container to use.
+     */
+    virtual void initTreeLikelihoods(const SequenceContainer & sequences) throw (Exception);
+
+    void fireParameterChanged(const ParameterList & params);
+    virtual void computeTreeLikelihood();
+    virtual void computeTreeDLikelihood();
+    virtual void computeTreeD2Likelihood();
+    /**
+     * @brief This builds the <i>parameters</i> list from all parametrizable objects,
+     * <i>i.e.</i> substitution model, rate distribution and tree.
+     */
+    virtual void initParameters();
+
+    /**
+     * @brief All parameters are stores in a parameter list.
+     *
+     * This function apply these parameters to the substitution model,
+     * to the rate distribution and to the branch lengths.
+     */
+    virtual void applyParameters() throw (Exception);  
+
+};
+
+/**
+ * @brief Estimate a distance matrix from sequence data, according to a given model.
+ *
+ * By default, the parameters of the model are fixed to there given values.
+ * It is possible to estimate one or several parameters by setting them with the
+ * setAdditionalParameters() method.
+ * Parameters will be estimated separately for each pair of sequence.
+ *
+ * For now it is not possible to retrieve estimated values.
+ * You'll have to specify a 'profiler' to the optimizer and then look at the file
+ * if you want to do so.
+ */
+class DistanceEstimation:
+  public virtual Clonable
+{
+  private:
+    auto_ptr<SubstitutionModel> model_;
+    auto_ptr<DiscreteDistribution> rateDist_;
+    const SiteContainer* sites_;
+    DistanceMatrix* dist_;
+    Optimizer* optimizer_;
+    MetaOptimizer* defaultOptimizer_;
+    size_t verbose_;
+    ParameterList parameters_;
+
+  public:
+  
+    /**
+     * @brief Create a new DistanceEstimation object according to a given substitution model and a rate distribution.
+     *
+     * This instance will own the model and distribution, and will take car of their recopy and destruction.
+     *
+     * @param model    The substitution model to use.
+     * @param rateDist The discrete rate distribution to use.
+     * @param verbose  The verbose level:
+     *  - 0=Off,
+     *  - 1=one * by row computation
+     *  - 2=one * by row computation and one . by column computation
+     *  - 3=2 + optimization verbose enabled
+     *  - 4=3 + likelihood object verbose enabled
+     */
+    DistanceEstimation(
+        SubstitutionModel* model,
+        DiscreteDistribution* rateDist,
+        size_t verbose = 1) :
+      model_(model),
+      rateDist_(rateDist),
+      sites_(0),
+      dist_(0),
+      optimizer_(0),
+      defaultOptimizer_(0),
+      verbose_(verbose),
+      parameters_()
+    {
+      init_();
+    }
+  
+    /**
+     * @brief Create a new DistanceEstimation object and compute distances
+     * according to a given substitution model and a rate distribution.
+     *
+     * This instance will own the model and distribution, and will take car of their recopy and destruction.
+     *
+     * @param model    The substitution model to use.
+     * @param rateDist The discrete rate distribution to use.
+     * @param sites    The sequence data.
+     * @param verbose  The verbose level:
+     *  - 0=Off,
+     *  - 1=one * by row computation
+     *  - 2=one * by row computation and one . by column computation
+     *  - 3=2 + optimization verbose enabled
+     *  - 4=3 + likelihood object verbose enabled
+     *  @param computeMat if true the computeMatrix() method is called.
+     */
+    DistanceEstimation(
+        SubstitutionModel* model,
+        DiscreteDistribution* rateDist,
+        const SiteContainer* sites,
+        size_t verbose = 1,
+        bool computeMat = true) :
+      model_(model),
+      rateDist_(rateDist),
+      sites_(sites),
+      dist_(0),
+      optimizer_(0),
+      defaultOptimizer_(0),
+      verbose_(verbose),
+      parameters_()
+    {
+      init_();
+      if(computeMat) computeMatrix();
+    }
+    
+    /**
+     * @brief Copy constructor.
+     *
+     * Only the distance matrix is hard-copied, if there is one.
+     *
+     * @param distanceEstimation The object to copy.
+     */
+    DistanceEstimation(const DistanceEstimation& distanceEstimation):
+      model_(distanceEstimation.model_->clone()),
+      rateDist_(distanceEstimation.rateDist_->clone()),
+      sites_(distanceEstimation.sites_),
+      dist_(0),
+      optimizer_(dynamic_cast<Optimizer *>(distanceEstimation.optimizer_->clone())),
+      defaultOptimizer_(dynamic_cast<MetaOptimizer *>(defaultOptimizer_->clone())),
+      verbose_(distanceEstimation.verbose_),
+      parameters_(distanceEstimation.parameters_)
+    {
+      if(distanceEstimation.dist_ != 0)
+        dist_ = new DistanceMatrix(*distanceEstimation.dist_);
+      else
+        dist_ = 0;
+    }
+
+    /**
+     * @brief Assigment operator.
+     *
+     * Only the distance matrix is hard-copied, if there is one.
+     * 
+     * @param distanceEstimation The object to copy.
+     * @return A reference toward this object.
+     */
+    DistanceEstimation& operator=(const DistanceEstimation& distanceEstimation)
+    {
+      model_.reset(distanceEstimation.model_->clone());
+      rateDist_.reset(distanceEstimation.rateDist_->clone());
+      sites_      = distanceEstimation.sites_;
+      if (distanceEstimation.dist_ != 0)
+        dist_     = new DistanceMatrix(*distanceEstimation.dist_);
+      else
+        dist_     = 0;
+      optimizer_  = dynamic_cast<Optimizer *>(distanceEstimation.optimizer_->clone());
+      // _defaultOptimizer has already been initialized since the default constructor has been called.
+      verbose_    = distanceEstimation.verbose_;
+      parameters_ = distanceEstimation.parameters_;
+      return *this;
+    }
+
+    virtual ~DistanceEstimation()
+    {
+      if (dist_) delete dist_;
+      delete defaultOptimizer_;
+      delete optimizer_;
+    }
+
+#ifndef NO_VIRTUAL_COV
+    DistanceEstimation*
+#else
+    Clonable*
+#endif
+    clone() const { return new DistanceEstimation(*this); }
+    
+  private:
+    void init_()
+    {
+      MetaOptimizerInfos* desc = new MetaOptimizerInfos();
+      std::vector<std::string> name;
+      name.push_back("BrLen");
+      desc->addOptimizer("Branch length", new PseudoNewtonOptimizer(0), name, 2, MetaOptimizerInfos::IT_TYPE_FULL);
+      ParameterList tmp = model_->getParameters();
+      tmp.addParameters(rateDist_->getParameters());
+      desc->addOptimizer("substitution model and rate distribution", new SimpleMultiDimensions(0), tmp.getParameterNames(), 0, MetaOptimizerInfos::IT_TYPE_STEP);
+      defaultOptimizer_ = new MetaOptimizer(0, desc);
+      defaultOptimizer_->setMessageHandler(0);
+      defaultOptimizer_->setProfiler(0);
+      defaultOptimizer_->getStopCondition()->setTolerance(0.0001);
+      optimizer_ = dynamic_cast<Optimizer*>(defaultOptimizer_->clone());
+    }
+
+  public:
+
+    /**
+     * @brief Perform the distance computation.
+     *
+     * Result can be called by the getMatrix() method.
+     *
+     * @throw NullPointerException if at least one of the model,
+     * rate distribution or data are not initialized.
+     */
+    void computeMatrix() throw (NullPointerException);
+    
+    /**
+     * @brief Get the distance matrix.
+     *
+     * @return A pointer toward the computed distance matrix.
+     */
+    DistanceMatrix* getMatrix() const { return dist_ == 0 ? 0 : new DistanceMatrix(*dist_); }
+
+    bool hasSubstitutionModel() const { return model_.get(); }
+
+    const SubstitutionModel& getSubstitutionModel() const throw (Exception) {
+      if (hasSubstitutionModel())
+        return *model_;
+      else
+        throw Exception("DistanceEstimation::getSubstitutionModel(). No model assciated to this instance.");
+    }
+
+    void resetSubstitutionModel(SubstitutionModel* model = 0) { model_.reset(model); }
+
+    bool hasRateDistribution() const { return rateDist_.get(); }
+
+    const DiscreteDistribution& getRateDistribution() const throw (Exception) {
+      if (hasRateDistribution())
+        return *rateDist_;
+      else
+        throw Exception("DistanceEstimation::getRateDistribution(). No rate distribution assciated to this instance.");
+    }
+
+    void resetRateDistribution(DiscreteDistribution* rateDist = 0) { rateDist_.reset(rateDist); }
+
+    void setData(const SiteContainer* sites) { sites_ = sites; }
+    const SiteContainer* getData() const { return sites_; }
+    void resetData() { sites_ = 0; }
+    
+    void setOptimizer(const Optimizer * optimizer)
+    { 
+      if (optimizer_) delete optimizer_;
+      optimizer_ = dynamic_cast<Optimizer *>(optimizer->clone());
+    }
+    const Optimizer* getOptimizer() const { return optimizer_; }
+    Optimizer* getOptimizer() { return optimizer_; }
+    void resetOptimizer() { optimizer_ = dynamic_cast<Optimizer*>(defaultOptimizer_->clone()); }
+
+    /**
+     * @brief Specify a list of parameters to be estimated.
+     *
+     * Parameters will be estimated separately for each distance.
+     *
+     * @param parameters A list of parameters to estimate.
+     */
+    void setAdditionalParameters(const ParameterList& parameters)
+    {
+      parameters_ = parameters;
+    }
+
+    /**
+     * @brief Reset all additional parameters.
+     */
+    void resetAdditionalParameters()
+    {
+      parameters_.reset();
+    }
+
+    /**
+     * @param verbose Verbose level.
+     */
+    void setVerbose(size_t verbose) { verbose_ = verbose; }
+    /**
+     * @return Verbose level.
+     */
+    size_t getVerbose() const { return verbose_; }
+};
+
+} //end of namespace bpp.
+
+#endif //_DISTANCEESTIMATION_H_
+
diff --git a/src/Bpp/Phyl/Distance/DistanceMethod.h b/src/Bpp/Phyl/Distance/DistanceMethod.h
new file mode 100755
index 0000000..099fc90
--- /dev/null
+++ b/src/Bpp/Phyl/Distance/DistanceMethod.h
@@ -0,0 +1,120 @@
+//
+// File: DistanceMethod.h
+// Created by: Julien Dutheil
+//             Vincent Ranwez
+// Created on: Wed jun 22 10:00 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _DISTANCEMETHOD_H_
+#define _DISTANCEMETHOD_H_
+
+//From bpp-core:
+#include <Bpp/Clonable.h>
+
+//From the STL:
+#include <string>
+
+namespace bpp
+{
+
+class DistanceMatrix;
+class Node;
+class Tree;
+
+/**
+ * @brief General interface for distance-based phylogenetic reconstruction methods.
+ */
+class DistanceMethod:
+  public virtual Clonable
+{
+	public:
+		DistanceMethod() {}
+		virtual ~DistanceMethod() {}
+
+	public:
+    /**
+     * @brief Set the distance matrix to use.
+     *
+     * @param matrix The matrix to use.
+     */
+		virtual void setDistanceMatrix(const DistanceMatrix& matrix) = 0;
+		
+    /**
+     * @brief Perform the clustering.
+     */
+    virtual void computeTree() = 0;
+    
+    /**
+     * @return The computed tree.
+     */
+		virtual Tree* getTree() const = 0;
+
+    /**
+     * @return The name of the distance method.
+     */
+    virtual std::string getName() const = 0;
+
+    /**
+     * @param yn Enable/Disable verbose mode.
+     */
+    virtual void setVerbose(bool yn) = 0;
+
+    /**
+     * @return True if verbose mode is enabled.
+     */
+    virtual bool isVerbose() const = 0;
+};
+
+/**
+ * @brief Interface for agglomerative distance methods.
+ *
+ * This interface does not contain any specific method and
+ * is there only for "ontology" purposes. Specific methods
+ * might be added later.
+ */
+class AgglomerativeDistanceMethod:
+  public DistanceMethod
+{
+	public:
+		AgglomerativeDistanceMethod() {}
+		virtual ~AgglomerativeDistanceMethod() {}
+
+};
+
+} //end of namespace bpp.
+
+#endif //_DISTANCEMETHOD_H_
+
diff --git a/src/Bpp/Phyl/Distance/HierarchicalClustering.cpp b/src/Bpp/Phyl/Distance/HierarchicalClustering.cpp
new file mode 100644
index 0000000..014dac9
--- /dev/null
+++ b/src/Bpp/Phyl/Distance/HierarchicalClustering.cpp
@@ -0,0 +1,213 @@
+//
+// File: HierarchicalClustering.cpp
+// From file Cluster.cpp in CoMap package.
+// Created by: Julien Dutheil
+// Created on: Tue Aug 30 17:19 2005
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+   This software is a computer program whose purpose is to map substitutions
+   on a tree and to detect co-evolving positions in a dataset.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "HierarchicalClustering.h"
+#include "../NodeTemplate.h"
+
+using namespace bpp;
+using namespace std;
+
+const string HierarchicalClustering::COMPLETE = "Complete";
+const string HierarchicalClustering::SINGLE   = "Single";
+const string HierarchicalClustering::AVERAGE  = "Average";
+const string HierarchicalClustering::MEDIAN   = "Median";
+const string HierarchicalClustering::WARD     = "Ward";
+const string HierarchicalClustering::CENTROID = "Centroid";
+
+TreeTemplate<Node>* HierarchicalClustering::getTree() const
+{
+  Node* root = TreeTemplateTools::cloneSubtree<Node>(*dynamic_cast<TreeTemplate<NodeTemplate<ClusterInfos> >*>(tree_)->getRootNode());
+  return new TreeTemplate<Node>(root);
+}
+
+vector<size_t> HierarchicalClustering::getBestPair() throw (Exception)
+{
+  vector<size_t> bestPair(2);
+  double distMin = -std::log(0.);
+  for (map<size_t, Node*>::iterator i = currentNodes_.begin(); i != currentNodes_.end(); i++)
+  {
+    size_t id = i->first;
+    map<size_t, Node*>::iterator j = i;
+    j++;
+    for ( ; j != currentNodes_.end(); j++)
+    {
+      size_t jd = j->first;
+      double dist = matrix_(id, jd);
+      if (dist < distMin)
+      {
+        distMin = dist;
+        bestPair[0] = id;
+        bestPair[1] = jd;
+      }
+    }
+  }
+  if (distMin == -std::log(0.))
+  {
+    cout << "---------------------------------------------------------------------------------" << endl;
+    for (map<size_t, Node*>::iterator i = currentNodes_.begin(); i != currentNodes_.end(); i++)
+    {
+      size_t id = i->first;
+      map<size_t, Node*>::iterator j = i;
+      j++;
+      for ( ; j != currentNodes_.end(); j++)
+      {
+        size_t jd = j->first;
+        double dist = matrix_(id, jd);
+        cout << dist << "\t";
+      }
+      cout << endl;
+    }
+    cout << "---------------------------------------------------------------------------------" << endl;
+
+    throw Exception("Unexpected error: no minimum found in the distance matrix.");
+  }
+
+  return bestPair;
+}
+vector<double> HierarchicalClustering::computeBranchLengthsForPair(const vector<size_t>& pair)
+{
+  vector<double> d(2);
+  double dist = matrix_(pair[0], pair[1]) / 2.;
+  d[0] = dist - dynamic_cast<NodeTemplate<ClusterInfos>*>(currentNodes_[pair[0]])->getInfos().length;
+  d[1] = dist - dynamic_cast<NodeTemplate<ClusterInfos>*>(currentNodes_[pair[1]])->getInfos().length;
+  return d;
+}
+
+double HierarchicalClustering::computeDistancesFromPair(const vector<size_t>& pair, const vector<double>& branchLengths, size_t pos)
+{
+  double w1, w2, w3, w4;
+  if (method_ == "Single")
+  {
+    w1 = .5;
+    w2 = .5;
+    w3 = 0.;
+    w4 = -.5;
+  }
+  else if (method_ == "Complete")
+  {
+    w1 = .5;
+    w2 = .5;
+    w3 = 0.;
+    w4 = .5;
+  }
+  else if (method_ == "Median")
+  {
+    w1 = .5;
+    w2 = .5;
+    w3 = -0.25;
+    w4 = 0.;
+  }
+  else if (method_ == "Average")
+  {
+    double n1 = static_cast<double>(dynamic_cast<NodeTemplate<ClusterInfos>*>(currentNodes_[pair[0]])->getInfos().numberOfLeaves);
+    double n2 = static_cast<double>(dynamic_cast<NodeTemplate<ClusterInfos>*>(currentNodes_[pair[1]])->getInfos().numberOfLeaves);
+    w1 = n1 / (n1 + n2);
+    w2 = n2 / (n1 + n2);
+    w3 = 0.;
+    w4 = 0.;
+  }
+  else if (method_ == "Ward")
+  {
+    double n1 = static_cast<double>(dynamic_cast<NodeTemplate<ClusterInfos>*>(currentNodes_[pair[0]])->getInfos().numberOfLeaves);
+    double n2 = static_cast<double>(dynamic_cast<NodeTemplate<ClusterInfos>*>(currentNodes_[pair[1]])->getInfos().numberOfLeaves);
+    double n3 = static_cast<double>(dynamic_cast<NodeTemplate<ClusterInfos>*>(currentNodes_[pos])->getInfos().numberOfLeaves);
+    w1 = (n1 + n3) / (n1 + n2 + n3);
+    w2 = (n2 + n3) / (n1 + n2 + n3);
+    w3 = -n3 / (n1 + n2 + n3);
+    w4 = 0.;
+  }
+  else if (method_ == "Centroid")
+  {
+    double n1 = static_cast<double>(dynamic_cast<NodeTemplate<ClusterInfos>*>(currentNodes_[pair[0]])->getInfos().numberOfLeaves);
+    double n2 = static_cast<double>(dynamic_cast<NodeTemplate<ClusterInfos>*>(currentNodes_[pair[1]])->getInfos().numberOfLeaves);
+    w1 = n1 / (n1 + n2);
+    w2 = n2 / (n1 + n2);
+    w3 = -n1 * n2 / pow(n1 + n2, 2.);
+    w4 = 0.;
+  }
+  else
+    throw Exception("HierarchicalClustering::computeBranchLengthsForPair. unknown method '" + method_ + "'.");
+  double d1 = matrix_(pair[0], pos);
+  double d2 = matrix_(pair[1], pos);
+  double d3 = matrix_(pair[0], pair[1]);
+  return w1 * d1 + w2 * d2 + w3 * d3 + w4* std::abs(d1 - d2);
+}
+
+void HierarchicalClustering::finalStep(int idRoot)
+{
+  NodeTemplate<ClusterInfos>* root = new NodeTemplate<ClusterInfos>(idRoot);
+  map<size_t, Node*>::iterator it = currentNodes_.begin();
+  size_t i1 = it->first;
+  Node* n1        = it->second;
+  it++;
+  size_t i2 = it->first;
+  Node* n2        = it->second;
+  double d = matrix_(i1, i2) / 2;
+  root->addSon(n1);
+  root->addSon(n2);
+  n1->setDistanceToFather(d - dynamic_cast<NodeTemplate<ClusterInfos>*>(n1)->getInfos().length);
+  n2->setDistanceToFather(d - dynamic_cast<NodeTemplate<ClusterInfos>*>(n2)->getInfos().length);
+  tree_ = new TreeTemplate<NodeTemplate<ClusterInfos> >(root);
+}
+
+Node* HierarchicalClustering::getLeafNode(int id, const string& name)
+{
+  ClusterInfos infos;
+  infos.numberOfLeaves = 1;
+  infos.length = 0.;
+  NodeTemplate<ClusterInfos>* leaf = new NodeTemplate<ClusterInfos>(id, name);
+  leaf->setInfos(infos);
+  return leaf;
+}
+
+Node* HierarchicalClustering::getParentNode(int id, Node* son1, Node* son2)
+{
+  ClusterInfos infos;
+  infos.numberOfLeaves =
+    dynamic_cast<NodeTemplate<ClusterInfos>*>(son1)->getInfos().numberOfLeaves
+    + dynamic_cast<NodeTemplate<ClusterInfos>*>(son2)->getInfos().numberOfLeaves;
+  infos.length = dynamic_cast<NodeTemplate<ClusterInfos>*>(son1)->getInfos().length + son1->getDistanceToFather();
+  Node* parent = new NodeTemplate<ClusterInfos>(id);
+  dynamic_cast<NodeTemplate<ClusterInfos>*>(parent)->setInfos(infos);
+  parent->addSon(son1);
+  parent->addSon(son2);
+  return parent;
+}
+
diff --git a/src/Bpp/Phyl/Distance/HierarchicalClustering.h b/src/Bpp/Phyl/Distance/HierarchicalClustering.h
new file mode 100644
index 0000000..acb9dd0
--- /dev/null
+++ b/src/Bpp/Phyl/Distance/HierarchicalClustering.h
@@ -0,0 +1,115 @@
+//
+// File: HierarchicalClustering.h
+// From file Cluster.h in CoMap package.
+// Created by: Julien Dutheil
+// Created on: Tue Aug 30 17:19 2005
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+   This software is a computer program whose purpose is to map substitutions
+   on a tree and to detect co-evolving positions in a dataset.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _HIERARCHICALCLUSTERING_H_
+#define _HIERARCHICALCLUSTERING_H_
+
+#include "AbstractAgglomerativeDistanceMethod.h"
+
+namespace bpp
+{
+class ClusterInfos
+{
+public:
+  size_t numberOfLeaves;
+  double length;
+
+public:
+  ClusterInfos() : numberOfLeaves(0),
+    length(0) {}
+};
+
+/**
+ * @brief Hierarchical clustering.
+ *
+ * This class implements the complete, single, average (= UPGMA), median, ward and centroid linkage methods.
+ */
+class HierarchicalClustering :
+  public AbstractAgglomerativeDistanceMethod
+{
+public:
+  static const std::string COMPLETE;
+  static const std::string SINGLE;
+  static const std::string AVERAGE;
+  static const std::string MEDIAN;
+  static const std::string WARD;
+  static const std::string CENTROID;
+
+protected:
+  std::string method_;
+
+public:
+  /**
+   * @brief Builds a new clustering object.
+   *
+   * @param method The linkage method to use. should be one of COMPLETE, SINGLE, AVERAGE, MEDIAN, WARD, CENTROID.
+   * @param verbose Tell if some progress information should be displayed.
+   */
+  HierarchicalClustering(const std::string& method, bool verbose = false) :
+    AbstractAgglomerativeDistanceMethod(verbose),
+    method_(method) {}
+  HierarchicalClustering(const std::string& method, const DistanceMatrix& matrix, bool verbose = false) throw (Exception) :
+    AbstractAgglomerativeDistanceMethod(matrix, verbose, true),
+    method_(method)
+  {
+    computeTree();
+  }
+
+  virtual ~HierarchicalClustering() {}
+
+  HierarchicalClustering* clone() const { return new HierarchicalClustering(*this); }
+
+public:
+  std::string getName() const { return "Hierarchical clustering: " + method_; }
+
+  TreeTemplate<Node>* getTree() const;
+
+protected:
+  std::vector<size_t> getBestPair() throw (Exception);
+  std::vector<double> computeBranchLengthsForPair(const std::vector<size_t>& pair);
+  double computeDistancesFromPair(const std::vector<size_t>& pair, const std::vector<double>& branchLengths, size_t pos);
+  void finalStep(int idRoot);
+  virtual Node* getLeafNode(int id, const std::string& name);
+  virtual Node* getParentNode(int id, Node* son1, Node* son2);
+};
+} // end of namespace bpp.
+
+#endif // _HIERARCHICALCLUSTERING_H_
+
diff --git a/src/Bpp/Phyl/Distance/NeighborJoining.cpp b/src/Bpp/Phyl/Distance/NeighborJoining.cpp
new file mode 100644
index 0000000..920bab4
--- /dev/null
+++ b/src/Bpp/Phyl/Distance/NeighborJoining.cpp
@@ -0,0 +1,159 @@
+//
+// File: NeighborJoining.cpp
+// Created by: Julien Dutheil
+//             Vincent Ranwez
+// Created on: Thu jun 23 10:39 2005
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "NeighborJoining.h"
+#include "../Tree.h"
+
+using namespace bpp;
+
+#include <cmath>
+#include <iostream>
+
+using namespace std;
+
+std::vector<size_t> NeighborJoining::getBestPair() throw (Exception)
+{
+  for (std::map<size_t, Node*>::iterator i = currentNodes_.begin(); i != currentNodes_.end(); i++)
+  {
+    size_t id = i->first;
+    sumDist_[id] = 0;
+    for (map<size_t, Node*>::iterator j = currentNodes_.begin(); j != currentNodes_.end(); j++)
+    {
+      size_t jd = j->first;
+      sumDist_[id] += matrix_(id, jd);
+    }
+  }
+
+  vector<size_t> bestPair(2);
+  double critMax = std::log(0.);
+  for (map<size_t, Node*>::iterator i = currentNodes_.begin(); i != currentNodes_.end(); i++)
+  {
+    size_t id = i->first;
+    map<size_t, Node*>::iterator j = i;
+    j++;
+    for ( ; j != currentNodes_.end(); j++)
+    {
+      size_t jd = j->first;
+      double crit = sumDist_[id] + sumDist_[jd] - static_cast<double>(currentNodes_.size() - 2) * matrix_(id, jd);
+      // cout << "\t" << id << "\t" << jd << "\t" << crit << endl;
+      if (crit > critMax)
+      {
+        critMax = crit;
+        bestPair[0] = id;
+        bestPair[1] = jd;
+      }
+    }
+  }
+
+  if (critMax == std::log(0.))
+  {
+    throw Exception("Unexpected error: no maximum criterium found.");
+  }
+  return bestPair;
+}
+
+std::vector<double> NeighborJoining::computeBranchLengthsForPair(const std::vector<size_t>& pair)
+{
+  double ratio = (sumDist_[pair[0]] - sumDist_[pair[1]]) / static_cast<double>(currentNodes_.size() - 2);
+  vector<double> d(2);
+  if (positiveLengths_)
+  {
+    d[0] = std::max(.5 * (matrix_(pair[0], pair[1]) + ratio), 0.);
+    d[1] = std::max(.5 * (matrix_(pair[0], pair[1]) - ratio), 0.);
+  }
+  else
+  {
+    d[0] = .5 * (matrix_(pair[0], pair[1]) + ratio);
+    d[1] = .5 * (matrix_(pair[0], pair[1]) - ratio);
+  }
+  return d;
+}
+
+double NeighborJoining::computeDistancesFromPair(const std::vector<size_t>& pair, const std::vector<double>& branchLengths, size_t pos)
+{
+  return
+    positiveLengths_ ?
+    std::max(.5 * (matrix_(pair[0], pos) - branchLengths[0] + matrix_(pair[1], pos) - branchLengths[1]), 0.)
+    :          .5 * (matrix_(pair[0], pos) - branchLengths[0] + matrix_(pair[1], pos) - branchLengths[1]);
+}
+
+void NeighborJoining::finalStep(int idRoot)
+{
+  Node* root = new Node(idRoot);
+  map<size_t, Node* >::iterator it = currentNodes_.begin();
+  size_t i1 = it->first;
+  Node* n1       = it->second;
+  it++;
+  size_t i2 = it->first;
+  Node* n2       = it->second;
+  if (currentNodes_.size() == 2)
+  {
+    // Rooted
+    double d = matrix_(i1, i2) / 2;
+    root->addSon(n1);
+    root->addSon(n2);
+    n1->setDistanceToFather(d);
+    n2->setDistanceToFather(d);
+  }
+  else
+  {
+    // Unrooted
+    it++;
+    size_t i3 = it->first;
+    Node* n3       = it->second;
+    double d1 = positiveLengths_ ?
+                std::max(matrix_(i1, i2) + matrix_(i1, i3) - matrix_(i2, i3), 0.)
+                :          matrix_(i1, i2) + matrix_(i1, i3) - matrix_(i2, i3);
+    double d2 = positiveLengths_ ?
+                std::max(matrix_(i2, i1) + matrix_(i2, i3) - matrix_(i1, i3), 0.)
+                :          matrix_(i2, i1) + matrix_(i2, i3) - matrix_(i1, i3);
+    double d3 = positiveLengths_ ?
+                std::max(matrix_(i3, i1) + matrix_(i3, i2) - matrix_(i1, i2), 0.)
+                :          matrix_(i3, i1) + matrix_(i3, i2) - matrix_(i1, i2);
+    root->addSon(n1);
+    root->addSon(n2);
+    root->addSon(n3);
+    n1->setDistanceToFather(d1 / 2.);
+    n2->setDistanceToFather(d2 / 2.);
+    n3->setDistanceToFather(d3 / 2.);
+  }
+  tree_ = new TreeTemplate<Node>(root);
+}
+
diff --git a/src/Bpp/Phyl/Distance/NeighborJoining.h b/src/Bpp/Phyl/Distance/NeighborJoining.h
new file mode 100755
index 0000000..905ef09
--- /dev/null
+++ b/src/Bpp/Phyl/Distance/NeighborJoining.h
@@ -0,0 +1,119 @@
+//
+// File: NeighborJoining.h
+// Created by: Julien Dutheil
+//             Vincent Ranwez
+// Created on: Thu jun 23 10:39 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _NEIGHBORJOINING_H_
+#define _NEIGHBORJOINING_H_
+
+#include "AbstractAgglomerativeDistanceMethod.h"
+
+namespace bpp
+{
+
+/**
+ * @brief The neighbor joining distance method.
+ *
+ * Reference:
+ * N Saitou and M Nei (1987), _Molecular Biology and Evolution_ 4(4) 406-25.
+ */ 
+class NeighborJoining :
+  public AbstractAgglomerativeDistanceMethod
+{
+	protected:
+    std::vector<double> sumDist_;
+    bool positiveLengths_;
+		
+	public:
+    /**
+     * @brief Create a new NeighborJoining object instance, without performing any computation.
+     *
+     * @param rooted Tell if the output tree should be rooted.
+     * @param positiveLengths Tell if negative lengths should be avoided.
+     * @param verbose Allow to display extra information, like progress bars.
+     */
+    NeighborJoining(bool rooted = false, bool positiveLengths = false, bool verbose = true) :
+      AbstractAgglomerativeDistanceMethod(verbose, rooted),
+      sumDist_(),
+      positiveLengths_(false)
+    {}
+
+    /**
+     * @brief Create a new NeighborJoining object instance and compute a tree from a distance matrix.
+     *
+     * @param matrix Input distance matrix.
+     * @param rooted Tell if the output tree should be rooted.
+     * @param positiveLengths Tell if negative lengths should be avoided.
+     * @param verbose Allow to display extra information, like progress bars.
+     */
+		NeighborJoining(const DistanceMatrix& matrix, bool rooted = false, bool positiveLengths = false, bool verbose = true) throw (Exception) :
+      AbstractAgglomerativeDistanceMethod(matrix, verbose, rooted),
+      sumDist_(),
+      positiveLengths_(positiveLengths) 
+		{
+			sumDist_.resize(matrix.size());
+			computeTree();
+		}
+   
+		virtual ~NeighborJoining() {}
+
+    NeighborJoining* clone() const { return new NeighborJoining(*this); }
+
+	public:
+    std::string getName() const { return "NJ"; }
+
+		virtual void setDistanceMatrix(const DistanceMatrix& matrix)
+		{ 
+			AbstractAgglomerativeDistanceMethod::setDistanceMatrix(matrix);
+			sumDist_.resize(matrix.size());
+		}
+
+    virtual void outputPositiveLengths(bool yn) { positiveLengths_ = yn; }
+	
+	protected:
+		std::vector<size_t> getBestPair() throw (Exception);
+		std::vector<double> computeBranchLengthsForPair(const std::vector<size_t>& pair);
+		double computeDistancesFromPair(const std::vector<size_t>& pair, const std::vector<double>& branchLengths, size_t pos);
+		void finalStep(int idRoot);	
+
+};
+
+} //end of namespace bpp.
+
+#endif //_NEIGHBORJOINING_H_
+
diff --git a/src/Bpp/Phyl/Distance/PGMA.cpp b/src/Bpp/Phyl/Distance/PGMA.cpp
new file mode 100644
index 0000000..b0b8177
--- /dev/null
+++ b/src/Bpp/Phyl/Distance/PGMA.cpp
@@ -0,0 +1,155 @@
+//
+// File: PGMA.cpp
+// Created by: Julien Dutheil
+// Created on: Mon jul 11 11:41 2005
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "PGMA.h"
+#include "../NodeTemplate.h"
+#include "../Tree.h"
+#include "../TreeTemplate.h"
+#include "../TreeTemplateTools.h"
+
+using namespace bpp;
+
+// From the STL:
+#include <cmath>
+#include <iostream>
+
+using namespace std;
+
+TreeTemplate<Node>* PGMA::getTree() const
+{
+  Node* root = TreeTemplateTools::cloneSubtree<Node>(*dynamic_cast<TreeTemplate<NodeTemplate<PGMAInfos> >*>(tree_)->getRootNode());
+  return new TreeTemplate<Node>(root);
+}
+
+vector<size_t> PGMA::getBestPair() throw (Exception)
+{
+  vector<size_t> bestPair(2);
+  double distMin = -std::log(0.);
+  for (map<size_t, Node*>::iterator i = currentNodes_.begin(); i != currentNodes_.end(); i++)
+  {
+    size_t id = i->first;
+    map<size_t, Node*>::iterator j = i;
+    j++;
+    for ( ; j != currentNodes_.end(); j++)
+    {
+      size_t jd = j->first;
+      double dist = matrix_(id, jd);
+      if (dist < distMin)
+      {
+        distMin = dist;
+        bestPair[0] = id;
+        bestPair[1] = jd;
+      }
+    }
+  }
+
+  if (distMin == -std::log(0.))
+  {
+    throw Exception("Unexpected error: no minimum found in the distance matrix.");
+  }
+
+  return bestPair;
+}
+
+vector<double> PGMA::computeBranchLengthsForPair(const vector<size_t>& pair)
+{
+  vector<double> d(2);
+  double dist = matrix_(pair[0], pair[1]) / 2.;
+  d[0] = dist - dynamic_cast<NodeTemplate<PGMAInfos>*>(currentNodes_[pair[0]])->getInfos().time;
+  d[1] = dist - dynamic_cast<NodeTemplate<PGMAInfos>*>(currentNodes_[pair[1]])->getInfos().time;
+  return d;
+}
+
+double PGMA::computeDistancesFromPair(const vector<size_t>& pair, const vector<double>& branchLengths, size_t pos)
+{
+  double w1, w2;
+  if (weighted_)
+  {
+    w1 = 1;
+    w2 = 1;
+  }
+  else
+  {
+    w1 = static_cast<double>(dynamic_cast<NodeTemplate<PGMAInfos>*>(currentNodes_[pair[0]])->getInfos().numberOfLeaves);
+    w2 = static_cast<double>(dynamic_cast<NodeTemplate<PGMAInfos>*>(currentNodes_[pair[1]])->getInfos().numberOfLeaves);
+  }
+  return (w1 * matrix_(pair[0], pos) + w2 * matrix_(pair[1], pos)) / (w1 + w2);
+}
+
+void PGMA::finalStep(int idRoot)
+{
+  NodeTemplate<PGMAInfos>* root = new NodeTemplate<PGMAInfos>(idRoot);
+  map<size_t, Node*>::iterator it = currentNodes_.begin();
+  size_t i1 = it->first;
+  Node* n1        = it->second;
+  it++;
+  size_t i2 = it->first;
+  Node* n2        = it->second;
+  double d = matrix_(i1, i2) / 2;
+  root->addSon(n1);
+  root->addSon(n2);
+  n1->setDistanceToFather(d - dynamic_cast<NodeTemplate<PGMAInfos>*>(n1)->getInfos().time);
+  n2->setDistanceToFather(d - dynamic_cast<NodeTemplate<PGMAInfos>*>(n2)->getInfos().time);
+  tree_ = new TreeTemplate<NodeTemplate<PGMAInfos> >(root);
+}
+
+Node* PGMA::getLeafNode(int id, const string& name)
+{
+  PGMAInfos infos;
+  infos.numberOfLeaves = 1;
+  infos.time = 0.;
+  NodeTemplate<PGMAInfos>* leaf = new NodeTemplate<PGMAInfos>(id, name);
+  leaf->setInfos(infos);
+  return leaf;
+}
+
+Node* PGMA::getParentNode(int id, Node* son1, Node* son2)
+{
+  PGMAInfos infos;
+  infos.numberOfLeaves =
+    dynamic_cast<NodeTemplate<PGMAInfos>*>(son1)->getInfos().numberOfLeaves
+    + dynamic_cast<NodeTemplate<PGMAInfos>*>(son2)->getInfos().numberOfLeaves;
+  infos.time = dynamic_cast<NodeTemplate<PGMAInfos>*>(son1)->getInfos().time + son1->getDistanceToFather();
+  Node* parent = new NodeTemplate<PGMAInfos>(id);
+  dynamic_cast<NodeTemplate<PGMAInfos>*>(parent)->setInfos(infos);
+  parent->addSon(son1);
+  parent->addSon(son2);
+  return parent;
+}
+
diff --git a/src/Bpp/Phyl/Distance/PGMA.h b/src/Bpp/Phyl/Distance/PGMA.h
new file mode 100644
index 0000000..e3e71de
--- /dev/null
+++ b/src/Bpp/Phyl/Distance/PGMA.h
@@ -0,0 +1,118 @@
+//
+// File: PGMA.h
+// Created by: Julien Dutheil
+// Created on: Mon jul 11 11:41 2005
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _PGMA_H_
+#define _PGMA_H_
+
+#include "AbstractAgglomerativeDistanceMethod.h"
+#include "../Tree.h"
+#include "../TreeTemplate.h"
+
+namespace bpp
+{
+/**
+ * @brief Inner data structure for WPGMA and UPGMA distance methods.
+ */
+struct PGMAInfos
+{
+  size_t numberOfLeaves;
+  double time;
+};
+
+/**
+ * @brief Compute WPGMA and UPGMA trees from a distance matrix.
+ *
+ * WPGMA = Weighted pair group method using arithmetic averaging,
+ * is equivalent to the average linkage hierarchical clustering method.
+ * The distance between two taxa is the average distance between all individuals in each taxa.
+ * The unweighted version (named UPGMA), uses a weighted average, with the number of individuals in a group as a weight.
+ */
+class PGMA :
+  public AbstractAgglomerativeDistanceMethod
+{
+protected:
+  bool weighted_;
+
+public:
+  PGMA(bool weighted = true) :
+    AbstractAgglomerativeDistanceMethod(true, true),
+    weighted_(weighted) {}
+
+  /**
+   * @brief Create a (U/W)PGMA object instance.
+   *
+   * @param matrix Input distance matrix.
+   * @param weighted Tell if we should perform Weighted or Unweighted pair group method.
+   * @param verbose Allow to display extra information, like progress bars.
+   */
+  PGMA(const DistanceMatrix& matrix, bool weighted = true, bool verbose = true) throw (Exception) :
+    AbstractAgglomerativeDistanceMethod(matrix, verbose, true),
+    weighted_(weighted)
+  {
+    computeTree();
+  }
+  virtual ~PGMA() {}
+
+  PGMA* clone() const { return new PGMA(*this); }
+
+public:
+  std::string getName() const { return std::string(weighted_ ? "W" : "U") + "PGMA"; }
+
+  void setDistanceMatrix(const DistanceMatrix& matrix)
+  {
+    AbstractAgglomerativeDistanceMethod::setDistanceMatrix(matrix);
+  }
+
+  TreeTemplate<Node>* getTree() const;
+
+  void setWeighted(bool weighted) { weighted_ = weighted; }
+  bool isWeighted() const { return weighted_; }
+
+protected:
+  std::vector<size_t> getBestPair() throw (Exception);
+  std::vector<double> computeBranchLengthsForPair(const std::vector<size_t>& pair);
+  double computeDistancesFromPair(const std::vector<size_t>& pair, const std::vector<double>& branchLengths, size_t pos);
+  void finalStep(int idRoot);
+  virtual Node* getLeafNode(int id, const std::string& name);
+  virtual Node* getParentNode(int id, Node* son1, Node* son2);
+};
+} // end of namespace bpp.
+
+#endif // _PGMA_H_
+
diff --git a/src/Bpp/Phyl/Graphics/AbstractDendrogramPlot.cpp b/src/Bpp/Phyl/Graphics/AbstractDendrogramPlot.cpp
new file mode 100644
index 0000000..32e443a
--- /dev/null
+++ b/src/Bpp/Phyl/Graphics/AbstractDendrogramPlot.cpp
@@ -0,0 +1,55 @@
+//
+// File: AbstractDendrogramPlot.cpp
+// Created by: Julien Dutheil
+// Created on: Fri Jul 17 11:23 2009
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide
+graphic components to develop bioinformatics applications.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "AbstractDendrogramPlot.h"
+
+using namespace bpp;
+using namespace std;
+
+short AbstractDendrogramPlot::ORIENTATION_LEFT_TO_RIGHT = 1;
+short AbstractDendrogramPlot::ORIENTATION_RIGHT_TO_LEFT = 2;
+short AbstractDendrogramPlot::ORIENTATION_TOP_TO_BOTTOM = 3;
+short AbstractDendrogramPlot::ORIENTATION_BOTTOM_TO_TOP = 4;
+
+void AbstractDendrogramPlot::plot(GraphicDevice& gDevice) const throw (Exception)
+{
+  gDevice.setCurrentPointSize(getDisplaySettings().pointSize);
+  drawDendrogram_(gDevice);
+}
+
diff --git a/src/Bpp/Phyl/Graphics/AbstractDendrogramPlot.h b/src/Bpp/Phyl/Graphics/AbstractDendrogramPlot.h
new file mode 100644
index 0000000..fc8a282
--- /dev/null
+++ b/src/Bpp/Phyl/Graphics/AbstractDendrogramPlot.h
@@ -0,0 +1,92 @@
+//
+// File: AbstractDendrogramPlot.h
+// Created by: Julien Dutheil
+// Created on: Fri Jul 17 11:23 2009
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide
+graphic components to develop bioinformatics applications.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _ABSTRACTDENDROGRAMPLOT_H_
+#define _ABSTRACTDENDROGRAMPLOT_H_
+
+#include "AbstractTreeDrawing.h"
+
+namespace bpp
+{
+
+/**
+ * @brief Basic implementation of dendrogram plots.
+ *
+ * Dendrograms are oriented plots, with all the leaves on one side of the plot, and the root node at the opposite side.
+ * This implementation offers to option for ploting form left to right or right to left. This will affect the direction
+ * of plot annotations. The drawing can always be transformed using the regular translation/rotation operation on the
+ * GraphicDevice.
+ */
+class AbstractDendrogramPlot:
+  public AbstractTreeDrawing
+{
+  private:
+    short horOrientation_;
+    short verOrientation_;
+
+  public:
+    AbstractDendrogramPlot():
+      AbstractTreeDrawing(), horOrientation_(ORIENTATION_LEFT_TO_RIGHT), verOrientation_(ORIENTATION_TOP_TO_BOTTOM)
+    {}
+
+  public:
+    void setHorizontalOrientation(short orientation) { horOrientation_ = orientation; }
+    void setVerticalOrientation(short orientation) { verOrientation_ = orientation; }
+
+    short getHorizontalOrientation() const { return horOrientation_; }
+    short getVerticalOrientation() const { return verOrientation_; }
+
+    void plot(GraphicDevice& gDevice) const throw (Exception);
+
+  protected:
+    virtual void drawDendrogram_(GraphicDevice& gDevice) const throw (Exception) = 0;
+   
+  public:
+    static short ORIENTATION_LEFT_TO_RIGHT;
+    static short ORIENTATION_RIGHT_TO_LEFT;
+    static short ORIENTATION_TOP_TO_BOTTOM;
+    static short ORIENTATION_BOTTOM_TO_TOP;
+
+};
+
+} //end of namespace bpp;
+
+#endif //_ABSTRACTDENDROGRAMPLOT_H_
+
+
diff --git a/src/Bpp/Phyl/Graphics/AbstractTreeDrawing.cpp b/src/Bpp/Phyl/Graphics/AbstractTreeDrawing.cpp
new file mode 100755
index 0000000..a7e0d1a
--- /dev/null
+++ b/src/Bpp/Phyl/Graphics/AbstractTreeDrawing.cpp
@@ -0,0 +1,103 @@
+//
+// File: AbstractTreeDrawing.cpp
+// Created by: Julien Dutheil
+// Created on: Sun Oct 16 10:06 2006
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide
+graphic components to develop bioinformatics applications.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "AbstractTreeDrawing.h"
+#include "../TreeTemplateTools.h"
+#include "../TreeTools.h"
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Numeric/Number.h>
+
+// From the STL:
+#include <algorithm>
+
+using namespace bpp;
+using namespace std;
+
+const TreeDrawingSettings AbstractTreeDrawing::DEFAULT_SETTINGS;
+  
+Point2D<double> AbstractTreeDrawing::getNodePosition(int nodeId) const
+throw (NodeNotFoundException)
+{
+  vector<INode *> nodes = tree_->getNodes();
+  for(unsigned int i = 0; i < nodes.size(); i++)
+  {
+    INode * node = nodes[i];
+    if(node->getId() == nodeId)
+    {
+      return node->getInfos().getPosition();
+    }
+  }
+  throw NodeNotFoundException("AbstractTreeDrawing::getNodePosition.", TextTools::toString(nodeId));
+}
+
+int AbstractTreeDrawing::getNodeAt(const Point2D<double>& position) const
+throw (NodeNotFoundException)
+{
+  vector<INode *> nodes = tree_->getNodes();
+  for(unsigned int i = 0; i < nodes.size(); i++)
+  {
+    INode * node = nodes[i];
+    Point2D<double> nodePos = node->getInfos().getPosition();
+    if(belongsTo(position, nodePos))
+    {
+      return node->getId();
+    }
+  }
+  throw NodeNotFoundException("AbstractTreeDrawing::getNode.", "");
+}
+
+bool AbstractTreeDrawing::belongsTo(const Point2D<double>& p1, const Point2D<double>& p2) const
+{
+  return (p1.getX() >= p2.getX() - settings_->pointArea && p1.getX() <= p2.getX() + settings_->pointArea
+       && p1.getY() >= p2.getY() - settings_->pointArea && p1.getY() <= p2.getY() + settings_->pointArea);
+}
+
+void AbstractTreeDrawing::drawAtNode(GraphicDevice& gDevice, const INode& node, const string& text, double xOffset, double yOffset, short hpos, short vpos, double angle) const
+{
+  gDevice.drawText(node.getInfos().getX() + xOffset * xUnit_, node.getInfos().getY() + yOffset * yUnit_, text, hpos, vpos, angle);
+}
+
+void AbstractTreeDrawing::drawAtBranch(GraphicDevice& gDevice, const INode& node, const string& text, double xOffset, double yOffset, short hpos, short vpos, double angle) const
+{
+  if (node.hasFather()) {
+    gDevice.drawText((node.getInfos().getX() + node.getFather()->getInfos().getX()) / 2. + xOffset * xUnit_, node.getInfos().getY() + yOffset * yUnit_, text, hpos, vpos, angle);
+  }
+}  
+
diff --git a/src/Bpp/Phyl/Graphics/AbstractTreeDrawing.h b/src/Bpp/Phyl/Graphics/AbstractTreeDrawing.h
new file mode 100755
index 0000000..f0df0b1
--- /dev/null
+++ b/src/Bpp/Phyl/Graphics/AbstractTreeDrawing.h
@@ -0,0 +1,379 @@
+//
+// File: AbstractTreeDrawing.h
+// Created by: Julien Dutheil
+// Created on: Sun Oct 8 11:57 2006
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide
+graphic components to develop bioinformatics applications.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _ABSTRACTTREEDRAWING_H_
+#define _ABSTRACTTREEDRAWING_H_
+
+#include "../TreeTemplate.h"
+#include "../NodeTemplate.h"
+#include "TreeDrawing.h"
+#include "TreeDrawingListener.h"
+
+// From ths STL:
+#include <vector>
+#include <string>
+#include <memory>
+
+namespace bpp
+{
+
+class TreeDrawingNodeInfo
+{
+  private:
+    Point2D<double> pos_;
+    bool collapsed_;
+    
+  public:
+    TreeDrawingNodeInfo() : pos_(), collapsed_(false) {}
+    virtual ~TreeDrawingNodeInfo() {}
+        
+  public:
+    const Point2D<double>& getPosition() const { return pos_; }
+    Point2D<double>& getPosition() { return pos_; }
+    void setPosition(const Point2D<double>& position) { pos_ = position; }
+    double getX() const { return pos_.getX(); }
+    double getY() const { return pos_.getY(); }
+    void setX(double x) { pos_.setX(x); }
+    void setY(double y) { pos_.setY(y); }
+    void collapse(bool yn) { collapsed_ = yn; }
+    bool isCollapsed() const { return collapsed_; }
+};
+
+typedef NodeTemplate<TreeDrawingNodeInfo> INode;
+
+
+
+/**
+ * @brief Event class that uses INode object (more efficient than relying on nodes id, but less generic).
+ */
+class DrawINodeEvent :
+  public DrawNodeEvent
+{
+  private:
+    const INode* node_;
+
+  public:
+    DrawINodeEvent(const TreeDrawing* source, GraphicDevice* gd, const INode* node, const Cursor& cursor) :
+      DrawNodeEvent(source, gd, node->getId(), cursor),
+      node_(node)
+    {}
+
+    DrawINodeEvent(const DrawINodeEvent& dne) :
+      DrawNodeEvent(dne), node_(dne.node_)
+    {}
+    
+    DrawINodeEvent& operator=(const DrawINodeEvent& dne)
+    {
+      DrawNodeEvent::operator=(dne);
+      node_ = dne.node_;
+      return *this;
+    }
+
+  public:
+    const INode* getINode() const { return node_; }
+
+};
+
+
+
+/**
+ * @brief Event class that uses INode object (more efficient than relying on nodes id, but less generic).
+ */
+class DrawIBranchEvent :
+  public DrawBranchEvent
+{
+  private:
+    const INode* node_;
+
+  public:
+    DrawIBranchEvent(const TreeDrawing* source, GraphicDevice* gd, const INode* node, const Cursor& cursor) :
+      DrawBranchEvent(source, gd, node->getId(), cursor),
+      node_(node)
+    {}
+
+    DrawIBranchEvent(const DrawIBranchEvent& dne) :
+      DrawBranchEvent(dne), node_(dne.node_)
+    {}
+    
+    DrawIBranchEvent& operator=(const DrawIBranchEvent& dne)
+    {
+      DrawBranchEvent::operator=(dne);
+      node_ = dne.node_;
+      return *this;
+    }
+
+  public:
+    const INode* getINode() const { return node_; }
+
+};
+
+
+
+/**
+ * @brief Partial implementation of the TreeDrawing interface.
+ *
+ * This basic implementation uses a dedicated NodeInfo structure in combination with the NodeTemplate class.
+ * This structures stores the current coordinates of all nodes, so that it is easy to annotate the tree drawing.:if expand("%") == ""|browse confirm w|else|confirm w|endif
+ *
+ */
+class AbstractTreeDrawing:
+  public virtual TreeDrawing
+{
+  private:
+    std::auto_ptr<TreeTemplate<INode> > tree_;
+    double xUnit_;
+    double yUnit_;
+    const TreeDrawingSettings* settings_;
+    std::vector<TreeDrawingListener*> listeners_;
+ 
+  public:
+    AbstractTreeDrawing(): tree_(0), xUnit_(1.), yUnit_(1.), settings_(&DEFAULT_SETTINGS), listeners_() {};
+    
+    AbstractTreeDrawing(const AbstractTreeDrawing& atd) :
+      tree_(atd.tree_.get() ? dynamic_cast<TreeTemplate<INode> *>(atd.tree_->clone()) : 0),
+      xUnit_(atd.xUnit_),
+      yUnit_(atd.yUnit_),
+      settings_(atd.settings_),
+      listeners_(atd.listeners_.size())
+    {
+      for (unsigned int i = 0; i < listeners_.size(); ++i)
+      {
+        if (atd.listeners_[i]->isAutonomous())
+          listeners_[i] = atd.listeners_[i];
+        else
+          listeners_[i] = dynamic_cast<TreeDrawingListener*>(atd.listeners_[i]->clone());
+      }
+    }
+     
+    AbstractTreeDrawing& operator=(const AbstractTreeDrawing& atd)
+    {
+      if (atd.tree_.get())
+        tree_.reset(dynamic_cast<TreeTemplate<INode> *>(atd.tree_->clone()));
+      else tree_.reset();
+      xUnit_              = atd.xUnit_;
+      yUnit_              = atd.yUnit_;
+      settings_           = atd.settings_;
+      listeners_.resize(atd.listeners_.size());
+      for (unsigned int i = 0; i < listeners_.size(); ++i)
+      {
+        if (atd.listeners_[i]->isAutonomous())
+          listeners_[i] = atd.listeners_[i];
+        else
+          listeners_[i] = dynamic_cast<TreeDrawingListener*>(atd.listeners_[i]->clone());
+      }
+      return *this;
+    }
+
+    virtual ~AbstractTreeDrawing()
+    {
+      for (unsigned int i = 0; i < listeners_.size(); i++)
+        if (!listeners_[i]->isAutonomous())
+          delete listeners_[i];
+    }
+  
+  public:
+    
+    bool hasTree() const { return tree_.get() != 0; }
+
+#ifdef NO_VIRTUAL_COV
+    Tree*
+#else
+    const TreeTemplate<INode>*
+#endif
+    getTree() const { return tree_.get(); }
+    
+    void setTree(const Tree* tree)
+    {
+      if (tree_.get())
+        tree_.reset();
+      if (!tree) tree_.reset();
+      else
+      {
+        tree_.reset(new TreeTemplate<INode>(*tree)); //We copy the tree
+      }
+      treeHasChanged();
+    }
+    
+    Point2D<double> getNodePosition(int nodeId) const throw (NodeNotFoundException);
+
+    int getNodeAt(const Point2D<double>& position) const throw (NodeNotFoundException);
+ 
+    /**
+     * @brief Utilitary function, telling if a point belongs to a specified area.
+     *
+     * This method is used internally to get a node coordinates.
+     *
+     * @param p1 Point to look for.
+     * @param p2 Second point defining the center of the area.
+     * @return True if p1 belongs to the area defined by p2.
+     */
+    bool belongsTo(const Point2D<double>& p1, const Point2D<double>& p2) const;
+
+    /**
+     * @brief Draw some text at a particular node position.
+     *
+     * @param gDevice The GraphicDevice object on which to draw.
+     * @param node The node of interest.
+     * @param text The text to draw.
+     * @param xOffset Horizontal offset.
+     * @param yOffset Vertical offset.
+     * @param hpos The way the text should be aligned horizontally (see GraphicDevice).
+     * @param vpos The way the text should be aligned vertically (see GraphicDevice).
+     * @param angle The rotation value of the text.
+     */
+    virtual void drawAtNode(GraphicDevice& gDevice, const INode& node, const std::string& text,
+        double xOffset = 0, double yOffset = 0,
+        short hpos = GraphicDevice::TEXT_HORIZONTAL_LEFT, short vpos = GraphicDevice::TEXT_VERTICAL_CENTER, double angle = 0) const;
+
+    /**
+     * @brief Draw some text at a particular branch position.
+     *
+     * @param gDevice The GraphicDevice object on which to draw.
+     * @param node The node of interest.
+     * @param text The text to draw.
+     * @param xOffset Horizontal offset.
+     * @param yOffset Vertical offset.
+     * @param hpos The way the text should be aligned horizontally (see GraphicDevice).
+     * @param vpos The way the text should be aligned vertically (see GraphicDevice).
+     * @param angle The rotation value of the text.
+     */
+    virtual void drawAtBranch(GraphicDevice& gDevice, const INode& node, const std::string& text, double xOffset = 0, double yOffset = 0, short hpos = GraphicDevice::TEXT_HORIZONTAL_LEFT, short vpos = GraphicDevice::TEXT_VERTICAL_CENTER, double angle = 0) const;
+   
+    void setDisplaySettings(const TreeDrawingSettings* tds) throw (NullPointerException) {
+      if (!tds)
+        throw NullPointerException("AbstractTreeDrawing::setDisplaySettings. Null pointer provided.");
+      settings_ = tds;
+    }
+    const TreeDrawingSettings& getDisplaySettings() const { return *settings_; }
+
+    double getXUnit() const { return xUnit_; }
+    
+    double getYUnit() const { return yUnit_; }
+
+    void setXUnit(double xu) { xUnit_ = xu; }
+    
+    void setYUnit(double yu) { yUnit_ = yu; }
+
+    void collapseNode(int nodeId, bool yn) throw (NodeNotFoundException, Exception)
+    {
+      if(! tree_.get()) throw Exception("AbstractTreeDrawing::collapseNode. No tree is associated to the drawing.");
+      tree_->getNode(nodeId)->getInfos().collapse(yn);
+    }
+
+    bool isNodeCollapsed(int nodeId) const throw (NodeNotFoundException, Exception)
+    {
+      if(! tree_.get()) throw Exception("AbstractTreeDrawing::isNodeCollapsed. No tree is associated to the drawing.");
+      return tree_->getNode(nodeId)->getInfos().isCollapsed();
+    }
+
+    void addTreeDrawingListener(TreeDrawingListener* listener) throw (Exception)
+    {
+      if (find(listeners_.begin(), listeners_.end(), listener) != listeners_.end())
+        throw Exception("AbstractTreeDrawing::addTreeDrawingListener. Listener is already associated to this drawing.");
+      listeners_.push_back(listener);
+    }
+
+    void removeTreeDrawingListener(TreeDrawingListener* listener) throw (Exception)
+    {
+      std::vector<TreeDrawingListener*>::iterator it = std::find(listeners_.begin(), listeners_.end(), listener);
+      if (it == listeners_.end())
+        throw Exception("AbstractTreeDrawing::addTreeDrawingListener. Listener is not associated to this drawing, and therefore can't be removed.");
+      listeners_.erase(it);
+      if (!listener->isAutonomous())
+        delete listener;
+    }
+    
+    /**
+     * @brief Method to implement to deal with redrawing when the underlying tree has been modified.
+     */
+    virtual void treeHasChanged() = 0;
+
+  protected:
+    TreeTemplate<INode>* getTree_() { return tree_.get(); }
+    const TreeTemplate<INode>* getTree_() const { return tree_.get(); }
+ 
+    void fireBeforeTreeEvent_(const DrawTreeEvent& event) const
+    {
+      for (unsigned int i = 0; i < listeners_.size(); i++)
+        if (listeners_[i]->isEnabled())
+          listeners_[i]->beforeDrawTree(event);
+    }
+
+    void fireAfterTreeEvent_(const DrawTreeEvent& event) const
+    {
+      for (unsigned int i = 0; i < listeners_.size(); i++)
+        if (listeners_[i]->isEnabled())
+          listeners_[i]->afterDrawTree(event);
+    }
+
+    void fireBeforeNodeEvent_(const DrawINodeEvent& event) const
+    {
+      for (unsigned int i = 0; i < listeners_.size(); i++)
+        if (listeners_[i]->isEnabled())
+          listeners_[i]->beforeDrawNode(event);
+    }
+
+    void fireAfterNodeEvent_(const DrawINodeEvent& event) const
+    {
+      for (unsigned int i = 0; i < listeners_.size(); i++)
+        if (listeners_[i]->isEnabled())
+          listeners_[i]->afterDrawNode(event);
+    }
+
+    void fireBeforeBranchEvent_(const DrawIBranchEvent& event) const
+    {
+      for (unsigned int i = 0; i < listeners_.size(); i++)
+        if (listeners_[i]->isEnabled())
+          listeners_[i]->beforeDrawBranch(event);
+    }
+
+    void fireAfterBranchEvent_(const DrawIBranchEvent& event) const
+    {
+      for (unsigned int i = 0; i < listeners_.size(); i++)
+        if (listeners_[i]->isEnabled())
+          listeners_[i]->afterDrawBranch(event);
+    }
+  public:
+    static const TreeDrawingSettings DEFAULT_SETTINGS;
+};
+
+} //end of namespace bpp.
+
+#endif //_ABSTRACTTREEDRAWING_H_
+
diff --git a/src/Bpp/Phyl/Graphics/CladogramPlot.cpp b/src/Bpp/Phyl/Graphics/CladogramPlot.cpp
new file mode 100755
index 0000000..6795c47
--- /dev/null
+++ b/src/Bpp/Phyl/Graphics/CladogramPlot.cpp
@@ -0,0 +1,144 @@
+//
+// File: CladogramPlot.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Oct 9 17:22 2006
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide
+graphic components to develop bioinformatics applications.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "CladogramPlot.h"
+#include "../TreeTemplateTools.h"
+
+//From the STL:
+#include <memory>
+
+using namespace bpp;
+using namespace std;
+
+CladogramDrawBranchEvent::CladogramDrawBranchEvent(const TreeDrawing* source, GraphicDevice* gd, const INode* node, double length, const Cursor& cursor, short orientation) :
+  DrawIBranchEvent(source, gd, node, cursor), orientation_(), length_(length)
+{
+  orientation_ = (orientation == AbstractDendrogramPlot::ORIENTATION_LEFT_TO_RIGHT ? -1 : 1);
+}
+
+Cursor CladogramDrawBranchEvent::getBranchCursor(double position) const
+{
+  double offset = 0;
+  if (getINode()->hasDistanceToFather())
+  {
+    offset = orientation_ * length_ * position;
+  }
+  return getCursor().getTranslation(offset, 0);
+}
+
+void CladogramPlot::setTree(const Tree* tree)
+{
+  AbstractDendrogramPlot::setTree(tree);
+  if (hasTree())
+    totalDepth_ = static_cast<double>(TreeTemplateTools::getDepth(*getTree_()->getRootNode()));
+}
+
+void CladogramPlot::drawDendrogram_(GraphicDevice& gDevice) const throw (Exception)
+{
+  if (hasTree())
+  {
+    DrawTreeEvent treeEvent(this, &gDevice);
+    fireBeforeTreeEvent_(treeEvent);
+    unsigned int* tipCounter = new unsigned int(0);
+    double y;
+    recursivePlot_(gDevice, *const_cast<INode*>(getTree_()->getRootNode()),
+        getHorizontalOrientation() == ORIENTATION_LEFT_TO_RIGHT ? 0 : getWidth() * getXUnit(),
+        y,
+        getHorizontalOrientation() == ORIENTATION_LEFT_TO_RIGHT ? 1. : -1.,
+        getVerticalOrientation() == ORIENTATION_TOP_TO_BOTTOM ? 1. : -1.,
+        tipCounter);
+    fireAfterTreeEvent_(treeEvent);
+  }
+}
+
+void CladogramPlot::recursivePlot_(GraphicDevice& gDevice, INode& node, double x, double& y, double hDirection, double vDirection, unsigned int* tipCounter) const
+{
+  double depth = static_cast<double>(TreeTemplateTools::getDepth(node));
+  double x2 = ((getHorizontalOrientation() == ORIENTATION_LEFT_TO_RIGHT ? totalDepth_ : 0) - depth) * getXUnit() * hDirection;
+  auto_ptr<Cursor> cursor;
+  auto_ptr<DrawINodeEvent> nodeEvent;
+  auto_ptr<DrawIBranchEvent> branchEvent;
+  short hpos = (getHorizontalOrientation() == ORIENTATION_LEFT_TO_RIGHT ? GraphicDevice::TEXT_HORIZONTAL_LEFT : GraphicDevice::TEXT_HORIZONTAL_RIGHT);
+  if (node.isLeaf())
+  {
+    y = ((getVerticalOrientation() == ORIENTATION_TOP_TO_BOTTOM ? 0 : getHeight()) + static_cast<double>(*tipCounter) * vDirection) * getYUnit();
+    (*tipCounter)++;
+    cursor.reset(new Cursor(x2, y, 0, hpos));
+    nodeEvent.reset(new DrawINodeEvent(this, &gDevice, &node, *cursor));
+    fireBeforeNodeEvent_(*nodeEvent);
+  }
+  else if (node.getInfos().isCollapsed())
+  {
+    y = ((getVerticalOrientation() == ORIENTATION_TOP_TO_BOTTOM ? 0 : getHeight()) + static_cast<double>(*tipCounter) * vDirection) * getYUnit();
+    (*tipCounter)++;
+    cursor.reset(new Cursor(x2, y, 0, hpos));
+    nodeEvent.reset(new DrawINodeEvent(this, &gDevice, &node, *cursor));
+    fireBeforeNodeEvent_(*nodeEvent);
+  }
+  else
+  {
+    //Vertical line. Call the method on son nodes first:
+    double miny = 1000000; //(unsigned int)(-log(0));
+    double maxy = 0;
+    for(unsigned int i = 0; i < node.getNumberOfSons(); i++)
+    {
+      double yson;
+      recursivePlot_(gDevice, *node.getSon(i), x2, yson, hDirection, vDirection, tipCounter);
+      if(yson < miny) miny = yson;
+      if(yson > maxy) maxy = yson;
+    }
+    y = (maxy + miny) / 2.;
+    cursor.reset(new Cursor(x2, y, 0, hpos));
+    nodeEvent.reset(new DrawINodeEvent(this, &gDevice, &node, *cursor));
+    fireBeforeNodeEvent_(*nodeEvent);
+    gDevice.drawLine(x2, miny, x2, maxy);
+  }
+  //Actualize node infos:
+  node.getInfos().setX(x2);
+  node.getInfos().setY(y);  
+  nodeEvent.reset(new DrawINodeEvent(this, &gDevice, &node, *cursor));
+  fireAfterNodeEvent_(*nodeEvent);
+  
+  //Horizontal line
+  branchEvent.reset(new CladogramDrawBranchEvent(this, &gDevice, &node, x2 - x, *cursor, getHorizontalOrientation()));
+  fireBeforeBranchEvent_(*branchEvent);
+  gDevice.drawLine(x, y, x2, y);
+  fireAfterBranchEvent_(*branchEvent);
+}
+
diff --git a/src/Bpp/Phyl/Graphics/CladogramPlot.h b/src/Bpp/Phyl/Graphics/CladogramPlot.h
new file mode 100755
index 0000000..a7fee2e
--- /dev/null
+++ b/src/Bpp/Phyl/Graphics/CladogramPlot.h
@@ -0,0 +1,115 @@
+//
+// File: CladogramPlot.h
+// Created by: Julien Dutheil
+// Created on: Tue Oct 9 17:22 2006
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide
+graphic components to develop bioinformatics applications.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _CLADOGRAMPLOT_H_
+#define _CLADOGRAMPLOT_H_
+
+#include <Bpp/Exceptions.h>
+
+#include "AbstractDendrogramPlot.h"
+
+namespace bpp
+{
+
+class CladogramDrawBranchEvent :
+  public DrawIBranchEvent
+{
+  private:
+    double orientation_;
+    double length_;
+
+  public:
+    CladogramDrawBranchEvent(const TreeDrawing* source, GraphicDevice* gd, const INode* node, double length_, const Cursor& cursor, short orientation);
+
+  public:
+    Cursor getBranchCursor(double position) const;
+    
+};
+
+
+
+/**
+ * @brief Cladogram representation of trees.
+ *
+ * This representation is for trees without branch lengths.
+ */
+class CladogramPlot:
+  public AbstractDendrogramPlot
+{
+  private:
+    double totalDepth_;
+    double numberOfLeaves_;
+    
+  public:
+    CladogramPlot():
+      AbstractDendrogramPlot(), totalDepth_(0), numberOfLeaves_(0)
+    {}
+    
+    virtual ~CladogramPlot() {}
+    
+    CladogramPlot* clone() const { return new CladogramPlot(*this); }
+
+  public:
+    std::string getName() const { return "Cladogram"; }
+    
+    void setTree(const Tree* tree = 0);
+
+    double getWidth() const { return totalDepth_; }
+    double getHeight() const { return numberOfLeaves_; }
+
+    void treeHasChanged()
+    {
+      if (hasTree())
+      {
+        totalDepth_ = static_cast<double>(TreeTemplateTools::getDepth(*getTree_()->getRootNode()));  
+        numberOfLeaves_ = static_cast<double>(getTree_()->getNumberOfLeaves());
+      }
+    }
+ 
+      
+  private:
+    void drawDendrogram_(GraphicDevice& gDevice) const throw (Exception);
+    void recursivePlot_(GraphicDevice& gDevice, INode& node, double x, double& y, double hDirection, double vDirection, unsigned int* tipCounter) const;
+
+};
+
+} //end of namespace bpp.
+
+#endif //_CLADOGRAMPLOT_H_
+
diff --git a/src/Bpp/Phyl/Graphics/PhylogramPlot.cpp b/src/Bpp/Phyl/Graphics/PhylogramPlot.cpp
new file mode 100755
index 0000000..789c70e
--- /dev/null
+++ b/src/Bpp/Phyl/Graphics/PhylogramPlot.cpp
@@ -0,0 +1,171 @@
+//
+// File: PhylogramPlot.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Oct 3 20:52 2006
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide
+graphic components to develop bioinformatics applications.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "PhylogramPlot.h"
+#include "../TreeTemplateTools.h"
+
+using namespace bpp;
+
+#include <string>
+
+using namespace std;
+
+PhylogramDrawBranchEvent::PhylogramDrawBranchEvent(const TreeDrawing* source, GraphicDevice* gd, const INode* node, const Cursor& cursor, short orientation) :
+  DrawIBranchEvent(source, gd, node, cursor), orientation_()
+{
+  orientation_ = (orientation == AbstractDendrogramPlot::ORIENTATION_LEFT_TO_RIGHT ? -1 : 1);
+}
+
+Cursor PhylogramDrawBranchEvent::getBranchCursor(double position) const
+{
+  double offset = 0;
+  if (getINode()->hasDistanceToFather())
+  {
+    double l = getINode()->getDistanceToFather();
+    offset = orientation_ * l * position * getTreeDrawing()->getXUnit();
+  }
+  return getCursor().getTranslation(offset, 0);
+}
+
+void PhylogramPlot::setTree(const Tree* tree)
+{
+  AbstractDendrogramPlot::setTree(tree);
+  if (tree)
+  {
+    getTree_()->setVoidBranchLengths(0.);
+  }
+}
+
+void PhylogramPlot::drawDendrogram_(GraphicDevice& gDevice) const throw (Exception)
+{
+  if (hasTree())
+  {
+    DrawTreeEvent treeEvent(this, &gDevice);
+    fireBeforeTreeEvent_(treeEvent);
+    unsigned int* tipCounter = new unsigned int(0);
+    double y;
+    recursivePlot_(gDevice, *const_cast<INode*>(getTree_()->getRootNode()),
+        getHorizontalOrientation() == ORIENTATION_LEFT_TO_RIGHT ? 0 : getWidth() * getXUnit(),
+        y,
+        getHorizontalOrientation() == ORIENTATION_LEFT_TO_RIGHT ? 1. : -1.,
+        getVerticalOrientation() == ORIENTATION_TOP_TO_BOTTOM ? 1. : -1.,
+        tipCounter);
+    fireAfterTreeEvent_(treeEvent);
+  }
+}
+
+void PhylogramPlot::recursivePlot_(GraphicDevice& gDevice, INode& node, double x, double& y, double hDirection, double vDirection, unsigned int* tipCounter) const
+{
+  double x2;
+  bool drawBranch = true;
+  if (node.hasDistanceToFather())
+  {
+    double length = node.hasDistanceToFather() ? node.getDistanceToFather() : 0.;
+    if (length < -10000000)
+    {
+      x2 = x;
+      drawBranch = false;
+    }
+    else
+    {
+      x2 = x + hDirection * length * getXUnit();
+    }
+  }
+  else
+  {
+    x2 = x;
+    drawBranch = false;
+  }
+ 
+  auto_ptr<Cursor> cursor;
+  auto_ptr<DrawINodeEvent> nodeEvent;
+  auto_ptr<DrawIBranchEvent> branchEvent;
+  short hpos = (getHorizontalOrientation() == ORIENTATION_LEFT_TO_RIGHT ? GraphicDevice::TEXT_HORIZONTAL_LEFT : GraphicDevice::TEXT_HORIZONTAL_RIGHT);
+  if (node.isLeaf())
+  {
+    y = ((getVerticalOrientation() == ORIENTATION_TOP_TO_BOTTOM ? 0 : getHeight()) + static_cast<double>(*tipCounter) * vDirection) * getYUnit();
+    (*tipCounter)++;
+    cursor.reset(new Cursor(x2, y, 0, hpos));
+    nodeEvent.reset(new DrawINodeEvent(this, &gDevice, &node, *cursor));
+    fireBeforeNodeEvent_(*nodeEvent);
+  }
+  else if (node.getInfos().isCollapsed())
+  {
+    y = ((getVerticalOrientation() == ORIENTATION_TOP_TO_BOTTOM ? 0 : getHeight()) + static_cast<double>(*tipCounter) * vDirection) * getYUnit();
+    (*tipCounter)++;
+    cursor.reset(new Cursor(x2, y, 0, hpos));
+    nodeEvent.reset(new DrawINodeEvent(this, &gDevice, &node, *cursor));
+    fireBeforeNodeEvent_(*nodeEvent);
+  }
+  else
+  {
+    //Vertical line. Call the method on son nodes first:
+    double miny = 1000000; //(unsigned int)(-log(0));
+    double maxy = 0;
+    for (unsigned int i = 0; i < node.getNumberOfSons(); i++)
+    {
+      double yson;
+      recursivePlot_(gDevice, *node.getSon(i), x2, yson, hDirection, vDirection, tipCounter);
+      if(yson < miny) miny = yson;
+      if(yson > maxy) maxy = yson;
+    }
+    y = (maxy + miny) / 2.;
+    cursor.reset(new Cursor(x2, y, 0, hpos));
+    nodeEvent.reset(new DrawINodeEvent(this, &gDevice, &node, *cursor));
+    fireBeforeNodeEvent_(*nodeEvent);
+    gDevice.drawLine(x2, miny, x2, maxy);
+  }
+  
+  //Actualize node infos:
+  node.getInfos().setX(x2);
+  node.getInfos().setY(y);
+  nodeEvent.reset(new DrawINodeEvent(this, &gDevice, &node, *cursor));
+  fireAfterNodeEvent_(*nodeEvent);
+
+  if (drawBranch)
+  {
+    //Horizontal line
+    branchEvent.reset(new PhylogramDrawBranchEvent(this, &gDevice, &node, *cursor, getHorizontalOrientation()));
+    fireBeforeBranchEvent_(*branchEvent);
+    gDevice.drawLine(x, y, x2, y);
+    fireAfterBranchEvent_(*branchEvent);
+  }
+}
+
+
diff --git a/src/Bpp/Phyl/Graphics/PhylogramPlot.h b/src/Bpp/Phyl/Graphics/PhylogramPlot.h
new file mode 100755
index 0000000..6cf0c91
--- /dev/null
+++ b/src/Bpp/Phyl/Graphics/PhylogramPlot.h
@@ -0,0 +1,113 @@
+//
+// File: PhylogramPlot.h
+// Created by: Julien Dutheil
+// Created on: Tue Oct 3 20:52 2006
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide
+graphic components to develop bioinformatics applications.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _PHYLOGRAMPLOT_H_
+#define _PHYLOGRAMPLOT_H_
+
+#include "AbstractDendrogramPlot.h"
+
+namespace bpp
+{
+
+class PhylogramDrawBranchEvent :
+  public DrawIBranchEvent
+{
+  private:
+    double orientation_;
+
+  public:
+    PhylogramDrawBranchEvent(const TreeDrawing* source, GraphicDevice* gd, const INode* node, const Cursor& cursor, short orientation);
+
+  public:
+    Cursor getBranchCursor(double position) const;
+    
+};
+
+
+  
+/**
+ * @brief Phylogram representation of trees.
+ *
+ * This representation is for trees with branch lengths.
+ */
+class PhylogramPlot:
+  public AbstractDendrogramPlot
+{
+  private:
+    double totalDepth_;
+    double numberOfLeaves_;
+
+  public:
+    PhylogramPlot():
+      AbstractDendrogramPlot(), totalDepth_(0), numberOfLeaves_(0)
+    {}
+    
+    virtual ~PhylogramPlot() {}
+
+    PhylogramPlot* clone() const { return new PhylogramPlot(*this); }
+
+  public:
+    std::string getName() const { return "Phylogram"; }
+ 
+    void setTree(const Tree* tree = 0);
+    
+    double getWidth() const { return totalDepth_; }
+    double getHeight() const { return numberOfLeaves_; }
+
+    void treeHasChanged()
+    {
+      if (hasTree())
+      {
+        getTree_()->setVoidBranchLengths(0.);
+        totalDepth_ = TreeTemplateTools::getHeight(*getTree_()->getRootNode());
+        numberOfLeaves_ = static_cast<double>(getTree_()->getNumberOfLeaves());
+      }
+    }
+ 
+  private:
+    void drawDendrogram_(GraphicDevice& gDevice) const throw (Exception);
+ 
+    void recursivePlot_(GraphicDevice& gDevice, INode& node, double x, double& y, double hDirection, double vDirection, unsigned int* tipCounter) const;
+
+};
+
+} //end of namespace bpp.
+
+#endif //_PHYLOGRAMPLOT_H_
+
diff --git a/src/Bpp/Phyl/Graphics/TreeDrawing.h b/src/Bpp/Phyl/Graphics/TreeDrawing.h
new file mode 100644
index 0000000..6b14891
--- /dev/null
+++ b/src/Bpp/Phyl/Graphics/TreeDrawing.h
@@ -0,0 +1,403 @@
+//
+// File: TreeDrawing.h
+// Created by: Julien Dutheil
+// Created on: Sun Oct 8 11:57 2006
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide
+graphic components to develop bioinformatics applications.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _TREEDRAWING_H_
+#define _TREEDRAWING_H_
+
+#include <Bpp/Clonable.h>
+#include <Bpp/Graphics/GraphicDevice.h>
+#include <Bpp/Graphics/Point2D.h>
+#include <Bpp/Graphics/Font/Font.h>
+
+// From PhylLib:
+#include "../Tree.h"
+
+namespace bpp
+{
+
+//Forward declarations:
+class TreeDrawing;
+class TreeDrawingListener;
+
+/**
+ * @brief A set of options to tune the display of a TreeDrawing object.
+ */
+class TreeDrawingSettings
+{
+  public:
+    Font fontLeafNames;
+    Font fontBranchLengths;
+    Font fontBootstrapValues;
+    Font fontNodesId;
+    unsigned int pointSize;
+    double pointArea; //this specifies the radius of the point area
+    //More options will be added in the future...
+    
+  public:
+    TreeDrawingSettings() :
+      fontLeafNames("Courier", Font::STYLE_NORMAL, Font::WEIGHT_NORMAL, 12),
+      fontBranchLengths("Courier", Font::STYLE_ITALIC, Font::WEIGHT_NORMAL, 10),
+      fontBootstrapValues("Courier", Font::STYLE_NORMAL, Font::WEIGHT_NORMAL, 10),
+      fontNodesId("Courier", Font::STYLE_NORMAL, Font::WEIGHT_BOLD, 12),
+      pointSize(1),
+      pointArea(5)
+  {}
+};
+
+
+/**
+ * @brief Data structure describing a plotting direction.
+ */
+class Cursor
+{
+private:
+  double x_;
+  double y_;
+  double angle_;
+  short hpos_;
+  short vpos_;
+
+public:
+  Cursor(double x, double y, double angle = 0, short hpos = GraphicDevice::TEXT_HORIZONTAL_CENTER, short vpos = GraphicDevice::TEXT_VERTICAL_CENTER) :
+    x_(x), y_(y), angle_(angle), hpos_(hpos), vpos_(vpos) {}
+
+public:
+  double getX() const { return x_; }
+  double getY() const { return y_; }
+  double getAngle() const { return angle_; }
+  short getHPos() const { return hpos_; }
+  short getVPos() const { return vpos_; }
+  double addX(double increment) { return x_ += increment; }
+  double addY(double increment) { return y_ += increment; }
+
+  Cursor getTranslation(double x, double y) const
+  {
+    Cursor c = *this;
+    c.addX(x);
+    c.addY(y);
+    return c;
+  }
+
+};
+
+
+
+/**
+ * @brief Event class used by TreeDrawing classes.
+ */
+class DrawNodeEvent
+{
+  private:
+    const TreeDrawing* td_;
+    GraphicDevice* gd_;
+    int id_;
+    Cursor cursor_;
+
+  public:
+    DrawNodeEvent(const TreeDrawing* source, GraphicDevice* gd, int nodeId, const Cursor& cursor) :
+      td_(source), gd_(gd), id_(nodeId), cursor_(cursor)
+    {}
+
+    DrawNodeEvent(const DrawNodeEvent& dne) :
+      td_(dne.td_), gd_(dne.gd_), id_(dne.id_), cursor_(dne.cursor_)
+    {}
+    
+    DrawNodeEvent& operator=(const DrawNodeEvent& dne)
+    {
+      td_     = dne.td_;
+      gd_     = dne.gd_;
+      id_     = dne.id_;
+      cursor_ = dne.cursor_;
+      return *this;
+    }
+
+    virtual ~DrawNodeEvent() {}
+
+  public:
+    virtual const TreeDrawing* getTreeDrawing() const { return td_; }
+    virtual GraphicDevice* getGraphicDevice() const { return gd_; }
+    virtual int getNodeId() const { return id_; }
+    virtual const Cursor& getCursor() const { return cursor_; }
+
+};
+
+
+
+/**
+ * @brief Event class used by TreeDrawing classes.
+ */
+class DrawBranchEvent
+{
+  private:
+    const TreeDrawing* td_;
+    GraphicDevice* gd_;
+    int id_;
+    Cursor cursor_;
+
+  public:
+    DrawBranchEvent(const TreeDrawing* source, GraphicDevice* gd, int nodeId, const Cursor& cursor) :
+      td_(source), gd_(gd), id_(nodeId), cursor_(cursor)
+    {}
+
+    DrawBranchEvent(const DrawBranchEvent& dne) :
+      td_(dne.td_), gd_(dne.gd_), id_(dne.id_), cursor_(dne.cursor_)
+    {}
+    
+    DrawBranchEvent& operator=(const DrawBranchEvent& dne)
+    {
+      td_     = dne.td_;
+      gd_     = dne.gd_;
+      id_     = dne.id_;
+      cursor_ = dne.cursor_;
+      return *this;
+    }
+
+    virtual ~DrawBranchEvent() {}
+
+  public:
+    virtual const TreeDrawing* getTreeDrawing() const { return td_; }
+    virtual GraphicDevice* getGraphicDevice() const { return gd_; }
+    virtual int getNodeId() const { return id_; }
+    virtual const Cursor& getCursor() const { return cursor_; }
+    /**
+     * @return The coordinate of a point on the branch.
+     * @param position The position of the point on the branch, as a proportion of the total branch length.
+     */
+    virtual Cursor getBranchCursor(double position) const = 0;
+
+};
+
+
+
+/**
+ * @brief Event class used by TreeDrawing classes.
+ */
+class DrawTreeEvent
+{
+  private:
+    const TreeDrawing* td_;
+    GraphicDevice* gd_;
+
+  public:
+    DrawTreeEvent(const TreeDrawing* source, GraphicDevice* gd) :
+      td_(source), gd_(gd)
+    {}
+
+    DrawTreeEvent(const DrawTreeEvent& dne) :
+      td_(dne.td_), gd_(dne.gd_)
+    {}
+    
+    DrawTreeEvent& operator=(const DrawTreeEvent& dte)
+    {
+      td_     = dte.td_;
+      gd_     = dte.gd_;
+      return *this;
+    }
+
+    virtual ~DrawTreeEvent() {}
+
+  public:
+    virtual const TreeDrawing* getTreeDrawing() const { return td_; }
+    virtual GraphicDevice* getGraphicDevice() const { return gd_; }
+
+};
+
+
+
+/**
+ * @brief Basal interface for tree drawing classes.
+ *
+ * Basicly, a TreeDrawing object draw a graph of the tree and compute the coordinates
+ * of each node on the graph. These coordinates may be retrieved by dedicated functions.
+ * The drawing is performed on a GraphicDevice object.
+ *
+ * The TreeDrwing class is in charge of the tree reprensentation, and offer tools to retireve
+ * the coordinates of nodes. Using these functions to plot annotation may turn to be unefficient
+ * however, particularly for large trees, as they involve a search on the whole tree. For easier
+ * tuning of the drawing extensions, the interface defines the drawProperty,
+ * getSupportedDrawableProperties and isDrawable methods. These methods can be used to add features
+ * to the plot. Adding new features can then be performed by subclassing an existing algorithm
+ * and adding support for more properties.
+ *
+ * The TreeDrawing interface do not implies that the implementation works on a copy of the tree.
+ * It takes a constant pointer toward the tree to plot. Depending on the implementation however,
+ * the inheriting class may chose to store a copy of the tree for convenience. Refer to the
+ * documentation of the specific implementation you are using for details.
+ *
+ */
+class TreeDrawing:
+  public virtual Clonable
+{
+  public:
+    TreeDrawing() {}
+    virtual ~TreeDrawing() {}
+ 
+#ifndef NO_VIRTUAL_COV
+    TreeDrawing* clone() const = 0;
+#endif
+
+  public:
+    /**
+     * @return A string describing this drawing algorithm.
+     */
+    virtual std::string getName() const = 0;
+
+    /**
+     * @return 'True' if a tree is attached to this instance.
+     */
+    virtual bool hasTree() const = 0;
+
+    /**
+     * @return A pointer toward the tree associated to this drawing.
+     */
+    virtual const Tree* getTree() const = 0;
+    
+    /**
+     * @param tree A pointer toward the tree to associate with this drawing.
+     */
+    virtual void setTree(const Tree* tree) = 0;
+
+    /**
+     * @brief Set the 'horizontal' expansion unit.
+     *
+     * The effect of this expansion factor depends on the implementation of the interface.
+     * @param xu The horizontal unit length.
+     */
+    virtual void setXUnit(double xu) = 0; 
+
+    /**
+     * @brief Set the 'vertical' expansion unit.
+     *
+     * The effect of this expansion factor depends on the implementation of the interface.
+     * @param yu The vertical unit length.
+     */
+    virtual void setYUnit(double yu) = 0;
+
+    /**
+     * @return The horizontal unit length.
+     */
+    virtual double getXUnit() const = 0;
+    
+    /**
+     * @return The vertical unit length.
+     */
+    virtual double getYUnit() const = 0;
+
+    /**
+     * @return The total width of the drawing, in X units.
+     */
+    virtual double getWidth() const = 0; 
+
+    /**
+     * @return The total height of the drawing, in Y units.
+     */
+    virtual double getHeight() const = 0; 
+
+    /**
+     * @brief Plot the tree onto the specified device.
+     *
+     * @param gDevice An object implementing the GraphicDevice interface.
+     */
+    virtual void plot(GraphicDevice& gDevice) const throw (Exception) = 0;
+
+    /**
+     * @brief Get the position of a node.
+     *
+     * @param nodeId The identifier of the node.
+     * @return The localization of the node using the coordinate system of the last GraphicDevice used.
+     * @throw NodeNotFoundException If the node does not correspond to a node in the tree.
+     */
+    virtual Point2D<double> getNodePosition(int nodeId) const throw (NodeNotFoundException) = 0;
+
+    /**
+     * @brief Get the node corresponding to a position on the device.
+     *
+     * @param position A position in the coordinates system of the last GraphicDevice used.
+     * @return The corresponding node identifier if available.
+     * @throw NodeNotFoundException If the node does not correspond to a node in the tree.
+     */
+    virtual int getNodeAt(const Point2D<double>& position) const throw (NodeNotFoundException) = 0;
+
+    /**
+     * @brief Properties to draw.
+     *
+     * @{
+     */
+
+    /**
+     * @brief Collapsing nodes
+     *
+     * @{
+     */
+    virtual void collapseNode(int nodeId, bool yn) throw (NodeNotFoundException, Exception) = 0;
+    virtual bool isNodeCollapsed(int nodeId) const throw (NodeNotFoundException, Exception) = 0;
+    /** @} */
+
+    /**
+     * @brief Global drawing settings.
+     *
+     * @{
+     */
+    virtual void setDisplaySettings(const TreeDrawingSettings* tds) = 0;
+    virtual const TreeDrawingSettings& getDisplaySettings() const = 0;
+    /** @} */
+
+    /**
+     * @brief Add a drawing listener to this instance.
+     *
+     * @param listener a pointer toward an object implementing the TreeDrawingListener interface.
+     * This object will then be owned by the class and copied and deleted if/when needed, unless
+     * it is autonomous.
+     * @see TreeDrawingListener
+     */
+    virtual void addTreeDrawingListener(TreeDrawingListener* listener) = 0;
+     
+    /**
+     * @brief Remove a drawing listener from this instance.
+     *
+     * @param listener a pointer toward an object implementing the TreeDrawingListener interface.
+     * If the listener is autonomous, it will be deleted.
+     */
+    virtual void removeTreeDrawingListener(TreeDrawingListener* listener) = 0;
+    };
+
+} //end of namespace bpp.
+
+#endif //_TREEDRAWING_H_
+
diff --git a/src/Bpp/Phyl/Graphics/TreeDrawingDisplayControler.cpp b/src/Bpp/Phyl/Graphics/TreeDrawingDisplayControler.cpp
new file mode 100644
index 0000000..6e7e429
--- /dev/null
+++ b/src/Bpp/Phyl/Graphics/TreeDrawingDisplayControler.cpp
@@ -0,0 +1,74 @@
+//
+// File: TreeDrawingDisplayControler.cpp
+// Created by: Julien Dutheil
+// Created on: Tue May 18 12:37 2010
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (2010)
+
+This software is a computer program whose purpose is to provide
+graphic components to develop bioinformatics applications.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "TreeDrawingDisplayControler.h"
+
+using namespace bpp;
+using namespace std;
+
+TreeDrawingDisplayControler::~TreeDrawingDisplayControler()
+{
+  for (std::map<std::string, TreeDrawingListener*>::iterator it = listeners_.begin();
+    it != listeners_.end(); ++it)
+  {
+    for (unsigned int j = 0; j < registeredTreeDrawings_.size(); ++j)
+      registeredTreeDrawings_[j]->removeTreeDrawingListener(it->second);
+    delete it->second;
+  }
+}
+
+void TreeDrawingDisplayControler::addListener(const std::string& propertyName, TreeDrawingListener* listener) throw (Exception)
+{
+  if (listeners_.find(propertyName) != listeners_.end())
+    throw Exception("TreeDrawingDisplayControler::addListener. A listener is already added with this name: " + propertyName + ".");
+  if (!listener)
+    throw Exception("TreeDrawingDisplayControler::addListener. Trying to add a NULL listener!");
+  if (!listener->isAutonomous())
+    throw Exception("TreeDrawingDisplayControler::addListener. Trying to add a non-autonomous listener!");
+  listeners_[propertyName] = listener;
+  //Add listener to already registered tree drawings:
+  for (unsigned int i = 0; i < registeredTreeDrawings_.size(); ++i)
+    registeredTreeDrawings_[i]->addTreeDrawingListener(listener);
+}
+
+const string BasicTreeDrawingDisplayControler::PROPERTY_NODE_IDS         = "Node ids";
+const string BasicTreeDrawingDisplayControler::PROPERTY_LEAF_NAMES       = "Leaf names";
+const string BasicTreeDrawingDisplayControler::PROPERTY_BRANCH_LENGTHS   = "Branch lengths";
+const string BasicTreeDrawingDisplayControler::PROPERTY_BOOTSTRAP_VALUES = "Bootstrap values";
+
diff --git a/src/Bpp/Phyl/Graphics/TreeDrawingDisplayControler.h b/src/Bpp/Phyl/Graphics/TreeDrawingDisplayControler.h
new file mode 100644
index 0000000..1124dad
--- /dev/null
+++ b/src/Bpp/Phyl/Graphics/TreeDrawingDisplayControler.h
@@ -0,0 +1,182 @@
+//
+// File: TreeDrawingDisplayControler.h
+// Created by: Julien Dutheil
+// Created on: Tue May 18 12:37 2010
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (2010)
+
+This software is a computer program whose purpose is to provide
+graphic components to develop bioinformatics applications.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _TREEDRAWINGDISPLAYCONTROLER_H_
+#define _TREEDRAWINGDISPLAYCONTROLER_H_
+
+#include "TreeDrawingListener.h"
+
+//From the STL:
+#include <string>
+#include <vector>
+#include <map>
+#include <algorithm>
+
+namespace bpp {
+
+/**
+ * @brief Easy tune of tree drawings display.
+ *
+ * This class maintains a set of autonomous TreeDrawing listeners that
+ * are used for annotating a tree drawing.
+ *
+ * @author Julien Dutheil
+ */
+class TreeDrawingDisplayControler
+{
+  private:
+    std::map<std::string, TreeDrawingListener*> listeners_;
+    std::vector<TreeDrawing*> registeredTreeDrawings_;
+
+  public:
+    TreeDrawingDisplayControler() :
+      listeners_(), registeredTreeDrawings_()
+    {}
+
+  private:
+    TreeDrawingDisplayControler(const TreeDrawingDisplayControler& tddc) :
+      listeners_(), registeredTreeDrawings_(tddc.registeredTreeDrawings_)
+    {
+      for (std::map<std::string, TreeDrawingListener*>::const_iterator it = tddc.listeners_.begin();
+          it != tddc.listeners_.end(); ++it)
+      {
+        listeners_[it->first] = dynamic_cast<TreeDrawingListener*>(it->second->clone());
+      }
+    }
+    TreeDrawingDisplayControler& operator=(const TreeDrawingDisplayControler& tddc)
+    {
+      listeners_.clear();
+      registeredTreeDrawings_ = tddc.registeredTreeDrawings_;
+      for (std::map<std::string, TreeDrawingListener*>::const_iterator it = tddc.listeners_.begin();
+          it != tddc.listeners_.end(); ++it)
+      {
+        listeners_[it->first] = dynamic_cast<TreeDrawingListener*>(it->second->clone());
+      }
+      return *this;
+    }
+
+  public:
+    virtual ~TreeDrawingDisplayControler();
+
+  public:
+    /**
+     * @brief Add a listener to the controler. The controler then owns the object, and will
+     * copy or delete it when needed.
+     */
+    void addListener(const std::string& propertyName, TreeDrawingListener* listener) throw (Exception);
+
+    bool hasListenerFor(const std::string& propertyName) const
+    {
+      return listeners_.find(propertyName) != listeners_.end();
+    }
+
+    void enableListener(const std::string& propertyName, bool tf) throw (Exception)
+    {
+      if (!hasListenerFor(propertyName))
+        throw Exception("TreeDrawingDisplayControler::enableListener. No listener is registered for property " + propertyName + ".");
+      listeners_[propertyName]->enable(tf);
+    }
+
+    bool isListenerEnabled(const std::string& propertyName) const throw (Exception)
+    {
+      if (!hasListenerFor(propertyName))
+        throw Exception("TreeDrawingDisplayControler::enableListener. No listener is registered for property " + propertyName + ".");
+      return listeners_.find(propertyName)->second->isEnabled();
+    }
+
+    void registerTreeDrawing(TreeDrawing* td) throw (Exception)
+    {
+      if (std::find(registeredTreeDrawings_.begin(), registeredTreeDrawings_.end(), td) != registeredTreeDrawings_.end())
+        throw Exception("TreeDrawingDisplayControler::registerTreeDrawing. TreeDrawing is already associated to this controler.");
+      for (std::map<std::string, TreeDrawingListener*>::iterator it = listeners_.begin();
+          it != listeners_.end(); ++it)
+        td->addTreeDrawingListener(it->second);
+      registeredTreeDrawings_.push_back(td);
+    }
+
+};
+
+
+
+/**
+ * @brief Easy tune of tree drawings display, a basic implementation:
+ *
+ * This class maintains several "standard" drawing listener for:
+ * - Plotting node id,
+ * - Plotting leaves names,
+ * - Plotting branch lengths,
+ * - Plotting plotting bootstrap values.
+ *
+ * This controler takes as an argument a TreeDrawingSettings object that is used by
+ * all listeners that require one.
+ */
+class BasicTreeDrawingDisplayControler :
+  public TreeDrawingDisplayControler
+{
+  public:
+    static const std::string PROPERTY_NODE_IDS;
+    static const std::string PROPERTY_LEAF_NAMES;
+    static const std::string PROPERTY_BRANCH_LENGTHS;
+    static const std::string PROPERTY_BOOTSTRAP_VALUES;
+
+  private:
+    const TreeDrawingSettings* settings_;
+
+  public:
+    BasicTreeDrawingDisplayControler(const TreeDrawingSettings* settings) throw (NullPointerException) :
+      settings_(settings)
+    {
+      if (!settings)
+        throw NullPointerException("BasicTreeDrawingDisplayControler::constructor. Trying to use NULL settings.");
+      addListener(PROPERTY_NODE_IDS        , reinterpret_cast<TreeDrawingListener*>(new NodesIdTreeDrawingListener        (settings_, true)));
+      addListener(PROPERTY_LEAF_NAMES      , reinterpret_cast<TreeDrawingListener*>(new LeafNamesTreeDrawingListener      (settings_, true)));
+      addListener(PROPERTY_BRANCH_LENGTHS  , reinterpret_cast<TreeDrawingListener*>(new BranchLengthsTreeDrawingListener  (settings_, true)));
+      addListener(PROPERTY_BOOTSTRAP_VALUES, reinterpret_cast<TreeDrawingListener*>(new BootstrapValuesTreeDrawingListener(settings_, true)));
+    }
+
+  private:
+    BasicTreeDrawingDisplayControler(const BasicTreeDrawingDisplayControler&) : settings_(0) {}
+    BasicTreeDrawingDisplayControler& operator=(const BasicTreeDrawingDisplayControler&) { return *this; }
+
+};
+
+} //end of namespace bpp.
+
+#endif //_TREEDRAWINGDISPLAYCONTROLER_H_
+
diff --git a/src/Bpp/Phyl/Graphics/TreeDrawingListener.cpp b/src/Bpp/Phyl/Graphics/TreeDrawingListener.cpp
new file mode 100644
index 0000000..958f5a0
--- /dev/null
+++ b/src/Bpp/Phyl/Graphics/TreeDrawingListener.cpp
@@ -0,0 +1,247 @@
+//
+// File: TreeDrawingListener.cpp
+// Created by: Julien Dutheil
+// Created on: Tue May 18 10:33 2010
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (2010)
+
+This software is a computer program whose purpose is to provide
+graphic components to develop bioinformatics applications.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "TreeDrawingListener.h"
+#include "AbstractTreeDrawing.h"
+
+//From the STL:
+#include <string>
+#include <exception>
+#include <typeinfo>
+
+using namespace std;
+
+using namespace bpp;
+
+void NodesIdTreeDrawingListener::afterDrawNode(const DrawNodeEvent& event)
+{
+  GraphicDevice* gd = event.getGraphicDevice();
+  Cursor cursor     = event.getCursor();
+  Font fontBck      = gd->getCurrentFont();
+  if (settings_)
+    gd->setCurrentFont(settings_->fontNodesId);
+  string name = "#" + TextTools::toString(event.getNodeId());
+  gd->drawText(cursor.getX(), cursor.getY(), name, cursor.getHPos(), cursor.getVPos(), cursor.getAngle());
+  gd->setCurrentFont(fontBck);
+}
+
+void LeafNamesTreeDrawingListener::afterDrawNode(const DrawNodeEvent& event)
+{
+  try
+  {
+    //Pointer-based event (efficient):
+    const DrawINodeEvent& eventC = dynamic_cast<const DrawINodeEvent&>(event);
+    if (eventC.getINode()->isLeaf())
+    {
+      GraphicDevice* gd = event.getGraphicDevice();
+      Cursor cursor     = event.getCursor();
+      Font fontBck      = gd->getCurrentFont();
+      if (settings_)
+        gd->setCurrentFont(settings_->fontLeafNames);
+      string name = eventC.getINode()->getName();
+      gd->drawText(cursor.getX(), cursor.getY(), name, cursor.getHPos(), cursor.getVPos(), cursor.getAngle());
+      gd->setCurrentFont(fontBck);
+    }
+  }
+  catch (bad_cast& e)
+  {
+    //Id-based event (less-efficient):
+    const TreeDrawing* td = event.getTreeDrawing();
+    if (td->getTree()->isLeaf(event.getNodeId()))
+    {
+      GraphicDevice* gd = event.getGraphicDevice();
+      Cursor cursor     = event.getCursor();
+      Font fontBck      = gd->getCurrentFont();
+      if (settings_)
+        gd->setCurrentFont(settings_->fontLeafNames);
+      string name = td->getTree()->getNodeName(event.getNodeId());
+      gd->drawText(cursor.getX(), cursor.getY(), name, cursor.getHPos(), cursor.getVPos(), cursor.getAngle());
+      gd->setCurrentFont(fontBck);
+    }
+  }
+}
+
+void BranchLengthsTreeDrawingListener::afterDrawBranch(const DrawBranchEvent& event)
+{
+  try
+  {
+    //Pointer-based event (efficient):
+    const DrawINodeEvent& eventC = dynamic_cast<const DrawINodeEvent&>(event);
+    if (eventC.getINode()->hasDistanceToFather())
+    {
+      GraphicDevice* gd = event.getGraphicDevice();
+      Cursor cursor     = event.getBranchCursor(0.5);
+      Font fontBck      = gd->getCurrentFont();
+      if (settings_)
+        gd->setCurrentFont(settings_->fontBranchLengths);
+      gd->drawText(cursor.getX(), cursor.getY(),
+          TextTools::toString(eventC.getINode()->getDistanceToFather()),
+          GraphicDevice::TEXT_HORIZONTAL_CENTER, GraphicDevice::TEXT_VERTICAL_BOTTOM, cursor.getAngle());
+      gd->setCurrentFont(fontBck);
+    }
+  }
+  catch (std::bad_cast& e)
+  {
+    //Id-based event (less-efficient):
+    const TreeDrawing* td = event.getTreeDrawing();
+    if (td->getTree()->hasDistanceToFather(event.getNodeId()))
+    {
+      GraphicDevice* gd = event.getGraphicDevice();
+      Cursor cursor     = event.getBranchCursor(0.5);
+      Font fontBck      = gd->getCurrentFont();
+      if (settings_)
+        gd->setCurrentFont(settings_->fontLeafNames);
+      gd->drawText(cursor.getX(), cursor.getY(),
+          TextTools::toString(td->getTree()->getDistanceToFather(event.getNodeId())),
+          GraphicDevice::TEXT_HORIZONTAL_CENTER, GraphicDevice::TEXT_VERTICAL_BOTTOM, cursor.getAngle());
+      gd->setCurrentFont(fontBck);
+    }
+  }
+}
+
+void BootstrapValuesTreeDrawingListener::afterDrawBranch(const DrawBranchEvent& event)
+{
+  try
+  {
+    //Pointer-based event (efficient):
+    const DrawINodeEvent& eventC = dynamic_cast<const DrawINodeEvent&>(event);
+    if (eventC.getINode()->hasBranchProperty(TreeTools::BOOTSTRAP))
+    {
+      const Clonable* b = eventC.getINode()->getBranchProperty(TreeTools::BOOTSTRAP);
+      GraphicDevice* gd = event.getGraphicDevice();
+      Cursor cursor     = event.getCursor();
+      Font fontBck      = gd->getCurrentFont();
+      if (settings_)
+        gd->setCurrentFont(settings_->fontBranchLengths);
+      gd->drawText(cursor.getX(), cursor.getY(),
+          TextTools::toString(dynamic_cast<const Number<double> *>(b)->getValue()),
+          cursor.getHPos(), GraphicDevice::TEXT_VERTICAL_CENTER, cursor.getAngle());
+      gd->setCurrentFont(fontBck);
+    }
+  }
+  catch (std::bad_cast& e)
+  {
+    //Id-based event (less-efficient):
+    const TreeDrawing* td = event.getTreeDrawing();
+    if (td->getTree()->hasBranchProperty(event.getNodeId(), TreeTools::BOOTSTRAP))
+    {
+      const Clonable* b = td->getTree()->getBranchProperty(event.getNodeId(), TreeTools::BOOTSTRAP);
+      GraphicDevice* gd = event.getGraphicDevice();
+      Cursor cursor     = event.getCursor();
+      Font fontBck      = gd->getCurrentFont();
+      if (settings_)
+        gd->setCurrentFont(settings_->fontLeafNames);
+      gd->drawText(cursor.getX(), cursor.getY(),
+          TextTools::toString(dynamic_cast<const Number<double> *>(b)->getValue()),
+          cursor.getHPos(), GraphicDevice::TEXT_VERTICAL_CENTER, cursor.getAngle());
+      gd->setCurrentFont(fontBck);
+    }
+  }
+}
+
+void LabelInnerNodesTreeDrawingListener::afterDrawNode(const DrawNodeEvent& event)
+{
+  try
+  {
+    //Pointer-based event (efficient):
+    const DrawINodeEvent& eventC = dynamic_cast<const DrawINodeEvent&>(event);
+    if (!eventC.getINode()->getInfos().isCollapsed())
+    {
+      GraphicDevice* gd = event.getGraphicDevice();
+      Cursor cursor     = event.getCursor();
+      if (eventC.getINode()->hasName())
+      {
+        string name = eventC.getINode()->getName();
+        gd->drawText(cursor.getX(), cursor.getY(), name, cursor.getHPos(), cursor.getVPos(), cursor.getAngle());
+      }
+    }
+  }
+  catch(std::bad_cast& e)
+  {
+    //Id-based event (less-efficient):
+    const TreeDrawing* td = event.getTreeDrawing();
+    if (! td->isNodeCollapsed(event.getNodeId()))
+    {
+      GraphicDevice* gd = event.getGraphicDevice();
+      Cursor cursor     = event.getCursor();
+      if (td->getTree()->hasNodeName(event.getNodeId()))
+      {
+        string name = td->getTree()->getNodeName(event.getNodeId());
+        gd->drawText(cursor.getX(), cursor.getY(), name, cursor.getHPos(), cursor.getVPos(), cursor.getAngle());
+      }
+    }
+  }
+}
+
+void LabelCollapsedNodesTreeDrawingListener::afterDrawNode(const DrawNodeEvent& event)
+{
+  try
+  {
+    //Pointer-based event (efficient):
+    const DrawINodeEvent& eventC = dynamic_cast<const DrawINodeEvent&>(event);
+    if (eventC.getINode()->getInfos().isCollapsed())
+    {
+      GraphicDevice* gd = event.getGraphicDevice();
+      Cursor cursor     = event.getCursor();
+      size_t size       = TreeTemplateTools::getNumberOfLeaves(*eventC.getINode());
+      string text = "";
+      if (eventC.getINode()->hasName())
+        text += eventC.getINode()->getName() + " ";
+      text += "(" + TextTools::toString(size) + " leaves)";
+      gd->drawText(cursor.getX(), cursor.getY(), text, cursor.getHPos(), cursor.getVPos(), cursor.getAngle());
+    }
+  }
+  catch(std::bad_cast& e)
+  {
+    //Id-based event (less-efficient):
+    const TreeDrawing* td = event.getTreeDrawing();
+    if (td->isNodeCollapsed(event.getNodeId()))
+    {
+      GraphicDevice* gd = event.getGraphicDevice();
+      Cursor cursor     = event.getCursor();
+      size_t size = TreeTools::getNumberOfLeaves(*td->getTree(), event.getNodeId());
+      string text = "";
+      if (td->getTree()->hasNodeName(event.getNodeId()))
+        text += td->getTree()->getNodeName(event.getNodeId()) + " ";
+      text += "(" + TextTools::toString(size) + " leaves)";
+      gd->drawText(cursor.getX(), cursor.getY(), text, cursor.getHPos(), cursor.getVPos(), cursor.getAngle());
+    }
+  }
+}
+
diff --git a/src/Bpp/Phyl/Graphics/TreeDrawingListener.h b/src/Bpp/Phyl/Graphics/TreeDrawingListener.h
new file mode 100644
index 0000000..6b2f88a
--- /dev/null
+++ b/src/Bpp/Phyl/Graphics/TreeDrawingListener.h
@@ -0,0 +1,303 @@
+//
+// File: TreeDrawingListener.h
+// Created by: Julien Dutheil
+// Created on: Tue May 18 10:33 2010
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (2010)
+
+This software is a computer program whose purpose is to provide
+graphic components to develop bioinformatics applications.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _TREEDRAWINGLISTENER_H_
+#define _TREEDRAWINGLISTENER_H_
+
+#include "TreeDrawing.h"
+
+#include <Bpp/Clonable.h>
+
+namespace bpp {
+
+/**
+ * @brief Interface allowing to capture drawing events.
+ *
+ * Implementing this interface allows you to easily and efficiently tune a plot,
+ * and/or add elements to it.
+ */
+class TreeDrawingListener :
+  public virtual Clonable
+{
+public:
+#ifndef NO_VIRTUAL_COV
+  TreeDrawingListener*
+#else
+  Clonable*
+#endif
+  clone() const = 0;
+
+  virtual void beforeDrawTree(const DrawTreeEvent& event) = 0;
+  virtual void afterDrawTree(const DrawTreeEvent& event) = 0;
+  virtual void beforeDrawNode(const DrawNodeEvent& event) = 0;
+  virtual void afterDrawNode(const DrawNodeEvent& event) = 0;
+  virtual void beforeDrawBranch(const DrawBranchEvent& event) = 0;
+  virtual void afterDrawBranch(const DrawBranchEvent& event) = 0;
+
+  /**
+   * @brief Tells if the listener is autonomous. If so, it
+   * will never be hard-copied or deleted.
+   */
+  virtual bool isAutonomous() const = 0;
+
+  virtual bool isEnabled() const = 0;
+  virtual void enable(bool tf) = 0;
+};
+
+
+/**
+ * @brief An empty implementation of the TreeDrawingListener interface.
+ */
+class TreeDrawingListenerAdapter :
+  public virtual TreeDrawingListener
+{
+private:
+  bool autonomous_;
+  bool enabled_;
+
+public:
+  TreeDrawingListenerAdapter(bool autonomous) : autonomous_(autonomous), enabled_(true) {}
+
+public:
+  void beforeDrawTree(const DrawTreeEvent& event) {}
+  void afterDrawTree(const DrawTreeEvent& event) {}
+  void beforeDrawNode(const DrawNodeEvent& event) {}
+  void afterDrawNode(const DrawNodeEvent& event) {}
+  void beforeDrawBranch(const DrawBranchEvent& event) {}
+  void afterDrawBranch(const DrawBranchEvent& event) {}
+  bool isAutonomous() const { return autonomous_; }
+  bool isEnabled() const { return enabled_; }
+  void enable(bool tf) { enabled_ = tf; }
+};
+
+
+
+/**
+ * @brief A TreeDrawingListener implementation that writes nodes id.
+ */
+class NodesIdTreeDrawingListener :
+  public TreeDrawingListenerAdapter
+{
+private:
+  const TreeDrawingSettings* settings_;
+
+public:
+  NodesIdTreeDrawingListener(const TreeDrawingSettings* settings, bool autonomous = false) :
+    TreeDrawingListenerAdapter(autonomous),
+    settings_(settings)
+  {}
+
+  NodesIdTreeDrawingListener(const NodesIdTreeDrawingListener& lntdl) :
+    TreeDrawingListenerAdapter(lntdl),
+    settings_(lntdl.settings_) {}
+  
+  NodesIdTreeDrawingListener& operator=(const NodesIdTreeDrawingListener& lntdl)
+  {
+    TreeDrawingListenerAdapter::operator=(lntdl);
+    settings_ = lntdl.settings_;
+    return *this;
+  }
+
+  NodesIdTreeDrawingListener* clone() const { return new NodesIdTreeDrawingListener(*this); }
+
+public :    
+  void afterDrawNode(const DrawNodeEvent& event);
+
+};
+
+
+/**
+ * @brief A TreeDrawingListener implementation that write leaf names.
+ */
+class LeafNamesTreeDrawingListener :
+  public TreeDrawingListenerAdapter
+{
+private:
+  const TreeDrawingSettings* settings_;
+
+public:
+  LeafNamesTreeDrawingListener(const TreeDrawingSettings* settings, bool autonomous = false) :
+    TreeDrawingListenerAdapter(autonomous),
+    settings_(settings)
+  {}
+
+  LeafNamesTreeDrawingListener(const LeafNamesTreeDrawingListener& lntdl) :
+    TreeDrawingListenerAdapter(lntdl),
+    settings_(lntdl.settings_)
+  {}
+  
+  LeafNamesTreeDrawingListener& operator=(const LeafNamesTreeDrawingListener& lntdl)
+  {
+    TreeDrawingListenerAdapter::operator=(lntdl);
+    settings_   = lntdl.settings_;
+    return *this;
+  }
+
+  LeafNamesTreeDrawingListener* clone() const { return new LeafNamesTreeDrawingListener(*this); }
+
+public :    
+  void afterDrawNode(const DrawNodeEvent& event);
+
+};
+
+
+/**
+ * @brief A TreeDrawingListener implementation that write the branch lengths of inner nodes.
+ *
+ * Collapsed nodes are not labelled.
+ *
+ * This listener works with TreeDrawing classes, but is more efficient when used with a class that fires DrawINodeEvent events.
+ */
+class BranchLengthsTreeDrawingListener :
+  public TreeDrawingListenerAdapter
+{
+private:
+  const TreeDrawingSettings* settings_;
+
+public:
+  BranchLengthsTreeDrawingListener(const TreeDrawingSettings* settings, bool autonomous = false) :
+    TreeDrawingListenerAdapter(autonomous),
+    settings_(settings)
+  {}
+
+  BranchLengthsTreeDrawingListener(const BranchLengthsTreeDrawingListener& lntdl) :
+    TreeDrawingListenerAdapter(lntdl),
+    settings_(lntdl.settings_)
+  {}
+  
+  BranchLengthsTreeDrawingListener& operator=(const BranchLengthsTreeDrawingListener& lntdl)
+  {
+    TreeDrawingListenerAdapter::operator=(lntdl);
+    settings_   = lntdl.settings_;
+    return *this;
+  }
+
+  BranchLengthsTreeDrawingListener* clone() const { return new BranchLengthsTreeDrawingListener(*this); }
+
+public :    
+  void afterDrawBranch(const DrawBranchEvent& event);
+
+};
+
+
+/**
+ * @brief A TreeDrawingListener implementation that write the bootstrap values of inner nodes.
+ *
+ * Collapsed nodes are not labelled.
+ *
+ * This listener works with TreeDrawing classes, but is more efficient when used with a class that fires DrawINodeEvent events.
+ */
+class BootstrapValuesTreeDrawingListener :
+  public TreeDrawingListenerAdapter
+{
+private:
+  const TreeDrawingSettings* settings_;
+
+public:
+  BootstrapValuesTreeDrawingListener(const TreeDrawingSettings* settings, bool autonomous = false) :
+    TreeDrawingListenerAdapter(autonomous),
+    settings_(settings)
+  {}
+
+  BootstrapValuesTreeDrawingListener(const BootstrapValuesTreeDrawingListener& lntdl) :
+    TreeDrawingListenerAdapter(lntdl),
+    settings_(lntdl.settings_) {}
+  
+  BootstrapValuesTreeDrawingListener& operator=(const BootstrapValuesTreeDrawingListener& lntdl)
+  {
+    TreeDrawingListenerAdapter::operator=(lntdl);
+    settings_   = lntdl.settings_;
+    return *this;
+  }
+
+  BootstrapValuesTreeDrawingListener* clone() const { return new BootstrapValuesTreeDrawingListener(*this); }
+
+public :    
+  void afterDrawBranch(const DrawBranchEvent& event);
+
+};
+
+
+/**
+ * @brief A TreeDrawingListener implementation that write the names of inner nodes.
+ *
+ * Collapsed nodes are not labelled.
+ *
+ * This listener works with TreeDrawing classes, but is more efficient when used with a class that fires DrawINodeEvent events.
+ */
+class LabelInnerNodesTreeDrawingListener :
+  public TreeDrawingListenerAdapter
+{
+
+public:
+  LabelInnerNodesTreeDrawingListener(bool autonomous = false) :
+    TreeDrawingListenerAdapter(autonomous) {}
+
+  LabelInnerNodesTreeDrawingListener* clone() const { return new LabelInnerNodesTreeDrawingListener(*this); }
+
+public :    
+  void afterDrawNode(const DrawNodeEvent& event);
+
+};
+
+
+
+/**
+ * @brief A TreeDrawingListener implementation that label the collapsed nodes.
+ *
+ * This listener works with TreeDrawing classes, but is more efficient when used with a class that fires DrawINodeEvent events.
+ */
+class LabelCollapsedNodesTreeDrawingListener :
+  public TreeDrawingListenerAdapter
+{
+public:
+  LabelCollapsedNodesTreeDrawingListener(bool autonomous = false) :
+    TreeDrawingListenerAdapter(autonomous) {}
+
+  LabelCollapsedNodesTreeDrawingListener* clone() const { return new LabelCollapsedNodesTreeDrawingListener(*this); }
+
+public :    
+  void afterDrawNode(const DrawNodeEvent& event);
+
+};
+
+} //end of namespace bpp
+
+#endif //_TREEDRAWINGLISTENER_H_
+
diff --git a/src/Bpp/Phyl/Io/BppOFrequenciesSetFormat.cpp b/src/Bpp/Phyl/Io/BppOFrequenciesSetFormat.cpp
new file mode 100644
index 0000000..9761233
--- /dev/null
+++ b/src/Bpp/Phyl/Io/BppOFrequenciesSetFormat.cpp
@@ -0,0 +1,604 @@
+//
+// File: BppOFrequenciesSetFormatFormat.cpp
+// Created by: Laurent Guéguen
+// Created on: lundi 9 juillet 2012, à 12h 56
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "BppOFrequenciesSetFormat.h"
+
+
+#include "../Model/FrequenciesSet/NucleotideFrequenciesSet.h"
+#include "../Model/FrequenciesSet/ProteinFrequenciesSet.h"
+#include "../Model/FrequenciesSet/CodonFrequenciesSet.h"
+#include "../Model/FrequenciesSet/MvaFrequenciesSet.h"
+
+//From bpp-core:
+#include <Bpp/Io/FileTools.h>
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Text/StringTokenizer.h>
+#include <Bpp/Text/KeyvalTools.h>
+// #include <Bpp/Numeric/Prob.all>
+#include <Bpp/Numeric/AutoParameter.h>
+
+//From bpp-seq:
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+#include <Bpp/Seq/App/SequenceApplicationTools.h>
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iomanip>
+
+using namespace std;
+
+unsigned char BppOFrequenciesSetFormat::DNA = 1;
+unsigned char BppOFrequenciesSetFormat::RNA = 2;
+unsigned char BppOFrequenciesSetFormat::NUCLEOTIDE = 1 | 2;
+unsigned char BppOFrequenciesSetFormat::PROTEIN = 4;
+unsigned char BppOFrequenciesSetFormat::CODON = 8;
+unsigned char BppOFrequenciesSetFormat::WORD = 16;
+unsigned char BppOFrequenciesSetFormat::ALL = 1 | 2 | 4 | 8 | 16;
+
+FrequenciesSet* BppOFrequenciesSetFormat::read(const Alphabet* alphabet, const std::string& freqDescription, const SiteContainer* data, bool parseArguments)
+{
+  unparsedArguments_.clear();
+  string freqName;
+  map<string, string> args;
+  KeyvalTools::parseProcedure(freqDescription, freqName, args);
+  auto_ptr<FrequenciesSet> pFS;
+
+  if (freqName == "Fixed")
+  {
+    if (AlphabetTools::isNucleicAlphabet(alphabet))
+    {
+      if (alphabetCode_ & NUCLEOTIDE)
+        pFS.reset(new FixedNucleotideFrequenciesSet(dynamic_cast<const NucleicAlphabet*>(alphabet)));
+      else
+        throw Exception("Nucleotide alphabet not supported.");
+    }
+    else if (AlphabetTools::isProteicAlphabet(alphabet))
+    {
+      if (alphabetCode_ & PROTEIN)
+        pFS.reset(new FixedProteinFrequenciesSet(dynamic_cast<const ProteicAlphabet*>(alphabet)));
+      else
+        throw Exception("Protein alphabet not supported.");
+    }
+    else if (AlphabetTools::isCodonAlphabet(alphabet))
+    {
+      if (alphabetCode_ & CODON)
+        pFS.reset(new FixedCodonFrequenciesSet(dynamic_cast<const CodonAlphabet*>(alphabet)));
+      else
+        throw Exception("Codon alphabet not supported.");
+    }
+    else
+    {
+      pFS.reset(new FixedFrequenciesSet(alphabet, alphabet->getSize()));
+    }
+  }
+  else if (freqName == "Full")
+  {
+    if (AlphabetTools::isNucleicAlphabet(alphabet))
+    {
+      if (alphabetCode_ & NUCLEOTIDE)
+        pFS.reset(new FullNucleotideFrequenciesSet(dynamic_cast<const NucleicAlphabet*>(alphabet)));
+      else
+        throw Exception("Nucleotide alphabet not supported.");
+    }
+    else if (AlphabetTools::isProteicAlphabet(alphabet))
+    {
+      if (alphabetCode_ & PROTEIN)
+        pFS.reset(new FullProteinFrequenciesSet(dynamic_cast<const ProteicAlphabet*>(alphabet)));
+      else
+        throw Exception("Protein alphabet not supported.");
+    }
+    else if (AlphabetTools::isCodonAlphabet(alphabet))
+    {
+      if (alphabetCode_ & CODON)
+        pFS.reset(new FullCodonFrequenciesSet(dynamic_cast<const CodonAlphabet*>(alphabet)));
+      else
+        throw Exception("Codon alphabet not supported.");
+    }
+    else
+    {
+      pFS.reset(new FullFrequenciesSet(alphabet));
+    }
+  }
+  else if (freqName == "GC")
+  {
+    if (!AlphabetTools::isNucleicAlphabet(alphabet))
+      throw Exception("Error, unvalid frequencies " + freqName + " with non-nucleic alphabet.");
+    if (alphabetCode_ & NUCLEOTIDE)
+      pFS.reset(new GCFrequenciesSet(dynamic_cast<const NucleicAlphabet*>(alphabet)));
+    else
+      throw Exception("Nucleotide alphabet not supported.");
+  }
+
+  // INDEPENDENTWORD
+  else if (freqName == "Word")
+  {
+    if (!(alphabetCode_ & WORD))
+      throw Exception("Word alphabet not supported.");
+    if (!AlphabetTools::isWordAlphabet(alphabet))
+      throw Exception("BppOFrequenciesSetFormat::read(...).\n\t Bad alphabet type "
+                      + alphabet->getAlphabetType() + " for frequencies set " + freqName + ".");
+
+    const WordAlphabet* pWA = dynamic_cast<const WordAlphabet*>(alphabet);
+
+    if (args.find("frequency") != args.end())
+    {
+      string sAFS = args["frequency"];
+
+      unsigned int nbfreq = pWA->getLength();
+      string st = "";
+      for (unsigned i = 0; i < nbfreq; i++)
+      {
+        st += TextTools::toString(i + 1);
+      }
+
+      BppOFrequenciesSetFormat nestedReader(alphabetCode_, false);
+      auto_ptr<FrequenciesSet> pFS2(nestedReader.read(pWA->getNAlphabet(0), sAFS, data, false));
+      map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+      for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+      {
+        unparsedArguments_[st + "_" + it->first] = it->second;
+      }
+      pFS.reset(new WordFromUniqueFrequenciesSet(pWA, pFS2.release()));
+    }
+    else
+    {
+      if (args.find("frequency1") == args.end())
+        throw Exception("BppOFrequenciesSetFormat::read. Missing argument 'frequency' or 'frequency1' for frequencies set 'Word'.");
+      vector<string> v_sAFS;
+      vector<FrequenciesSet*> v_AFS;
+      unsigned int nbfreq = 1;
+
+      while (args.find("frequency" + TextTools::toString(nbfreq)) != args.end())
+      {
+        v_sAFS.push_back(args["frequency" + TextTools::toString(nbfreq++)]);
+      }
+
+      if (v_sAFS.size() != pWA->getLength())
+        throw Exception("BppOFrequenciesSetFormat::read. Number of frequencies (" + TextTools::toString(v_sAFS.size()) + ") does not match length of the words (" + TextTools::toString(pWA->getLength()) + ")");
+
+      for (unsigned i = 0; i < v_sAFS.size(); i++)
+      {
+        BppOFrequenciesSetFormat nestedReader(alphabetCode_, false);
+        pFS.reset(nestedReader.read(pWA->getNAlphabet(i), v_sAFS[i], data, false));
+        map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+        for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+        {
+          unparsedArguments_[TextTools::toString(i + 1) + "_" + it->first] = it->second;
+        }
+        v_AFS.push_back(pFS.release());
+      }
+
+      pFS.reset(new WordFromIndependentFrequenciesSet(pWA, v_AFS));
+    }
+  }
+  // INDEPENDENT CODON
+  else if (freqName == "Codon")
+  {
+    if (!(alphabetCode_ & CODON))
+      throw Exception("Codon alphabet not supported.");
+    if (!AlphabetTools::isCodonAlphabet(alphabet))
+      throw Exception("BppOFrequenciesSetFormat::read.\n\t Bad alphabet type "
+                      + alphabet->getAlphabetType() + " for frequenciesset " + freqName + ".");
+
+    const CodonAlphabet* pWA = dynamic_cast<const CodonAlphabet*>(alphabet);
+
+    if (args.find("frequency") != args.end())
+    {
+      string sAFS = args["frequency"];
+
+      BppOFrequenciesSetFormat nestedReader(alphabetCode_, false);
+      auto_ptr<FrequenciesSet> pFS2(nestedReader.read(pWA->getNAlphabet(0), sAFS, data, false));
+      map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+
+      for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+      {
+        unparsedArguments_["123_" + it->first] = it->second;
+      }
+      pFS.reset(new CodonFromUniqueFrequenciesSet(pWA, pFS2.release(), "Codon"));
+    }
+    else
+    {
+      if (args.find("frequency1") == args.end())
+        throw Exception("BppOFrequenciesSetFormat::read. Missing argument 'frequency' or 'frequency1' for frequencies set.");
+      vector<string> v_sAFS;
+      vector<FrequenciesSet*> v_AFS;
+      unsigned int nbfreq = 1;
+
+      while (args.find("frequency" + TextTools::toString(nbfreq)) != args.end())
+      {
+        v_sAFS.push_back(args["frequency" + TextTools::toString(nbfreq++)]);
+      }
+
+      if (v_sAFS.size() != 3)
+        throw Exception("BppOFrequenciesSetFormat::read. Number of frequencies (" + TextTools::toString(v_sAFS.size()) + ") is not three");
+
+      for (unsigned i = 0; i < v_sAFS.size(); i++)
+      {
+        BppOFrequenciesSetFormat nestedReader(alphabetCode_, false);
+        pFS.reset(nestedReader.read(pWA->getNAlphabet(i), v_sAFS[i], data, false));
+        map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+        for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+        {
+          unparsedArguments_[TextTools::toString(i + 1) + "_" + it->first] = it->second;
+        }
+        v_AFS.push_back(pFS.release());
+      }
+
+      pFS.reset(new CodonFromIndependentFrequenciesSet(pWA, v_AFS, "Codon"));
+    }
+  }
+
+  // CODON PER AA Frequencies
+  else if (freqName == "FullPerAA")
+  {
+    if (!(alphabetCode_ & CODON))
+      throw Exception("Codon alphabet not supported.");
+    if (!AlphabetTools::isCodonAlphabet(alphabet))
+      throw Exception("BppOFrequenciesSetFormat::read.\n\t Bad alphabet type "
+                      + alphabet->getAlphabetType() + " for frequenciesset " + freqName + ".");
+
+    const CodonAlphabet* pWA = dynamic_cast<const CodonAlphabet*>(alphabet);
+
+    if (args.find("genetic_code") == args.end())
+      args["genetic_code"] = pWA->getAlphabetType();
+
+    GeneticCode* pgc = SequenceApplicationTools::getGeneticCode(dynamic_cast<const NucleicAlphabet*>(pWA->getNAlphabet(0)), args["genetic_code"]);
+    if (pgc->getSourceAlphabet()->getAlphabetType() != pWA->getAlphabetType())
+      throw Exception("Mismatch between genetic code and codon alphabet");
+
+    const ProteicAlphabet* pPA = dynamic_cast<const ProteicAlphabet*>(pgc->getTargetAlphabet());
+
+    auto_ptr<ProteinFrequenciesSet> pPFS;
+
+    if (args.find("protein_frequencies") != args.end())
+    {
+      string sPFS = args["protein_frequencies"];
+      BppOFrequenciesSetFormat nestedReader(alphabetCode_, false);
+      pPFS.reset(dynamic_cast<ProteinFrequenciesSet*>(nestedReader.read(pPA, sPFS, data, false)));
+      map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+
+      for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+      {
+        unparsedArguments_["FullPerAA." + it->first] = it->second;
+      }
+      pFS.reset(new FullPerAACodonFrequenciesSet(pgc, pPFS.release()));
+    }
+    else
+      pFS.reset(new FullPerAACodonFrequenciesSet(pgc));
+  }
+
+  // codeml frequencies syntax
+  
+  else if (AlphabetTools::isCodonAlphabet(alphabet))
+  {
+    if (!(alphabetCode_ & CODON))
+      throw Exception("Codon alphabet not supported.");
+    const CodonAlphabet* pWA = dynamic_cast<const CodonAlphabet*>(alphabet);
+
+    short opt = -1;
+    string mgmtStopCodon="quadratic";
+    
+    if (freqName == "F0")
+    {
+      opt = CodonFrequenciesSet::F0;
+    }
+    else if (freqName == "F1X4")
+    {
+      opt = CodonFrequenciesSet::F1X4;
+      
+      if (args.find("mgmtStopCodon") != args.end()){
+        mgmtStopCodon = args["mgmtStopCodon"];
+        ApplicationTools::displayResult("StopCodon frequencies distribution ", mgmtStopCodon);
+      }
+      if (args.find("frequency") != args.end())
+        {
+          string sAFS = args["frequency"];
+
+          BppOFrequenciesSetFormat nestedReader(alphabetCode_, false);
+          auto_ptr<FrequenciesSet> pFS2(nestedReader.read(pWA->getNAlphabet(0), sAFS, data, false));
+          if (pFS2->getName()!="Full")
+            throw Exception("BppOFrequenciesSetFormat::read. The frequency option in F1X4 can only be Full");
+            
+          map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+
+          for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+            {
+              unparsedArguments_["123_" + it->first] = it->second;
+            }
+        }
+      if (args.find("123_theta") != args.end())
+          unparsedArguments_["123_Full.theta"] = args["123_theta"];
+      if (args.find("123_theta1") != args.end())
+        unparsedArguments_["123_Full.theta1"] = args["123_theta1"];
+      if (args.find("123_theta2") != args.end())
+        unparsedArguments_["123_Full.theta2"] = args["123_theta2"];
+    }
+    else if (freqName == "F3X4")
+    {
+      opt = CodonFrequenciesSet::F3X4;
+
+      if (args.find("mgmtStopCodon") != args.end()){
+        mgmtStopCodon = args["mgmtStopCodon"];
+        ApplicationTools::displayResult("StopCodon frequencies distribution ", mgmtStopCodon);
+      }
+
+      if (args.find("frequency1") != args.end() ||
+          args.find("frequency2") != args.end() ||
+          args.find("frequency3") != args.end())
+        {
+        vector<string> v_sAFS;
+
+        for (unsigned int nbfreq = 1; nbfreq<=3; nbfreq++)
+          if (args.find("frequency" + TextTools::toString(nbfreq)) != args.end())
+            v_sAFS.push_back(args["frequency" + TextTools::toString(nbfreq)]);
+          else
+            v_sAFS.push_back("");
+        
+        for (unsigned i = 0; i < v_sAFS.size(); i++)
+          {
+            BppOFrequenciesSetFormat nestedReader(alphabetCode_, false);
+            if (v_sAFS[i]!=""){
+              pFS.reset(nestedReader.read(pWA->getNAlphabet(i), v_sAFS[i], data, false));
+              if (pFS->getName()!="Full")
+                throw Exception("BppOFrequenciesSetFormat::read. The frequency options in F3X4 can only be Full");
+
+              map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+              for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+                {
+                  unparsedArguments_[TextTools::toString(i + 1) + "_" + it->first] = it->second;
+                }
+            }
+          }
+        }
+      for (unsigned int i = 1 ; i <= 3; i++){
+        
+        if (args.find(TextTools::toString(i)+"_theta") != args.end())
+          unparsedArguments_[TextTools::toString(i)+"_Full.theta"] = args[TextTools::toString(i)+"_theta"];
+        if (args.find(TextTools::toString(i)+"_theta1") != args.end())
+          unparsedArguments_[TextTools::toString(i)+"_Full.theta1"] = args[TextTools::toString(i)+"_theta1"];
+        if (args.find(TextTools::toString(i)+"_theta2") != args.end())
+          unparsedArguments_[TextTools::toString(i)+"_Full.theta2"] = args[TextTools::toString(i)+"_theta2"];
+      }
+    }
+    else if (freqName == "F61")
+    {
+      opt = CodonFrequenciesSet::F61;
+    }
+    if (opt != -1)
+      pFS.reset(CodonFrequenciesSet::getFrequenciesSetForCodons(opt, *dynamic_cast<const CodonAlphabet*>(alphabet), mgmtStopCodon));
+    else
+      throw Exception("Unknown frequency option: " + freqName);
+  }
+  
+  //MVAprotein freq set for COaLA model
+  else if (freqName == "MVAprotein")
+  {
+	  pFS.reset(new MvaFrequenciesSet(dynamic_cast<const ProteicAlphabet*>(alphabet)));
+	  dynamic_cast<MvaFrequenciesSet*>(pFS.get())->setParamValues(args);
+  }
+  else
+    throw Exception("Unknown frequency option: " + freqName);
+
+  vector<string> pnames = pFS->getParameters().getParameterNames();
+
+  string pref = pFS->getNamespace();
+  for (unsigned int i = 0; i < pnames.size(); i++)
+  {
+    string name = pFS->getParameterNameWithoutNamespace(pnames[i]);
+    if (args.find(name) != args.end())
+      unparsedArguments_[pref + name] = args[name];
+  }
+
+  // Forward arguments:
+  if (args.find("init") != args.end())
+  {
+    unparsedArguments_["init"] = args["init"];
+    unparsedArguments_["initFreqs"] = args["init"];
+  }
+  if (args.find("init.observedPseudoCount") != args.end())
+  {
+    unparsedArguments_["init.observedPseudoCount"] = args["init.observedPseudoCount"];
+    unparsedArguments_["initFreqs.observedPseudoCount"] = args["init.observedPseudoCount"];
+  }
+  if (args.find("values") != args.end())
+  {
+    unparsedArguments_["initFreqs"] = "values" + args["values"];
+    unparsedArguments_["init"] = "values" + args["values"];
+  }
+
+  if (parseArguments)
+    initialize_(*pFS, data);
+  return pFS.release();
+}
+
+void BppOFrequenciesSetFormat::write(const FrequenciesSet* pfreqset,
+                                     OutputStream& out,
+                                     std::vector<std::string>& writtenNames) const
+{
+  if (!pfreqset)
+  {
+    out << "None";
+    return;
+  }
+  ParameterList pl = pfreqset->getParameters();
+  unsigned int p = out.getPrecision();
+  out.setPrecision(12);
+  bool flag(false);
+  string name = pfreqset->getName();
+  out << name << "(";
+
+
+  if ((name == "Fixed") || (name == "F0"))
+  {
+    vector<double> vf = pfreqset->getFrequencies();
+    out << "values=(";
+    for (unsigned int i = 0; i < vf.size(); i++)
+    {
+      if (i != 0)
+        out << ", ";
+      out << vf[i];
+    }
+    out << ")";
+  }
+  else
+  {
+    if (name != "F1X4" && name != "F3X4" && name != "F61")
+    {
+      const WordFromIndependentFrequenciesSet* pWFI = dynamic_cast<const WordFromIndependentFrequenciesSet*>(pfreqset);
+      if (pWFI != NULL)
+      {
+        for (unsigned int i = 0; i < pWFI->getLength(); i++)
+        {
+          if (i != 0)
+            out << ", ";
+          out << "frequency" << i + 1 << "=";
+          write(&pWFI->getFrequenciesSetForLetter(i), out, writtenNames);
+        }
+        flag = true;
+      }
+      const WordFromUniqueFrequenciesSet* pWFU = dynamic_cast<const WordFromUniqueFrequenciesSet*>(pfreqset);
+      if (pWFU != NULL)
+      {
+        for (unsigned int i = 0; i < pWFU->getLength(); i++)
+        {
+          if (i != 0)
+            out << ", ";
+          out << "frequency=";
+          write(&pWFU->getFrequenciesSetForLetter(i), out, writtenNames);
+        }
+        flag = true;
+      }
+      const FullPerAACodonFrequenciesSet* pFPA=dynamic_cast<const FullPerAACodonFrequenciesSet*>(pfreqset);
+      if (pFPA != NULL)
+        {
+          const ProteinFrequenciesSet* ppfs=pFPA->getProteinFrequenciesSet();
+          out << "protein_frequencies=";
+          
+          write(ppfs, out, writtenNames);
+      
+          flag = true;
+        }
+    }
+
+    for (unsigned int i = 0; i < pl.size(); i++)
+      {
+        if (find(writtenNames.begin(), writtenNames.end(), pl[i].getName()) == writtenNames.end())
+          {
+            if (flag)
+              out << ",";
+            else
+              flag = true;
+            string pname = pfreqset->getParameterNameWithoutNamespace(pl[i].getName());
+            (out << pname << "=").enableScientificNotation(false) << pl[i].getValue();
+            writtenNames.push_back(pl[i].getName());
+          }
+      }
+  }
+  
+  out << ")";
+  out.setPrecision(p);
+}
+
+void BppOFrequenciesSetFormat::initialize_(FrequenciesSet& freqSet, const SiteContainer* data)
+{
+  if (unparsedArguments_.find("init") != unparsedArguments_.end())
+  {
+    // Initialization using the "init" option
+    string init = unparsedArguments_["init"];
+    if (init == "observed")
+    {
+      if (!data)
+        throw Exception("Missing data for observed frequencies");
+      unsigned int psc = 0;
+      if (unparsedArguments_.find("observedPseudoCount") != unparsedArguments_.end())
+        psc = TextTools::toInt(unparsedArguments_["observedPseudoCount"]);
+
+      map<int, double> freqs;
+      SequenceContainerTools::getFrequencies(*data, freqs, psc);
+
+      freqSet.setFrequenciesFromMap(freqs);
+    }
+    else if (init.substr(0, 6) == "values")
+    {
+      // Initialization using the "values" argument
+      vector<double> frequencies;
+      string rf = init.substr(6);
+
+      StringTokenizer strtok(rf.substr(1, rf.length() - 2), ",");
+      while (strtok.hasMoreToken())
+        frequencies.push_back(TextTools::toDouble(strtok.nextToken()));
+      freqSet.setFrequencies(frequencies);
+    }
+    else if (init == "balanced")
+    {
+      // Nothing to do here, this is the default instanciation.
+    }
+    else
+      throw Exception("Unknown init argument");
+  }
+  else
+  {
+    // Explicit initialization of each parameter
+    ParameterList pl = freqSet.getParameters();
+
+    for (unsigned int i = 0; i < pl.size(); i++)
+    {
+      AutoParameter ap(pl[i]);
+      if (verbose_)
+        ap.setMessageHandler(ApplicationTools::warning);
+      pl.setParameter(i, ap);
+    }
+
+    for (unsigned int i = 0; i < pl.size(); i++)
+    {
+      const string pName = pl[i].getName();
+      double value = ApplicationTools::getDoubleParameter(pName, unparsedArguments_, pl[i].getValue());
+
+      pl[i].setValue(value);
+      if (verbose_)
+        ApplicationTools::displayResult("Parameter found", pName + "=" + TextTools::toString(pl[i].getValue()));
+    }
+
+    freqSet.matchParametersValues(pl);
+  }
+}
+
+
diff --git a/src/Bpp/Phyl/Io/BppOFrequenciesSetFormat.h b/src/Bpp/Phyl/Io/BppOFrequenciesSetFormat.h
new file mode 100644
index 0000000..e50b435
--- /dev/null
+++ b/src/Bpp/Phyl/Io/BppOFrequenciesSetFormat.h
@@ -0,0 +1,100 @@
+//
+// File: Bpp0FrequenciesSetFormat.h
+// Created by: Laurent Guéguen
+// Created on: lundi 9 juillet 2012, à 12h 57
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _BPPOFREQUENCIESSETFORMAT_H_
+#define _BPPOFREQUENCIESSETFORMAT_H_
+
+#include "IoFrequenciesSetFactory.h"
+
+namespace bpp
+{
+/**
+ * @brief Substitution model I/O in BppO format.
+ *
+ * Creates a new substitution model object according to model description syntax
+ * (see the Bio++ Progam Suite manual for a detailed description of this syntax).
+ *
+ */
+class BppOFrequenciesSetFormat :
+  public virtual IFrequenciesSet,
+  public virtual OFrequenciesSet
+{
+public:
+  static unsigned char DNA;
+  static unsigned char RNA;
+  static unsigned char NUCLEOTIDE;
+  static unsigned char PROTEIN;
+  static unsigned char CODON;
+  static unsigned char WORD;
+  static unsigned char ALL;
+
+private:
+  unsigned char alphabetCode_;
+  bool verbose_;
+  std::map<std::string, std::string> unparsedArguments_;
+
+public:
+  BppOFrequenciesSetFormat(unsigned char alphabetCode, bool verbose):
+    alphabetCode_(alphabetCode), verbose_(verbose), unparsedArguments_() {}
+  virtual ~BppOFrequenciesSetFormat() {}
+
+public:
+  const std::string getFormatName() const { return "BppO"; }
+
+  const std::string getFormatDescription() const { return "Bpp Options format."; }
+
+  FrequenciesSet* read(const Alphabet* alphabet,
+                       const std::string& freqDescription,
+                       const SiteContainer* data,
+                       bool parseArguments = true);
+
+  const std::map<std::string, std::string>& getUnparsedArguments() const { return unparsedArguments_; }
+
+  void write(const FrequenciesSet* pfreqset,
+             OutputStream& out,
+             std::vector<std::string>& writtenNames) const;
+
+private:
+  void initialize_(FrequenciesSet& freqSet, const SiteContainer* data);
+};
+
+} // end of namespace bpp.
+
+#endif // _BPPOFREQUENCIESSETFORMAT_H_
+
diff --git a/src/Bpp/Phyl/Io/BppORateDistributionFormat.cpp b/src/Bpp/Phyl/Io/BppORateDistributionFormat.cpp
new file mode 100644
index 0000000..5282803
--- /dev/null
+++ b/src/Bpp/Phyl/Io/BppORateDistributionFormat.cpp
@@ -0,0 +1,361 @@
+//
+// File: BppORateDistributionFormat.cpp
+// Created by: Laurent Guéguen and Julien Dutheil
+// Created on: Fri 16 november 2012, at 13:44
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "BppORateDistributionFormat.h"
+#include "../Model/RateDistribution/ConstantRateDistribution.h"
+#include "../Model/RateDistribution/GammaDiscreteRateDistribution.h"
+#include "../Model/RateDistribution/GaussianDiscreteRateDistribution.h"
+#include "../Model/RateDistribution/ExponentialDiscreteRateDistribution.h"
+
+//From bpp-core:
+#include <Bpp/Text/KeyvalTools.h>
+#include <Bpp/Numeric/Prob/InvariantMixedDiscreteDistribution.h>
+#include <Bpp/Numeric/Prob/SimpleDiscreteDistribution.h>
+#include <Bpp/Numeric/Prob/MixtureOfDiscreteDistributions.h>
+#include <Bpp/Io/BppOParametrizableFormat.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iomanip>
+
+using namespace std;
+
+
+DiscreteDistribution* BppORateDistributionFormat::read(
+    const std::string& distDescription,
+    bool parseArguments)
+{
+  unparsedArguments_.clear();
+  string distName;
+  map<string, string> args;
+  KeyvalTools::parseProcedure(distDescription, distName, args);
+  auto_ptr<DiscreteDistribution> rDist;
+
+  if (distName == "Uniform")
+    throw Exception("BppO Warning: Uniform distribution is deprecated, use Constant instead.");
+
+  if ((distName == "InvariantMixed") || (distName == "Invariant"))
+  {
+    // We have to parse the nested distribution first:
+    string nestedDistDescription = args["dist"];
+    if (TextTools::isEmpty(nestedDistDescription))
+      throw Exception("BppORateDistributionFormat::read. Missing argument 'dist' for distribution 'Invariant'.");
+    if (verbose_)
+      ApplicationTools::displayResult("Invariant Mixed distribution", distName );
+    BppORateDistributionFormat nestedReader(false);
+    DiscreteDistribution* nestedDistribution = nestedReader.read(nestedDistDescription, false);
+    map<string, string> unparsedArgumentsNested(nestedReader.getUnparsedArguments());
+
+    // Now we create the Invariant rate distribution:
+    rDist.reset(new InvariantMixedDiscreteDistribution(nestedDistribution, 0.1, 0.000001));
+
+    // Then we update the parameter set:
+    for (map<string, string>::iterator it = unparsedArgumentsNested.begin();
+         it != unparsedArgumentsNested.end(); it++)
+    {
+      unparsedArguments_["Invariant." + it->first] = it->second;
+    }
+
+    if (args.find("p") != args.end())
+      unparsedArguments_["Invariant.p"] = args["p"];
+  }
+  else if (distName == "Constant")
+  {
+    if (!allowConstant_)
+      throw Exception("BppORateDistributionFormat::read(). Constant distribution not allowed.");
+
+    if (args.find("value") != args.end())
+      throw Exception("Found argument 'value' in Constant distribution. Constant distribution is defined to have an average of 1.");
+    rDist.reset(new ConstantRateDistribution());
+  }
+  else if (distName == "Simple")
+  {
+    if (args.find("values") == args.end())
+      throw Exception("Missing argument 'values' in Simple distribution");
+    if (args.find("probas") == args.end())
+      throw Exception("Missing argument 'probas' in Simple distribution");
+    vector<double> probas, values;
+
+    string rf = args["values"];
+    StringTokenizer strtok(rf.substr(1, rf.length() - 2), ",");
+    while (strtok.hasMoreToken())
+      values.push_back(TextTools::toDouble(strtok.nextToken()));
+
+    rf = args["probas"];
+    StringTokenizer strtok2(rf.substr(1, rf.length() - 2), ",");
+    while (strtok2.hasMoreToken())
+      probas.push_back(TextTools::toDouble(strtok2.nextToken()));
+
+    std::map<size_t, std::vector<double> > ranges;
+
+    if (args.find("ranges") != args.end())
+    {
+      string rr = args["ranges"];
+      StringTokenizer strtok3(rr.substr(1, rr.length() - 2), ",");
+      string desc;
+      double deb, fin;
+      size_t num;
+      size_t po, pf, ppv;
+      while (strtok3.hasMoreToken())
+      {
+        desc = strtok3.nextToken();
+        po = desc.find("[");
+        ppv = desc.find(";");
+        pf = desc.find("]");
+        num = (size_t)(TextTools::toInt(desc.substr(1, po - 1)));
+        deb = TextTools::toDouble(desc.substr(po + 1, ppv - po - 1));
+        fin = TextTools::toDouble(desc.substr(ppv + 1, pf - ppv - 1));
+        vector<double> vd;
+        vd.push_back(deb);
+        vd.push_back(fin);
+        ranges[num] = vd;
+      }
+    }
+    if (ranges.size() == 0)
+      rDist.reset(new SimpleDiscreteDistribution(values, probas));
+    else
+      rDist.reset(new SimpleDiscreteDistribution(values, ranges, probas));
+
+    vector<string> v = rDist->getParameters().getParameterNames();
+
+    for (size_t i = 0; i < v.size(); i++)
+    {
+      unparsedArguments_[v[i]] = TextTools::toString(rDist->getParameterValue(rDist->getParameterNameWithoutNamespace(v[i])));
+    }
+  }
+  else if (distName == "Mixture")
+  {
+    if (args.find("probas") == args.end())
+      throw Exception("Missing argument 'probas' in Mixture distribution");
+    vector<double> probas;
+    vector<DiscreteDistribution*> v_pdd;
+    string rf = args["probas"];
+    StringTokenizer strtok2(rf.substr(1, rf.length() - 2), ",");
+    while (strtok2.hasMoreToken())
+      probas.push_back(TextTools::toDouble(strtok2.nextToken()));
+
+    vector<string> v_nestedDistrDescr;
+
+    size_t nbd = 0;
+    while (args.find("dist" + TextTools::toString(++nbd)) != args.end())
+      v_nestedDistrDescr.push_back(args["dist" + TextTools::toString(nbd)]);
+
+    if (v_nestedDistrDescr.size() != probas.size())
+      throw Exception("Number of distributions (keyword 'dist" + TextTools::toString(probas.size()) + "') do not fit the number of probabilities");
+
+    for (unsigned i = 0; i < v_nestedDistrDescr.size(); i++)
+    {
+      BppORateDistributionFormat nestedReader(false);
+      auto_ptr<DiscreteDistribution> pdd(nestedReader.read(v_nestedDistrDescr[i], false));
+      map<string, string> unparsedArgumentsNested(nestedReader.getUnparsedArguments());
+
+      for (map<string, string>::iterator it = unparsedArgumentsNested.begin(); it != unparsedArgumentsNested.end(); it++)
+      {
+        unparsedArguments_[distName + "." + TextTools::toString(i + 1) + "_" + it->first] = it->second;
+      }
+      v_pdd.push_back(pdd.release());
+    }
+    rDist.reset(new MixtureOfDiscreteDistributions(v_pdd, probas));
+  }
+  else
+  {
+    if (args.find("n") == args.end())
+      throw Exception("Missing argument 'n' (number of classes) in " + distName
+                      + " distribution");
+    size_t nbClasses = TextTools::to<size_t>(args["n"]);
+
+    if (distName == "Gamma")
+    {
+      rDist.reset(new GammaDiscreteRateDistribution(nbClasses, 1.));
+
+      if (args.find("alpha") != args.end())
+        unparsedArguments_["Gamma.alpha"] = args["alpha"];
+      if (args.find("beta") != args.end())
+        throw Exception("Found argument 'beta' in Gamma distribution. Gamma distribution is defined to have an average of 1, with beta=alpha.");
+    }
+    else if (distName == "Gaussian")
+    {
+      rDist.reset(new GaussianDiscreteRateDistribution(nbClasses, 1));
+      if (args.find("mu") != args.end())
+        throw Exception("Found argument 'mu' in Gaussian distribution. Gaussian distribution is defined to have an average of 1, with mu=1.");
+      if (args.find("sigma") != args.end())
+        unparsedArguments_["Gaussian.sigma"] = args["sigma"];
+    }
+    else if (distName == "Exponential")
+    {
+      rDist.reset(new ExponentialDiscreteRateDistribution(nbClasses));
+      if (args.find("lambda") != args.end())
+        throw Exception("Found argument 'lambda' in Exponential distribution. Exponential distribution is defined to have an average of 1, with lambda=1.");
+    }
+    else
+    {
+      throw Exception("Unsupported rate distribution: " + distName + ".");
+    }
+  }
+  if (verbose_)
+  {
+    ApplicationTools::displayResult("Distribution", distName);
+    ApplicationTools::displayResult("Number of classes", TextTools::toString(rDist->getNumberOfCategories()));
+  }
+
+  if (parseArguments)
+    initialize_(*rDist);
+
+  return rDist.release();
+}
+
+
+void BppORateDistributionFormat::write(
+    const DiscreteDistribution& dist,
+    OutputStream& out,
+    std::map<std::string, std::string>& globalAliases,
+    std::vector<std::string>& writtenNames) const
+{
+  bool comma = false;
+
+  const DiscreteDistribution* pd;
+
+  out << dist.getName() + "(";
+
+  const InvariantMixedDiscreteDistribution* invar = dynamic_cast<const InvariantMixedDiscreteDistribution*>(&dist);
+  if (invar)
+  {
+    pd = invar->getVariableSubDistribution();
+    out << "dist=";
+    write(*pd, out, globalAliases, writtenNames);
+    comma = true;
+  }
+  else
+  {
+    const MixtureOfDiscreteDistributions* mix = dynamic_cast<const MixtureOfDiscreteDistributions*>(&dist);
+    if (mix)
+    {
+      size_t nd = mix->getNumberOfDistributions();
+      for (size_t i = 0; i < nd; i++)
+      {
+        if (comma)
+          out << ",";
+        out << "dist" + TextTools::toString(i + 1) + "=";
+        write(*mix->getNDistribution(i), out, globalAliases, writtenNames);
+        comma = true;
+      }
+      out << ",probas=(";
+      for (size_t i = 0; i < nd; i++)
+      {
+        out << mix->getNProbability(i);
+        if (i != nd - 1)
+          out << ",";
+      }
+      out << ")";
+      for (size_t i = 1; i < nd; i++)
+      {
+        writtenNames.push_back(mix->getNamespace() + "theta" + TextTools::toString(i));
+      }
+    }
+  }
+  if (dynamic_cast<const ExponentialDiscreteRateDistribution*>(&dist) ||
+      dynamic_cast<const GammaDiscreteRateDistribution*>(&dist) ||
+      dynamic_cast<const GaussianDiscreteRateDistribution*>(&dist))
+  {
+    if (comma)
+      out << ",";
+    out << "n="  << dist.getNumberOfCategories();
+    comma = true;
+  }
+
+  const SimpleDiscreteDistribution* ps = dynamic_cast<const SimpleDiscreteDistribution*>(&dist);
+  if (ps)
+  {
+    size_t nd = ps->getNumberOfCategories();
+    if (comma)
+      out << ",";
+    out << "values=(";
+    for (size_t i = 0; i < nd; i++)
+    {
+      out << ps->getCategory(i);
+      if (i != nd - 1)
+        out << ",";
+    }
+    out << "),probas=(";
+    for (size_t i = 0; i < nd; i++)
+    {
+      out << ps->getProbability(i);
+      if (i != nd - 1)
+        out << ",";
+    }
+    out << ")";
+
+    const std::map<size_t, std::vector<double> > range = ps->getRanges();
+    if (range.size() != 0)
+    {
+      out << ", ranges=(";
+      std::map<size_t, std::vector<double> >::const_iterator it(range.begin());
+      while (it != range.end())
+      {
+        out << "V" << TextTools::toString(it->first);
+        out << "[" << TextTools::toString(it->second[0]) << ";" << TextTools::toString(it->second[1]) << "]";
+        it++;
+        if (it != range.end())
+          out << ",";
+      }
+    }
+
+    out << ")";
+
+    for (size_t i = 1; i < nd; i++)
+    {
+      writtenNames.push_back(ps->getNamespace() + "theta" + TextTools::toString(i));
+    }
+    for (size_t i = 1; i < nd + 1; i++)
+    {
+      writtenNames.push_back(ps->getNamespace() + "V" + TextTools::toString(i));
+    }
+
+    comma = true;
+  }
+
+
+  // Writing the parameters
+  BppOParametrizableFormat bOP;
+  bOP.write(dynamic_cast<const ParameterAliasable*>(&dist), out, globalAliases, dist.getIndependentParameters().getParameterNames(), writtenNames, true, comma);
+  out << ")";
+}
+
+
diff --git a/src/Bpp/Phyl/Io/BppORateDistributionFormat.h b/src/Bpp/Phyl/Io/BppORateDistributionFormat.h
new file mode 100644
index 0000000..73ad097
--- /dev/null
+++ b/src/Bpp/Phyl/Io/BppORateDistributionFormat.h
@@ -0,0 +1,92 @@
+//
+// File: BppORateDistributionFormat.h
+// Created by: Laurent Guéguen and Julien Dutheil
+// Created on: Fri 16 november 2012, at 13:44
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _BPPORATEDISTRIBUTIONFORMAT_H_
+#define _BPPORATEDISTRIBUTIONFORMAT_H_
+
+#include <Bpp/Io/BppODiscreteDistributionFormat.h>
+
+namespace bpp
+{
+/**
+ * @brief Rate Distribution I/O in BppO format.
+ *
+ * Creates a new discrete distribution object according to
+ * distribution description syntax (see the Bio++ Progam Suite
+ * manual for a detailed description of this syntax).
+ *
+ * Rate distributions are normalized and have a mean of 1, so that branch lengths are measured in mean number of substitutions per site.
+ *
+ * @see BppODiscreteDistribtution for a more generic parser.
+ *
+ */
+
+class BppORateDistributionFormat:
+  public BppODiscreteDistributionFormat
+{
+private:
+  bool allowConstant_;
+
+public:
+  /**
+   * @brief Build a new BppORateDistributionFormat object.
+   *
+   * @param allowConstant Is contant distribution allowed.
+   */
+  BppORateDistributionFormat(bool allowConstant):
+    BppODiscreteDistributionFormat(),
+    allowConstant_(allowConstant)
+  {}
+
+  virtual ~BppORateDistributionFormat() {}
+
+public:
+
+  DiscreteDistribution* read(const std::string& distDescription, bool parseArguments);
+
+  void write(const DiscreteDistribution& dist,
+             OutputStream& out,
+             std::map<std::string, std::string>& globalAliases,
+             std::vector<std::string>& writtenNames) const;
+};
+
+} // end of namespace bpp.
+
+#endif // _BPPORATEDISTRIBUTIONFORMAT_H_
+
diff --git a/src/Bpp/Phyl/Io/BppOSubstitutionModelFormat.cpp b/src/Bpp/Phyl/Io/BppOSubstitutionModelFormat.cpp
new file mode 100644
index 0000000..d524866
--- /dev/null
+++ b/src/Bpp/Phyl/Io/BppOSubstitutionModelFormat.cpp
@@ -0,0 +1,1331 @@
+//
+// File: BppOSubstitutionModelFormat.cpp
+// Created by: Laurent Guéguen
+// Created on: mercredi 4 juillet 2012, à 13h 58
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "BppOSubstitutionModelFormat.h"
+#include "BppORateDistributionFormat.h"
+
+#include <Bpp/Io/FileTools.h>
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Text/StringTokenizer.h>
+#include <Bpp/Text/KeyvalTools.h>
+
+#include "../Model/Codon/MG94.h"
+#include "../Model/Codon/GY94.h"
+#include "../Model/Codon/YNGKP_M1.h"
+#include "../Model/Codon/YNGKP_M2.h"
+#include "../Model/Codon/YNGKP_M3.h"
+#include "../Model/Codon/YNGKP_M7.h"
+#include "../Model/Codon/YNGKP_M8.h"
+#include "../Model/Codon/YN98.h"
+#include "../Model/Codon/TripletSubstitutionModel.h"
+#include "../Model/Codon/CodonRateSubstitutionModel.h"
+#include "../Model/Codon/CodonDistanceSubstitutionModel.h"
+#include "../Model/Codon/CodonRateFrequenciesSubstitutionModel.h"
+#include "../Model/Codon/CodonDistanceFrequenciesSubstitutionModel.h"
+#include "../Model/Codon/CodonDistancePhaseFrequenciesSubstitutionModel.h"
+#include "../Model/Codon/CodonDistanceFitnessPhaseFrequenciesSubstitutionModel.h"
+#include "../Model/RE08.h"
+#include "../Model/TS98.h"
+#include "../Model/G2001.h"
+#include "../Model/Nucleotide/F84.h"
+#include "../Model/Nucleotide/NucleotideSubstitutionModel.h"
+#include "../Model/Nucleotide/gBGC.h"
+#include "../Model/Nucleotide/RN95.h"
+#include "../Model/Nucleotide/GTR.h"
+#include "../Model/Nucleotide/RN95s.h"
+#include "../Model/Nucleotide/HKY85.h"
+#include "../Model/Nucleotide/SSR.h"
+#include "../Model/Nucleotide/JCnuc.h"
+#include "../Model/Nucleotide/T92.h"
+#include "../Model/Nucleotide/K80.h"
+#include "../Model/Nucleotide/TN93.h"
+#include "../Model/Nucleotide/L95.h"
+#include "../Model/Nucleotide/YpR.h"
+#include "../Model/Protein/CoalaCore.h"
+#include "../Model/Protein/LLG08_EX2.h"
+#include "../Model/Protein/Coala.h"
+#include "../Model/Protein/LLG08_EX3.h"
+#include "../Model/Protein/DSO78.h"
+#include "../Model/Protein/LLG08_UL2.h"
+#include "../Model/Protein/JCprot.h"
+#include "../Model/Protein/LLG08_UL3.h"
+#include "../Model/Protein/JTT92.h"
+#include "../Model/Protein/ProteinSubstitutionModel.h"
+#include "../Model/Protein/LG08.h" 
+#include "../Model/Protein/UserProteinSubstitutionModel.h"
+#include "../Model/Protein/LGL08_CAT.h"
+#include "../Model/Protein/WAG01.h"
+#include "../Model/Protein/LLG08_EHO.h"
+#include "../Model/BinarySubstitutionModel.h"
+
+#include "../App/PhylogeneticsApplicationTools.h"
+
+#include "BppOFrequenciesSetFormat.h"
+
+#include <Bpp/Seq/App/SequenceApplicationTools.h>
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+
+#include <Bpp/Io/OutputStream.h>
+#include <Bpp/Io/BppOParametrizableFormat.h>
+#include <Bpp/Io/BppODiscreteDistributionFormat.h>
+
+//From Numeric
+
+#include <Bpp/Numeric/Prob/ConstantDistribution.h>
+#include <Bpp/Numeric/AutoParameter.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iomanip>
+
+using namespace std;
+
+unsigned char BppOSubstitutionModelFormat::DNA = 1;
+unsigned char BppOSubstitutionModelFormat::RNA = 2;
+unsigned char BppOSubstitutionModelFormat::NUCLEOTIDE = 1 | 2;
+unsigned char BppOSubstitutionModelFormat::PROTEIN = 4;
+unsigned char BppOSubstitutionModelFormat::CODON = 8;
+unsigned char BppOSubstitutionModelFormat::WORD = 16;
+unsigned char BppOSubstitutionModelFormat::BINARY = 32;
+unsigned char BppOSubstitutionModelFormat::ALL = 1 | 2 | 4 | 8 | 16 | 32;
+
+
+SubstitutionModel* BppOSubstitutionModelFormat::read(const Alphabet* alphabet,
+                                                     const std::string& modelDescription,
+                                                     const SiteContainer* data,
+                                                     bool parseArguments)
+{
+  unparsedArguments_.clear();
+  auto_ptr<SubstitutionModel> model;
+  string modelName = "";
+  map<string, string> args;
+  KeyvalTools::parseProcedure(modelDescription, modelName, args);
+
+  // //////////////////////////////////
+  // / MIXED MODELS
+  // ////////////////////////////////
+
+  if ((modelName == "MixedModel" || (modelName == "Mixture")) && allowMixed_)
+    model.reset(readMixed_(alphabet, modelDescription, data));
+
+
+  // /////////////////////////////////
+  // / WORDS and CODONS
+  // ///////////////////////////////
+
+  else if ((modelName == "Word") || (modelName == "Triplet") || (modelName.substr(0, 5) == "Codon"))
+    model.reset(readWord_(alphabet, modelDescription, data));
+
+
+  // //////////////////////////////////////
+  // PREDEFINED CODON MODELS
+  // //////////////////////////////////////
+
+  else if (((modelName == "MG94") || (modelName == "YN98") ||
+            (modelName == "GY94") || (modelName.substr(0, 5) == "YNGKP")) && (alphabetCode_ & CODON))
+  {
+    if (!(alphabetCode_ & CODON))
+      throw Exception("BppOSubstitutionModelFormat::read. Codon alphabet not supported.");
+    if (!AlphabetTools::isCodonAlphabet(alphabet))
+      throw Exception("Alphabet should be Codon Alphabet.");
+
+    const CodonAlphabet* pCA = dynamic_cast<const CodonAlphabet*>(alphabet);
+
+    if (args.find("genetic_code") == args.end())
+      args["genetic_code"] = pCA->getAlphabetType();
+
+    auto_ptr<GeneticCode> pgc(SequenceApplicationTools::getGeneticCode(dynamic_cast<const NucleicAlphabet*>(pCA->getNAlphabet(0)), args["genetic_code"]));
+    if (pgc->getSourceAlphabet()->getAlphabetType() != pCA->getAlphabetType())
+      throw Exception("Mismatch between genetic code and codon alphabet");
+
+    string freqOpt = ApplicationTools::getStringParameter("frequencies", args, "F0", "", true, verbose_);
+    BppOFrequenciesSetFormat freqReader(BppOFrequenciesSetFormat::ALL, verbose_);
+    auto_ptr<FrequenciesSet> codonFreqs(freqReader.read(pCA, freqOpt, data, false));
+    map<string, string> unparsedParameterValuesNested(freqReader.getUnparsedArguments());
+
+    for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+    {
+      unparsedArguments_[modelName + "." + it->first] = it->second;
+    }
+
+    if (modelName == "MG94")
+      model.reset(new MG94(pgc.release(), codonFreqs.release()));
+    else if (modelName == "GY94")
+      model.reset(new GY94(pgc.release(), codonFreqs.release()));
+    else if ((modelName == "YN98") || (modelName == "YNGKP_M0"))
+      model.reset(new YN98(pgc.release(), codonFreqs.release()));
+    else if (modelName == "YNGKP_M1")
+      model.reset(new YNGKP_M1(pgc.release(), codonFreqs.release()));
+    else if (modelName == "YNGKP_M2")
+      model.reset(new YNGKP_M2(pgc.release(), codonFreqs.release()));
+    else if (modelName == "YNGKP_M3")
+      if (args.find("n") == args.end())
+        model.reset(new YNGKP_M3(pgc.release(), codonFreqs.release()));
+      else
+        model.reset(new YNGKP_M3(pgc.release(), codonFreqs.release(), TextTools::to<unsigned int>(args["n"])));
+    else if ((modelName == "YNGKP_M7") || modelName == "YNGKP_M8")
+    {
+      if (args.find("n") == args.end())
+        throw Exception("Missing argument 'n' (number of classes) in " + modelName + " distribution");
+      unsigned int nbClasses = TextTools::to<unsigned int>(args["n"]);
+      if (verbose_)
+        ApplicationTools::displayResult("Number of classes in model", nbClasses);
+
+      if (modelName == "YNGKP_M7")
+        model.reset(new YNGKP_M7(pgc.release(), codonFreqs.release(), nbClasses));
+      else if (modelName == "YNGKP_M8")
+        model.reset(new YNGKP_M8(pgc.release(), codonFreqs.release(), nbClasses));
+    }
+    else
+      throw Exception("Unknown Codon model: " + modelName);
+  }
+
+
+  // //////////////////////////////////
+  // gBGC
+  // //////////////////////////////////
+
+  else if (modelName == "gBGC")
+  {
+    if (!(alphabetCode_ & NUCLEOTIDE))
+      throw Exception("BppOSubstitutionModelFormat::read. Nucleotide alphabet not supported.");
+    // We have to parse the nested model first:
+    string nestedModelDescription = args["model"];
+    if (TextTools::isEmpty(nestedModelDescription))
+      throw Exception("BppOSubstitutionModelFormat::read. Missing argument 'model' for model 'gBGC'.");
+    if (verbose_)
+      ApplicationTools::displayResult("Biased gene conversion", modelName);
+    BppOSubstitutionModelFormat nestedReader(NUCLEOTIDE, true, true, false, verbose_);
+    auto_ptr<NucleotideSubstitutionModel> nestedModel(dynamic_cast<NucleotideSubstitutionModel*>(nestedReader.read(alphabet, nestedModelDescription, data, false)));
+    map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+
+    // Now we create the gBGC substitution model:
+    model.reset(new gBGC(dynamic_cast<const NucleicAlphabet*>(alphabet), nestedModel.release()));
+
+    // Then we update the parameter set:
+    for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+    {
+      unparsedArguments_["gBGC." + it->first] = it->second;
+    }
+  }
+
+  // //////////////////////////////////
+  // YpR
+  // //////////////////////////////////
+
+  else if (modelName == "YpR_Sym")
+  {
+    if (!(alphabetCode_ & NUCLEOTIDE))
+      throw Exception("BppOSubstitutionModelFormat::read. Nucleotide alphabet not supported.");
+    if (alphabet->getAlphabetType() != "RNY alphabet")
+      throw Exception("Mismatch alphabet: " + alphabet->getAlphabetType() + " for model: " + modelName);
+    const RNY* prny = dynamic_cast<const RNY*>(alphabet);
+
+    string nestedModelDescription = args["model"];
+    if (TextTools::isEmpty(nestedModelDescription))
+      throw Exception("BppOSubstitutionModelFormat::read. Missing argument 'model' for model 'YpR_sym'.");
+    if (verbose_)
+      ApplicationTools::displayResult("Symetric YpR model", modelName);
+    BppOSubstitutionModelFormat nestedReader(NUCLEOTIDE, false, false, false, verbose_);
+    auto_ptr<NucleotideSubstitutionModel> nestedModel(dynamic_cast<NucleotideSubstitutionModel*>(nestedReader.read(&prny->getLetterAlphabet(), nestedModelDescription, data, false)));
+    map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+    for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+    {
+      unparsedArguments_["YpR_Sym." + it->first] = it->second;
+    }
+
+    model.reset(new YpR_Sym(prny, nestedModel.release()));
+  }
+  else if (modelName == "YpR_Gen")
+  {
+    if (!(alphabetCode_ & NUCLEOTIDE))
+      throw Exception("BppOSubstitutionModelFormat::read. Nucleotide alphabet not supported.");
+    if (alphabet->getAlphabetType() != "RNY alphabet")
+      throw Exception("Mismatch alphabet: " + alphabet->getAlphabetType() + " for model: " + modelName);
+    const RNY* prny = dynamic_cast<const RNY*>(alphabet);
+
+    string nestedModelDescription = args["model"];
+    if (TextTools::isEmpty(nestedModelDescription))
+      throw Exception("BppOSubstitutionModelFormat::read. Missing argument 'model' for model 'YpR_gen'.");
+    if (verbose_)
+      ApplicationTools::displayResult("General YpR model", modelName);
+    BppOSubstitutionModelFormat nestedReader(NUCLEOTIDE, false, false, false, verbose_);
+    auto_ptr<NucleotideSubstitutionModel> nestedModel(dynamic_cast<NucleotideSubstitutionModel*>(nestedReader.read(&prny->getLetterAlphabet(), nestedModelDescription, data, false)));
+    map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+
+    for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+    {
+      unparsedArguments_["YpR_Gen." + it->first] = it->second;
+    }
+
+    model.reset(new YpR_Gen(prny, nestedModel.release()));
+  }
+
+
+  // /////////////////////////////////
+  // / RE08
+  // ///////////////////////////////
+
+  else if (modelName == "RE08")
+  {
+    if (!allowGaps_)
+      throw Exception("BppOSubstitutionModelFormat::read. No Gap model allowed here.");
+
+    // We have to parse the nested model first:
+    string nestedModelDescription = args["model"];
+    if (TextTools::isEmpty(nestedModelDescription))
+      throw Exception("BppOSubstitutionModelFormat::read. Missing argument 'model' for model 'RE08'.");
+    if (verbose_)
+      ApplicationTools::displayResult("Gap model", modelName);
+    BppOSubstitutionModelFormat nestedReader(ALL, allowCovarions_, false, false, verbose_);
+    auto_ptr<ReversibleSubstitutionModel> nestedModel(dynamic_cast<ReversibleSubstitutionModel*>(nestedReader.read(alphabet, nestedModelDescription, data, false)));
+    map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+
+    // Now we create the RE08 substitution model:
+    model.reset(new RE08(nestedModel.release()));
+
+    // Then we update the parameter set:
+    for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+    {
+      unparsedArguments_["RE08.model_" + it->first] = it->second;
+    }
+  }
+
+  // /////////////////////////////////
+  // / TS98
+  // ///////////////////////////////
+
+  else if (modelName == "TS98")
+  {
+    if (!allowCovarions_)
+      throw Exception("BppOSubstitutionModelFormat::read. No Covarion model allowed here.");
+
+    // We have to parse the nested model first:
+    string nestedModelDescription = args["model"];
+    if (TextTools::isEmpty(nestedModelDescription))
+      throw Exception("BppOSubstitutionModelFormat::read. Missing argument 'model' for model 'TS98'.");
+    if (verbose_)
+      ApplicationTools::displayResult("Covarion model", modelName);
+    BppOSubstitutionModelFormat nestedReader(ALL, false, allowMixed_, allowGaps_, false);
+    auto_ptr<ReversibleSubstitutionModel> nestedModel(dynamic_cast<ReversibleSubstitutionModel*>(nestedReader.read(alphabet, nestedModelDescription, data, false)));
+    map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+
+    // Now we create the TS98 substitution model:
+    model.reset(new TS98(nestedModel.release()));
+
+    // Then we update the parameter set:
+    for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+    {
+      unparsedArguments_["TS98.model_" + it->first] = it->second;
+    }
+  }
+
+  // /////////////////////////////////
+  // / G01
+  // ///////////////////////////////
+
+  else if (modelName == "G01")
+  {
+    if (!allowCovarions_)
+      throw Exception("BppOSubstitutionModelFormat::read. No Covarion model allowed here.");
+
+    // We have to parse the nested model first:
+    string nestedModelDescription = args["model"];
+    if (TextTools::isEmpty(nestedModelDescription))
+      throw Exception("BppOSubstitutionModelFormat::read. Missing argument 'model' for model 'G01'.");
+    string nestedRateDistDescription = args["rdist"];
+    if (TextTools::isEmpty(nestedRateDistDescription))
+      throw Exception("BppOSubstitutionModelFormat::read. Missing argument 'rdist' for model 'G01'.");
+    if (verbose_)
+      ApplicationTools::displayResult("Covarion model", modelName);
+    BppOSubstitutionModelFormat nestedReader(ALL, false, allowMixed_, allowGaps_, verbose_);
+    auto_ptr<ReversibleSubstitutionModel> nestedModel(dynamic_cast<ReversibleSubstitutionModel*>(nestedReader.read(alphabet, nestedModelDescription, data, false)));
+    map<string, string> unparsedParameterValuesNestedModel(nestedReader.getUnparsedArguments());
+    BppORateDistributionFormat rateReader(false);
+    auto_ptr<DiscreteDistribution> nestedRDist(rateReader.read(nestedRateDistDescription, false));
+    map<string, string> unparsedParameterValuesNestedDist(rateReader.getUnparsedArguments());
+
+    // Now we create the TS98 substitution model:
+    model.reset(new G2001(nestedModel.release(), nestedRDist.release()));
+
+    // Then we update the parameter set:
+    for (map<string, string>::iterator it = unparsedParameterValuesNestedModel.begin(); it != unparsedParameterValuesNestedModel.end(); it++)
+    {
+      unparsedArguments_["G01.model_" + it->first] = it->second;
+    }
+    for (map<string, string>::iterator it = unparsedParameterValuesNestedDist.begin(); it != unparsedParameterValuesNestedDist.end(); it++)
+    {
+      unparsedArguments_["G01.rdist_" + it->first] = it->second;
+    }
+  }
+  else
+  {
+    // This is a 'simple' model...
+    if (AlphabetTools::isNucleicAlphabet(alphabet))
+    {
+      if (!(alphabetCode_ & NUCLEOTIDE))
+        throw Exception("BppOSubstitutionModelFormat::read. Nucleotide alphabet not supported.");
+      const NucleicAlphabet* alpha = dynamic_cast<const NucleicAlphabet*>(alphabet);
+
+      // /////////////////////////////////
+      // / GTR
+      // ///////////////////////////////
+
+      if (modelName == "GTR")
+      {
+        model.reset(new GTR(alpha));
+      }
+
+
+      // /////////////////////////////////
+      // / SSR
+      // ///////////////////////////////
+
+      else if (modelName == "SSR")
+      {
+        model.reset(new SSR(alpha));
+      }
+
+      // /////////////////////////////////
+      // / L95
+      // ///////////////////////////////
+
+      else if (modelName == "L95")
+      {
+        model.reset(new L95(alpha));
+      }
+
+      // /////////////////////////////////
+      // / RN95
+      // ///////////////////////////////
+
+      else if (modelName == "RN95")
+      {
+        model.reset(new RN95(alpha));
+      }
+
+      // /////////////////////////////////
+      // / RN95s
+      // ///////////////////////////////
+
+      else if (modelName == "RN95s")
+      {
+        model.reset(new RN95s(alpha));
+      }
+
+      // /////////////////////////////////
+      // / TN93
+      // //////////////////////////////
+
+      else if (modelName == "TN93")
+      {
+        model.reset(new TN93(alpha));
+      }
+
+      // /////////////////////////////////
+      // / HKY85
+      // ///////////////////////////////
+
+      else if (modelName == "HKY85")
+      {
+        model.reset(new HKY85(alpha));
+      }
+
+      // /////////////////////////////////
+      // / F84
+      // ///////////////////////////////
+
+      else if (modelName == "F84")
+      {
+        model.reset(new F84(alpha));
+      }
+
+      // /////////////////////////////////
+      // / T92
+      // ///////////////////////////////
+
+      else if (modelName == "T92")
+      {
+        model.reset(new T92(alpha));
+      }
+
+      // /////////////////////////////////
+      // / K80
+      // ///////////////////////////////
+
+      else if (modelName == "K80")
+      {
+        model.reset(new K80(alpha));
+      }
+
+
+      // /////////////////////////////////
+      // / JC69
+      // ///////////////////////////////
+
+      else if (modelName == "JC69")
+      {
+        model.reset(new JCnuc(alpha));
+      }
+      else
+      {
+        throw Exception("Model '" + modelName + "' unknown.");
+      }
+    }
+    else
+    {
+      if (!(alphabetCode_ & PROTEIN))
+        throw Exception("BppOSubstitutionModelFormat::read. Protein alphabet not supported.");
+      const ProteicAlphabet* alpha = dynamic_cast<const ProteicAlphabet*>(alphabet);
+
+      if (modelName.find("+F")!=string::npos){
+        string freqOpt = ApplicationTools::getStringParameter("frequencies", args, "Full", "", true, verbose_);
+        BppOFrequenciesSetFormat freqReader(BppOFrequenciesSetFormat::ALL, false);
+        auto_ptr<FrequenciesSet> protFreq(freqReader.read(alpha, freqOpt, data, true));
+        map<string, string> unparsedParameterValuesNested(freqReader.getUnparsedArguments());
+
+        for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+          {
+            unparsedArguments_[modelName + "." + it->first] = it->second;
+          }
+        
+        if (modelName == "JC69+F")
+          model.reset(new JCprot(alpha, dynamic_cast<ProteinFrequenciesSet*>(protFreq.release()), true));
+        else if (modelName == "DSO78+F")
+          model.reset(new DSO78(alpha, dynamic_cast<ProteinFrequenciesSet*>(protFreq.release()), true));
+        else if (modelName == "JTT92+F")
+          model.reset(new JTT92(alpha, dynamic_cast<ProteinFrequenciesSet*>(protFreq.release()), true));
+        else if (modelName == "LG08+F")
+          model.reset(new LG08(alpha, dynamic_cast<ProteinFrequenciesSet*>(protFreq.release()), true));
+        else if (modelName == "WAG01+F")
+          model.reset(new WAG01(alpha, dynamic_cast<ProteinFrequenciesSet*>(protFreq.release()), true));
+        else if (modelName == "Empirical+F")
+          {
+            string prefix = args["name"];
+            if (TextTools::isEmpty(prefix))
+              throw Exception("'name' argument missing for user-defined substitution model.");
+            model.reset(new UserProteinSubstitutionModel(alpha, args["file"], dynamic_cast<ProteinFrequenciesSet*>(protFreq.release()), prefix + "+F.", true));
+          }
+      }
+      else if (modelName == "JC69")
+        model.reset(new JCprot(alpha));
+      else if (modelName == "DSO78")
+        model.reset(new DSO78(alpha));
+      else if (modelName == "JTT92")
+        model.reset(new JTT92(alpha));
+      else if (modelName == "LG08")
+        model.reset(new LG08(alpha));
+      else if (modelName == "WAG01")
+        model.reset(new WAG01(alpha));
+      else if (modelName == "LLG08_EHO")
+        model.reset(new LLG08_EHO(alpha));
+      else if (modelName == "LLG08_EX2")
+        model.reset(new LLG08_EX2(alpha));
+      else if (modelName == "LLG08_EX3")
+        model.reset(new LLG08_EX3(alpha));
+      else if (modelName == "LLG08_UL2")
+        model.reset(new LLG08_UL2(alpha));
+      else if (modelName == "LLG08_UL3")
+        model.reset(new LLG08_UL3(alpha));
+      else if (modelName == "LGL08_CAT")
+      {
+        unsigned int nbCat = TextTools::toInt(args["nbCat"]);
+        model.reset(new LGL08_CAT(alpha, nbCat));
+      }
+      else if (modelName == "Empirical")
+      {
+        string prefix = args["name"];
+        if (TextTools::isEmpty(prefix))
+          throw Exception("'name' argument missing for user-defined substitution model.");
+        model.reset(new UserProteinSubstitutionModel(alpha, args["file"], prefix));
+      }
+      else if (modelName == "COaLA")
+      {
+        string nbrOfParametersPerBranch = args["nbrAxes"];
+        if (TextTools::isEmpty(nbrOfParametersPerBranch))
+          throw Exception("'nbrAxes' argument missing to define the number of axis of the Correspondence Analysis.");
+        string exchangeability = args["exch"];
+        if (TextTools::isEmpty(exchangeability))
+          throw Exception("'exch' argument missing to define exchangeability.");
+        string file = args["file"];
+        if (exchangeability == "Empirical" && TextTools::isEmpty(file))
+          throw Exception("'file' argument missing to specify the exchangeabilities of the user-defined empirical model.");
+        model.reset(new Coala(alpha, TextTools::toInt(nbrOfParametersPerBranch), exchangeability, file));
+        dynamic_cast<Coala*>(model.get())->setFreqFromData(*data);
+      }
+
+      else if (AlphabetTools::isBinaryAlphabet(alphabet))
+      {
+        if (!(alphabetCode_ & BINARY))
+          throw Exception("BppOSubstitutionModelFormat::read. Binary alphabet not supported.");
+        const BinaryAlphabet* balpha = dynamic_cast<const BinaryAlphabet*>(alphabet);
+
+        if (modelName == "Binary")
+          model.reset(new BinarySubstitutionModel(balpha));
+      }
+      else
+        throw Exception("Model '" + modelName + "' unknown.");
+    }
+    if (verbose_)
+      ApplicationTools::displayResult("Substitution model", modelName);
+  }
+
+  // Update parameter args:
+  vector<string> pnames = model->getParameters().getParameterNames();
+
+  string pref = model->getNamespace();
+
+  for (size_t i = 0; i < pnames.size(); i++)
+  {
+    string name = model->getParameterNameWithoutNamespace(pnames[i]);
+    if (args.find(name) != args.end())
+      unparsedArguments_[pref + name] = args[name];
+  }
+
+  // Now look if some parameters are aliased:
+  ParameterList pl = model->getIndependentParameters();
+  string pname, pval, pname2;
+  for (size_t i = 0; i < pl.size(); i++)
+  {
+    pname = model->getParameterNameWithoutNamespace(pl[i].getName());
+
+    if (args.find(pname) == args.end())
+      continue;
+    pval = args[pname];
+
+    if ((pval.length() >= 5 && pval.substr(0, 5) == "model") ||
+        (pval.find("(") != string::npos))
+      continue;
+    bool found = false;
+    for (unsigned int j = 0; j < pl.size() && !found; j++)
+    {
+      pname2 = model->getParameterNameWithoutNamespace(pl[j].getName());
+
+      // if (j == i || args.find(pname2) == args.end()) continue; Julien 03/03/2010: This extra condition prevents complicated (nested) models to work properly...
+      if (j == i)
+        continue;
+      if (pval == pname2)
+      {
+        // This is an alias...
+        // NB: this may throw an exception if uncorrect! We leave it as is for now :s
+        model->aliasParameters(pname2, pname);
+        if (verbose_)
+          ApplicationTools::displayResult("Parameter alias found", pname + "->" + pname2);
+        found = true;
+      }
+    }
+    if (!TextTools::isDecimalNumber(pval) && !found)
+      throw Exception("Incorrect parameter syntax: parameter " + pval + " was not found and can't be used as a value for parameter " + pname + ".");
+  }
+
+  // 2 following tests be removed in a later version
+  if (args.find("useObservedFreqs") != args.end())
+    throw Exception("useObservedFreqs argument is obsolete. Please use 'initFreqs=observed' instead.");
+  if (args.find("useObservedFreqs.pseudoCount") != args.end())
+    throw Exception("useObservedFreqs.pseudoCount argument is obsolete. Please use 'initFreqs.observedPseudoCount' instead.");
+
+
+  if (args.find("initFreqs") != args.end())
+    unparsedArguments_[pref + "initFreqs"] = args["initFreqs"];
+  if (args.find("initFreqs.observedPseudoCount") != args.end())
+    unparsedArguments_[pref + "initFreqs.observedPseudoCount"] = args["initFreqs.observedPseudoCount"];
+
+  if (parseArguments)
+    initialize_(*model, data);
+
+  return model.release();
+}
+
+
+SubstitutionModel* BppOSubstitutionModelFormat::readWord_(const Alphabet* alphabet, const std::string& modelDescription, const SiteContainer* data)
+{
+  auto_ptr<SubstitutionModel> model;
+  string modelName = "";
+  map<string, string> args;
+  KeyvalTools::parseProcedure(modelDescription, modelName, args);
+
+  vector<string> v_nestedModelDescription;
+  vector<SubstitutionModel*> v_pSM;
+  const WordAlphabet* pWA;
+
+  string s, nestedModelDescription;
+  unsigned int nbmodels;
+
+  if ((modelName == "Word" && !AlphabetTools::isWordAlphabet(alphabet)) ||
+      (modelName != "Word" && !AlphabetTools::isCodonAlphabet(alphabet)))
+    throw Exception("Bad alphabet type "
+                    + alphabet->getAlphabetType() + " for  model " + modelName + ".");
+
+  pWA = dynamic_cast<const WordAlphabet*>(alphabet);
+
+  if (args.find("model") != args.end())
+  {
+    v_nestedModelDescription.push_back(args["model"]);
+    nbmodels = (modelName == "Word") ? pWA->getLength() : 3;
+  }
+  else
+  {
+    if (args.find("model1") == args.end())
+      throw Exception("Missing argument 'model' or 'model1' for model " + modelName + ".");
+
+    nbmodels = 0;
+
+    while (args.find("model" + TextTools::toString(nbmodels + 1)) != args.end())
+      v_nestedModelDescription.push_back(args["model" + TextTools::toString(++nbmodels)]);
+  }
+
+  if (nbmodels < 2)
+    throw Exception("Missing nested models for model " + modelName + ".");
+
+  if (pWA->getLength() != nbmodels)
+    throw Exception("Bad alphabet type "
+                    + alphabet->getAlphabetType() + " for  model " + modelName + ".");
+
+
+  if (v_nestedModelDescription.size() != nbmodels)
+  {
+    BppOSubstitutionModelFormat nestedReader(alphabetCode_, false, true, false, false);
+    model.reset(nestedReader.read(pWA->getNAlphabet(0), v_nestedModelDescription[0], data, false));
+    map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+    string pref = "";
+    for (unsigned int i = 0; i < nbmodels; i++)
+    {
+      pref += TextTools::toString(i + 1);
+    }
+
+    for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+    {
+      unparsedArguments_[modelName + "." + pref + "_" + it->first] = it->second;
+    }
+
+    v_pSM.push_back(model.release());
+  }
+  else
+  {
+    for (unsigned i = 0; i < v_nestedModelDescription.size(); i++)
+    {
+      BppOSubstitutionModelFormat nestedReader(alphabetCode_, false, true, false, false);
+      model.reset(nestedReader.read(pWA->getNAlphabet(i), v_nestedModelDescription[i], data, false));
+      map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+      for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+      {
+        unparsedArguments_[modelName + "." + TextTools::toString(i + 1) + "_" + it->first] = it->second;
+      }
+
+      v_pSM.push_back(model.release());
+    }
+  }
+
+  // /////////////////////////////////
+  // / WORD
+  // ///////////////////////////////
+
+  if (modelName == "Word")
+  {
+    model.reset((v_nestedModelDescription.size() != nbmodels)
+                ? new WordSubstitutionModel(v_pSM[0], nbmodels)
+                : new WordSubstitutionModel(v_pSM));
+  }
+
+  // /////////////////////////////////
+  // / CODON
+  // ///////////////////////////////
+
+  else
+  {
+    const CodonAlphabet* pCA = dynamic_cast<const CodonAlphabet*>(pWA);
+    if (pCA == 0)
+      throw Exception("Non codon Alphabet fo model" + modelName + " model.");
+
+    auto_ptr< AlphabetIndex2 > pai2;
+    auto_ptr<GeneticCode> pgc;
+    auto_ptr<FrequenciesSet> pFS;
+
+    if ((dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]) == 0) ||
+        ((v_nestedModelDescription.size() == 3) &&
+         (dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[1]) == 0 || dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[2]) == 0)))
+      throw Exception("Non simple NucleotideSubstitutionModel imbedded in " + modelName + " model.");
+
+
+    if (modelName.find("Dist") != string::npos)
+    {
+      if (args.find("genetic_code") == args.end())
+        args["genetic_code"] = pCA->getAlphabetType();
+
+      pgc.reset(SequenceApplicationTools::getGeneticCode(dynamic_cast<const NucleicAlphabet*>(pCA->getNAlphabet(0)), args["genetic_code"]));
+      if (pgc->getSourceAlphabet()->getAlphabetType() != pCA->getAlphabetType())
+        throw Exception("Mismatch between genetic code and codon alphabet");
+
+      pai2.reset((args.find("aadistance") == args.end()) ? 0 : SequenceApplicationTools::getAlphabetIndex2(&AlphabetTools::PROTEIN_ALPHABET, args["aadistance"]));
+    }
+
+
+    if (modelName.find("Freq") != string::npos)
+    {
+      if (args.find("frequencies") == args.end())
+        throw Exception("Missing equilibrium frequencies.");
+
+      BppOFrequenciesSetFormat bIOFreq(alphabetCode_, verbose_);
+      pFS.reset(bIOFreq.read(pCA, args["frequencies"], data, false));
+      map<string, string> unparsedParameterValuesNested(bIOFreq.getUnparsedArguments());
+
+      for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+      {
+        unparsedArguments_[modelName + "." + it->first] = it->second;
+      }
+    }
+
+
+    // //
+
+    if (modelName == "Triplet")
+      model.reset((v_nestedModelDescription.size() != 3)
+                  ? new TripletSubstitutionModel(
+                    pCA,
+                    dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]))
+                  : new TripletSubstitutionModel(
+                    pCA,
+                    dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]),
+                    dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[1]),
+                    dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[2])));
+
+    else if (modelName == "CodonRate")
+      model.reset((v_nestedModelDescription.size() != 3)
+                  ? new CodonRateSubstitutionModel(
+                    pCA,
+                    dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]))
+                  : new CodonRateSubstitutionModel(
+                    pCA,
+                    dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]),
+                    dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[1]),
+                    dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[2])));
+
+
+    else if (modelName == "CodonDist")
+    {
+      if (v_nestedModelDescription.size() != 3)
+        model.reset(new CodonDistanceSubstitutionModel(pgc.release(), dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]), pai2.release()));
+      else
+        model.reset(new CodonDistanceSubstitutionModel(
+                      pgc.release(),
+                      dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]),
+                      dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[1]),
+                      dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[2]), pai2.release()));
+    }
+
+    else if (modelName == "CodonRateFreq")
+    {
+      if (v_nestedModelDescription.size() != 3)
+        model.reset(new CodonRateFrequenciesSubstitutionModel(pCA, dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]), pFS.release()));
+      else
+        model.reset(new CodonRateFrequenciesSubstitutionModel(pCA,
+                                                              dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]),
+                                                              dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[1]),
+                                                              dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[2]),
+                                                              pFS.release()));
+    }
+
+    else if (modelName == "CodonDistFreq")
+    {
+      if (v_nestedModelDescription.size() != 3)
+        model.reset(new CodonDistanceFrequenciesSubstitutionModel(pgc.release(),
+                                                                  dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]),
+                                                                  pFS.release(),
+                                                                  pai2.release()));
+      else
+        model.reset(new CodonDistanceFrequenciesSubstitutionModel(
+                      pgc.release(),
+                      dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]),
+                      dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[1]),
+                      dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[2]),
+                      pFS.release(),
+                      pai2.release()));
+    }
+
+    else if (modelName == "CodonDistPhasFreq")
+    {
+      if (v_nestedModelDescription.size() != 3)
+        model.reset(new CodonDistancePhaseFrequenciesSubstitutionModel(pgc.release(),
+                                                                       dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]),
+                                                                       pFS.release(),
+                                                                       pai2.release()));
+      else
+        model.reset(new CodonDistancePhaseFrequenciesSubstitutionModel(
+                      pgc.release(),
+                      dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]),
+                      dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[1]),
+                      dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[2]),
+                      pFS.release(),
+                      pai2.release()));
+    }
+    else if (modelName == "CodonDistFitPhasFreq")
+    {
+      if (args.find("fitness") == args.end())
+        throw Exception("Missing fitness in model " + modelName + ".");
+
+      BppOFrequenciesSetFormat bIOFreq(alphabetCode_, verbose_);
+      auto_ptr<FrequenciesSet> pFit(bIOFreq.read(pCA, args["fitness"], data, false));
+      map<string, string> unparsedParameterValuesNested(bIOFreq.getUnparsedArguments());
+
+      for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+      {
+        unparsedArguments_[modelName + ".fit_" + it->first] = it->second;
+      }
+
+      if (v_nestedModelDescription.size() != 3)
+      {
+        model.reset(new CodonDistanceFitnessPhaseFrequenciesSubstitutionModel(pgc.release(),
+                                                                              dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]),
+                                                                              pFit.release(),
+                                                                              pFS.release(),
+                                                                              pai2.release()));
+      }
+      else
+        model.reset(new CodonDistanceFitnessPhaseFrequenciesSubstitutionModel(
+                      pgc.release(),
+                      dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[0]),
+                      dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[1]),
+                      dynamic_cast<NucleotideSubstitutionModel*>(v_pSM[2]),
+                      pFit.release(),
+                      pFS.release(),
+                      pai2.release()));
+    }
+  }
+  return model.release();
+}
+
+
+MixedSubstitutionModel* BppOSubstitutionModelFormat::readMixed_(const Alphabet* alphabet, const std::string& modelDescription, const SiteContainer* data)
+{
+  auto_ptr<MixedSubstitutionModel> model;
+
+  string modelName = "";
+  map<string, string> args;
+  KeyvalTools::parseProcedure(modelDescription, modelName, args);
+  auto_ptr<SubstitutionModel> pSM;
+
+  if (modelName == "MixedModel")
+  {
+    if (args.find("model") == args.end())
+      throw Exception("The argument 'model' is missing from MixedSubstitutionModel description");
+    string nestedModelDescription = args["model"];
+    BppOSubstitutionModelFormat nestedReader(alphabetCode_, allowCovarions_, true, allowGaps_, false);
+    pSM.reset(nestedReader.read(alphabet, nestedModelDescription, data, false));
+    map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+
+    map<string, DiscreteDistribution*> mdist;
+    map<string, string> unparsedParameterValuesNested2;
+
+    for (map<string, string>::iterator it = unparsedParameterValuesNested.begin();
+         it != unparsedParameterValuesNested.end();
+         it++)
+    {
+      if (it->second.find("(") != string::npos)
+      {
+        BppODiscreteDistributionFormat bIO(false);
+        mdist[pSM->getParameterNameWithoutNamespace(it->first)] = bIO.read(it->second, false);
+        map<string, string> unparsedParameterValuesNested3(bIO.getUnparsedArguments());
+        for (map<string, string>::iterator it2 = unparsedParameterValuesNested3.begin();
+             it2 != unparsedParameterValuesNested3.end();
+             it2++)
+        {
+          unparsedParameterValuesNested2[it->first + "_" + it2->first] = it2->second;
+        }
+      }
+      else
+        unparsedParameterValuesNested2[it->first] = it->second;
+    }
+
+    for (map<string, string>::iterator it = unparsedParameterValuesNested2.begin();
+         it != unparsedParameterValuesNested2.end();
+         it++)
+    {
+      unparsedArguments_[it->first] = it->second;
+    }
+
+
+    int fi(-1), ti(-1);
+
+    if (args.find("from") != args.end())
+      fi = alphabet->charToInt(args["from"]);
+    if (args.find("to") != args.end())
+      ti = alphabet->charToInt(args["to"]);
+
+    string sModN=pSM->getName();
+    model.reset(new MixtureOfASubstitutionModel(alphabet, pSM.release(), mdist, fi, ti));
+
+    vector<string> v = model->getParameters().getParameterNames();
+
+    for (map<string, DiscreteDistribution*>::iterator it = mdist.begin();
+         it != mdist.end(); it++)
+    {
+      delete it->second;
+    }
+
+    if (verbose_)
+      {
+        ApplicationTools::displayResult("Mixture Of A Substitution Model", sModN);
+        ApplicationTools::displayResult("Number of classes", model->getNumberOfModels());
+      }
+  }
+
+
+  else if (modelName == "Mixture")
+  {
+    vector<string> v_nestedModelDescription;
+    vector<SubstitutionModel*> v_pSM;
+
+    if (args.find("model1") == args.end())
+    {
+      throw Exception("Missing argument 'model1' for model " + modelName + ".");
+    }
+    unsigned int nbmodels = 0;
+
+    while (args.find("model" + TextTools::toString(nbmodels + 1)) != args.end())
+    {
+      v_nestedModelDescription.push_back(args["model" + TextTools::toString(++nbmodels)]);
+    }
+
+    if (nbmodels < 2)
+      throw Exception("Missing nested models for model " + modelName + ".");
+
+    for (unsigned i = 0; i < v_nestedModelDescription.size(); i++)
+    {
+      BppOSubstitutionModelFormat nestedReader(alphabetCode_, false, true, false, false);
+      pSM.reset(nestedReader.read(alphabet, v_nestedModelDescription[i], data, false));
+      map<string, string> unparsedParameterValuesNested(nestedReader.getUnparsedArguments());
+      for (map<string, string>::iterator it = unparsedParameterValuesNested.begin(); it != unparsedParameterValuesNested.end(); it++)
+      {
+        unparsedArguments_[modelName + "." + TextTools::toString(i + 1) + "_" + it->first] = it->second;
+      }
+      v_pSM.push_back(pSM.release());
+    }
+
+    model.reset(new MixtureOfSubstitutionModels(alphabet, v_pSM));
+    if (verbose_)
+        ApplicationTools::displayResult("Mixture Of Substitution Models", modelName );
+  }
+  else
+    throw Exception("Unknown model name for mixture " + modelName);
+
+  return model.release();
+}
+
+
+void BppOSubstitutionModelFormat::write(const SubstitutionModel& model,
+                                        OutputStream& out,
+                                        std::map<std::string, std::string>& globalAliases,
+                                        std::vector<std::string>& writtenNames) const
+{
+  bool comma = false;
+
+  //  Mixed Model that are defined as "Mixture" and "Mixed"
+
+  if ((dynamic_cast<const MixedSubstitutionModel*>(&model) != NULL) && (dynamic_cast<const AbstractBiblioMixedSubstitutionModel*>(&model) == NULL))
+  {
+    writeMixed_(*dynamic_cast<const MixedSubstitutionModel*>(&model), out, globalAliases, writtenNames);
+    return;
+  }
+
+  out << model.getName() + "(";
+
+  // Is it a protein user defined model?
+  const UserProteinSubstitutionModel* userModel = dynamic_cast<const UserProteinSubstitutionModel*>(&model);
+  if (userModel)
+  {
+    out << "file=" << userModel->getPath();
+    comma = true;
+  }
+
+  // Is it a markov-modulated model?
+  const MarkovModulatedSubstitutionModel* mmModel = dynamic_cast<const MarkovModulatedSubstitutionModel*>(&model);
+  if (mmModel)
+  {
+    out << "model=";
+    const SubstitutionModel* nestedModel = mmModel->getNestedModel();
+    write(*nestedModel, out, globalAliases, writtenNames);
+
+    const G2001* gModel = dynamic_cast<const G2001*>(&model);
+    if (gModel)
+    {
+      // Also print distribution here:
+      out << ",rdist=";
+      const DiscreteDistribution* nestedDist = gModel->getRateDistribution();
+      const BppODiscreteDistributionFormat* bIO = new BppODiscreteDistributionFormat();
+
+      bIO->write(*nestedDist, out, globalAliases, writtenNames);
+      delete bIO;
+    }
+    comma = true;
+  }
+
+  // Is it a model with gaps?
+  const RE08* reModel = dynamic_cast<const RE08*>(&model);
+  if (reModel)
+  {
+    out << "model=";
+    const SubstitutionModel* nestedModel = reModel->getNestedModel();
+    write(*nestedModel, out, globalAliases, writtenNames);
+    comma = true;
+  }
+
+  // Is it a YpR model?
+  const YpR* yprModel = dynamic_cast<const YpR*>(&model);
+  if (yprModel)
+  {
+    out << "model=";
+    const SubstitutionModel* nestedModel = yprModel->getNestedModel();
+    write(*nestedModel, out, globalAliases, writtenNames);
+    comma = true;
+  }
+
+  // Is it a word model?
+
+  const AbstractWordSubstitutionModel* wM = dynamic_cast<const AbstractWordSubstitutionModel*>(&model);
+  if (wM)
+  {
+    size_t nmod = wM->getNumberOfModels();
+    const SubstitutionModel* mod0 = wM->getNModel(0);
+    if (nmod == 1)
+    {
+      out << "model=";
+      write(*mod0, out, globalAliases, writtenNames);
+    }
+    else
+    {
+      const SubstitutionModel* mod1 = wM->getNModel(1);
+      if (mod1 == mod0)
+      {
+        out << "model=";
+        write(*mod0, out, globalAliases, writtenNames);
+      }
+      else
+      {
+        out << "model1=";
+        write(*mod0, out, globalAliases, writtenNames);
+        for (unsigned int i = 1; i < nmod; i++)
+        {
+          out << ",model" + TextTools::toString(i + 1) + "=";
+          write(*wM->getNModel(i), out, globalAliases, writtenNames);
+        }
+      }
+    }
+    comma = true;
+  }
+
+  // Is it a COaLA model ?
+  const Coala* coalaModel = dynamic_cast<const Coala*>(&model);
+  if (coalaModel)
+  {
+    out << "exch=" << coalaModel->getExch() << ",nbrAxes=" << coalaModel->getNbrOfAxes();
+    comma = true;
+  }
+
+  // Regular model
+  const FrequenciesSet* pfs = model.getFrequenciesSet();
+  if (pfs)
+  {
+    if (comma)
+      out << ",";
+    out << "frequencies=";
+
+    BppOFrequenciesSetFormat bIOFreq(alphabetCode_, false);
+    bIOFreq.write(pfs, out, writtenNames);
+    comma = true;
+  }
+
+  // Specific case of CodonFitnessSubstitutionModel
+
+  const CodonDistanceFitnessPhaseFrequenciesSubstitutionModel* pCF = dynamic_cast<const CodonDistanceFitnessPhaseFrequenciesSubstitutionModel*>(&model);
+  if (pCF)
+  {
+    if (comma)
+      out << ",";
+    out << "fitness=";
+
+    BppOFrequenciesSetFormat bIOFreq(alphabetCode_, false);
+    bIOFreq.write(pCF->getFitness(), out, writtenNames);
+    comma = true;
+  }
+
+  // and the other parameters
+
+  BppOParametrizableFormat bIO;
+  bIO.write(&model, out, globalAliases, model.getIndependentParameters().getParameterNames(), writtenNames, true, comma);
+  out << ")";
+}
+
+
+void BppOSubstitutionModelFormat::writeMixed_(const MixedSubstitutionModel& model,
+                                              OutputStream& out,
+                                              std::map<std::string, std::string>& globalAliases,
+                                              std::vector<std::string>& writtenNames) const
+{
+  if (dynamic_cast<const MixtureOfSubstitutionModels*>(&model) != NULL)
+  {
+    const MixtureOfSubstitutionModels* pMS = dynamic_cast<const MixtureOfSubstitutionModels*>(&model);
+
+    for (unsigned int i = 0; i < pMS->getNumberOfModels(); i++)
+    {
+      const SubstitutionModel* eM = pMS->getNModel(i);
+
+      vector<string> vpl = eM->getIndependentParameters().getParameterNames();
+      for (unsigned j = 0; j < vpl.size(); j++)
+      {
+        if (eM->getParameterNameWithoutNamespace(vpl[j]) == "rate")
+          writtenNames.push_back(vpl[j]);
+      }
+    }
+
+    out << "Mixture(";
+    for (unsigned int i = 0; i < pMS->getNumberOfModels(); i++)
+    {
+      if (i != 0)
+        out << ", ";
+      out << "model" + TextTools::toString(i + 1) + "=";
+      write(*pMS->getNModel(i), out, globalAliases, writtenNames);
+    }
+  }
+  else
+  {
+    const MixtureOfASubstitutionModel* pMS = dynamic_cast<const MixtureOfASubstitutionModel*>(&model);
+    out << "MixedModel(model=";
+    const SubstitutionModel* eM = pMS->getNModel(0);
+
+    ParameterList pl = eM->getIndependentParameters();
+    vector<string> vpl = pl.getParameterNames();
+
+    for (unsigned j = 0; j < vpl.size(); j++)
+    {
+      if (find(writtenNames.begin(), writtenNames.end(), vpl[j]) == writtenNames.end())
+      {
+        if (eM->getParameterNameWithoutNamespace(vpl[j]) == "rate")
+          writtenNames.push_back(vpl[j]);
+        else
+        {
+          const DiscreteDistribution* pDD = pMS->getDistribution(vpl[j]);
+          if (pDD && dynamic_cast<const ConstantDistribution*>(pDD) == NULL)
+          {
+            const BppODiscreteDistributionFormat* bIO = new BppODiscreteDistributionFormat();
+            StdStr sout;
+            bIO->write(*pDD, sout, globalAliases, writtenNames);
+            globalAliases[vpl[j]] = sout.str();
+            delete bIO;
+          }
+        }
+      }
+    }
+
+    write(*eM, out, globalAliases, writtenNames);
+
+    if (pMS->from() != -1)
+      out << ",from=" << model.getAlphabet()->intToChar(pMS->from()) << ",to=" << model.getAlphabet()->intToChar(pMS->to());
+  }
+
+  const BppOParametrizableFormat* bIO = new BppOParametrizableFormat();
+  bIO->write(&model, out, globalAliases, model.getIndependentParameters().getParameterNames(), writtenNames, true, true);
+  delete bIO;
+
+  out << ")";
+}
+
+void BppOSubstitutionModelFormat::initialize_(
+  SubstitutionModel& model,
+  const SiteContainer* data) throw (Exception)
+{
+  string initFreqs = ApplicationTools::getStringParameter(model.getNamespace() + "initFreqs", unparsedArguments_, "", "", true, false);
+  if (verbose_)
+    ApplicationTools::displayResult("External frequencies initialization for model", (initFreqs == "") ? "None" : initFreqs);
+
+  if (initFreqs != "")
+  {
+    if (initFreqs == "observed")
+    {
+      if (!data)
+        throw Exception("BppOSubstitutionModelFormat::initialize_(). Missing data for observed frequencies");
+      unsigned int psi = ApplicationTools::getParameter<unsigned int>(model.getNamespace() + "initFreqs.observedPseudoCount", unparsedArguments_, 0);
+      model.setFreqFromData(*data, psi);
+    }
+    else if (initFreqs.substr(0, 6) == "values")
+    {
+      // Initialization using the "values" argument
+      map<int, double> frequencies;
+
+      string rf = initFreqs.substr(6);
+      StringTokenizer strtok(rf.substr(1, rf.length() - 2), ",");
+      unsigned int i = 0;
+      while (strtok.hasMoreToken())
+        frequencies[i++] = TextTools::toDouble(strtok.nextToken());
+      model.setFreq(frequencies);
+    }
+    else
+      throw Exception("Unknown initFreqs argument");
+  }
+
+  ParameterList pl = model.getIndependentParameters();
+  for (size_t i = 0; i < pl.size(); i++)
+  {
+    AutoParameter ap(pl[i]);
+    ap.setMessageHandler(ApplicationTools::warning);
+    pl.setParameter(i, ap);
+  }
+  size_t posp;
+  for (size_t i = 0; i < pl.size(); i++)
+  {
+    const string pName = pl[i].getName();
+    posp = pName.rfind(".");
+    bool test1 = (initFreqs == "");
+    bool test2 = (model.getParameterNameWithoutNamespace(pName).size() < posp + 6) || (model.getParameterNameWithoutNamespace(pName).substr(posp + 1, 5) != "theta");
+    bool test3 = (unparsedArguments_.find(pName) != unparsedArguments_.end());
+    if (test1 || test2 || test3)
+    {
+      if (!test1 && !test2 && test3)
+        ApplicationTools::displayWarning("Warning, initFreqs argument is set and a value is set for parameter " + pName);
+      double value = ApplicationTools::getDoubleParameter(pName, unparsedArguments_, pl[i].getValue());
+      pl[i].setValue(value);
+    }
+    if (verbose_)
+      ApplicationTools::displayResult("Parameter found", pName + "=" + TextTools::toString(pl[i].getValue()));
+  }
+
+  model.matchParametersValues(pl);
+}
+
+
diff --git a/src/Bpp/Phyl/Io/BppOSubstitutionModelFormat.h b/src/Bpp/Phyl/Io/BppOSubstitutionModelFormat.h
new file mode 100644
index 0000000..e3d89b7
--- /dev/null
+++ b/src/Bpp/Phyl/Io/BppOSubstitutionModelFormat.h
@@ -0,0 +1,154 @@
+//
+// File: Bpp0SubstitutionModelFormat.h
+// Created by: Laurent Guéguen
+// Created on: mercredi 4 juillet 2012, à 13h 26
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _BPPOSUBSTITUTIONMODELFORMAT_H_
+#define _BPPOSUBSTITUTIONMODELFORMAT_H_
+
+#include "IoSubstitutionModelFactory.h"
+#include "../Model/MixedSubstitutionModel.h"
+
+namespace bpp
+{
+/**
+ * @brief Substitution model I/O in BppO format.
+ *
+ * Creates a new substitution model object according to model description syntax
+ * (see the Bio++ Progam Suite manual for a detailed description of this syntax).
+ *
+ */
+
+class BppOSubstitutionModelFormat :
+  public ISubstitutionModel,
+  public OSubstitutionModel
+{
+public:
+  static unsigned char DNA;
+  static unsigned char RNA;
+  static unsigned char NUCLEOTIDE;
+  static unsigned char PROTEIN;
+  static unsigned char CODON;
+  static unsigned char WORD;
+  static unsigned char BINARY;
+  static unsigned char ALL;
+
+private:
+  unsigned char alphabetCode_;
+  bool allowCovarions_;
+  bool allowMixed_;
+  bool allowGaps_;
+  bool verbose_;
+  std::map<std::string, std::string> unparsedArguments_;
+
+public:
+  /**
+   * @brief Create a new BppOSubstitutionModelFormat object.
+   *
+   * @param alphabetCode     Bit saying which alphabets are allowed in the model specification.
+   * @param allowCovarions   Tell is a covarion model can be returned.
+   * @param allowMixed       Tell is a mixture model can be returned.
+   * @param allowGaps        Tell is a gap model can be returned.
+   * @param verbose          Tell if the construction is verbose.
+   */
+  BppOSubstitutionModelFormat(unsigned char alphabetCode, bool allowCovarions, bool allowMixed, bool allowGaps, bool verbose):
+    alphabetCode_(alphabetCode),
+    allowCovarions_(allowCovarions),
+    allowMixed_(allowMixed),
+    allowGaps_(allowGaps),
+    verbose_(verbose),
+    unparsedArguments_()
+  {}
+
+  virtual ~BppOSubstitutionModelFormat() {}
+
+public:
+  const std::string getFormatName() const { return "BppO"; }
+
+  const std::string getFormatDescription() const { return "Bpp Options format."; }
+
+  SubstitutionModel* read(const Alphabet* alphabet, const std::string& modelDescription, const SiteContainer* data = 0, bool parseArguments = true);
+
+  const std::map<std::string, std::string>& getUnparsedArguments() const { return unparsedArguments_; }
+
+  /**
+   * @brief Write a substitution model to a stream.
+   *
+   * @param model A substitution model object;
+   * @param out The output stream;
+   * @param globalAliases parameters linked to global alias. The
+   * output will be "name=alias_name";
+   * @param writtenNames is the vector of the written
+   * parameters so far [in, out];
+   * @throw Exception If an error occured.
+   */
+  void write(const SubstitutionModel& model,
+             OutputStream& out,
+             std::map<std::string, std::string>& globalAliases,
+             std::vector<std::string>& writtenNames) const;
+
+private:
+  MixedSubstitutionModel* readMixed_(const Alphabet* alphabet, const std::string& modelDescription, const SiteContainer* data);
+
+  SubstitutionModel* readWord_(const Alphabet* alphabet, const std::string& modelDescription, const SiteContainer* data);
+
+  /**
+   * @brief Set parameter initial values of a given model according to options.
+   *
+   * Parameters actually depends on the model passed as argument.
+   * See getSubstitutionModel for more information.
+   *
+   * This function is mainly for internal usage, you're probably looking for the getSubstitutionModel or getSubstitutionModelSet function.
+   *
+   * @param model                   The model to set.
+   * @param data   A pointer toward the SiteContainer for which the substitution model is designed.
+   *               The alphabet associated to the data must be of the same type as the one specified for the model.
+   *               May be equal to NULL, but in this case use_observed_freq option will be unavailable.
+   * @throw Exception if an error occured.
+   */
+  void initialize_(SubstitutionModel& model, const SiteContainer* data) throw (Exception);
+
+  void writeMixed_(const MixedSubstitutionModel& model,
+             OutputStream& out,
+             std::map<std::string, std::string>& globalAliases,
+             std::vector<std::string>& writtenNames) const;
+};
+
+} // end of namespace bpp.
+
+#endif // _BPPOSUBSTITUTIONMODELFORMAT_H_
+
diff --git a/src/Bpp/Phyl/Io/IoDistanceMatrix.h b/src/Bpp/Phyl/Io/IoDistanceMatrix.h
new file mode 100755
index 0000000..8cb1bd6
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoDistanceMatrix.h
@@ -0,0 +1,173 @@
+//
+// File: IODistanceMatrix.h
+// Created by: Julien Dutheil
+// Created on: Wed Jun 08 15:43 2005
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _IODISTANCEMATRIX_H_
+#define _IODISTANCEMATRIX_H_
+
+#include <Bpp/Io/IoFormat.h>
+
+// From the STL:
+#include <iostream>
+#include <fstream>
+
+namespace bpp
+{
+
+class DistanceMatrix;
+
+/**
+ * @brief General interface for distance matrix I/O.
+ */
+class IODistanceMatrix:
+  public virtual IOFormat
+{
+	public:
+		IODistanceMatrix() {}
+		virtual ~IODistanceMatrix() {}
+
+	public:
+		virtual const std::string getDataType() const { return "Distance matrix"; }
+};
+
+/**
+ * @brief General interface for distance matrix readers.
+ */
+class IDistanceMatrix:
+  public virtual IODistanceMatrix
+{
+	public:
+		IDistanceMatrix() {}
+		virtual ~IDistanceMatrix() {}
+
+	public:
+    /**
+     * @brief Read a distance matrix from a file.
+     *
+     * @param path The file path.
+     * @return A new distance matrix object.
+     * @throw Exception If an error occured.
+     */
+		virtual DistanceMatrix* read(const std::string& path) const throw (Exception) = 0;
+    /**
+     * @brief Read a distance matrix from a stream.
+     *
+     * @param in The input stream.
+     * @return A new distance matrix object.
+     * @throw Exception If an error occured.
+     */
+		virtual DistanceMatrix* read(std::istream& in) const throw (Exception) = 0;
+};
+
+/**
+ * @brief General interface for distance matrix writers.
+ */
+class ODistanceMatrix:
+  public virtual IODistanceMatrix
+{
+	public:
+		ODistanceMatrix() {}
+		virtual ~ODistanceMatrix() {}
+
+	public:
+    /**
+     * @brief Write a distance matrix to a file.
+     *
+     * @param dist A distance matrix object.
+     * @param path The file path.
+     * @param overwrite Tell if existing file must be overwritten.
+     * Otherwise append to the file.
+     * @throw Exception If an error occured.
+     */
+		virtual void write(const DistanceMatrix& dist, const std::string& path, bool overwrite) const throw (Exception) = 0;
+    /**
+     * @brief Write a distance matrix to a stream.
+     *
+     * @param dist A distance matrix object.
+     * @param out The output stream.
+     * @throw Exception If an error occured.
+     */
+		virtual void write(const DistanceMatrix& dist, std::ostream& out) const throw (Exception) = 0;
+};
+
+/**
+ * @brief Partial implementation of the IDistanceMatrix interface.
+ */
+class AbstractIDistanceMatrix:
+  public virtual IDistanceMatrix
+{
+	public:
+		AbstractIDistanceMatrix() {}
+		virtual ~AbstractIDistanceMatrix() {}
+
+	public:
+		virtual DistanceMatrix* read(const std::string& path) const throw (Exception)
+		{
+      std::ifstream input(path.c_str(), std::ios::in);
+			DistanceMatrix* mat = read(input);
+			input.close();
+			return mat;
+		}
+		virtual DistanceMatrix* read(std::istream& in) const throw (Exception) = 0;
+};
+
+/**
+ * @brief Partial implementation of the ODistanceMatrix interface.
+ */
+class AbstractODistanceMatrix:
+  public virtual ODistanceMatrix
+{
+	public:
+		AbstractODistanceMatrix() {}
+		virtual ~AbstractODistanceMatrix() {}
+
+	public:
+		virtual void write(const DistanceMatrix& dist, const std::string& path, bool overwrite) const throw (Exception)
+		{
+			// Open file in specified mode
+      std::ofstream output(path.c_str(), overwrite ? (std::ios::out) : (std::ios::out|std::ios::app));
+			write(dist, output);
+			output.close();
+		}
+		virtual void write(const DistanceMatrix& dist, std::ostream& out) const throw (Exception) = 0;
+};
+
+} //end of namespace bpp.
+
+#endif //_IODISTANCEMATRIX_H_
+
diff --git a/src/Bpp/Phyl/Io/IoDistanceMatrixFactory.cpp b/src/Bpp/Phyl/Io/IoDistanceMatrixFactory.cpp
new file mode 100644
index 0000000..12f826f
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoDistanceMatrixFactory.cpp
@@ -0,0 +1,58 @@
+//
+// File IODistanceMatrixFactory.cpp
+// Created by: Julien Dutheil
+// Created on: Tue 18/04/06 10:24
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for sequences analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "IoDistanceMatrixFactory.h"
+#include "PhylipDistanceMatrixFormat.h"
+
+using namespace bpp;
+
+const std::string IODistanceMatrixFactory::PHYLIP_FORMAT = "Phylip"; 
+
+IDistanceMatrix* IODistanceMatrixFactory::createReader(const std::string& format) throw (Exception)
+{
+  if(format == PHYLIP_FORMAT) return new PhylipDistanceMatrixFormat();
+  else throw Exception("Format " + format + " is not supported for input.");
+}
+  
+ODistanceMatrix* IODistanceMatrixFactory::createWriter(const std::string& format) throw (Exception)
+{
+  if(format == PHYLIP_FORMAT) return new PhylipDistanceMatrixFormat();
+  else throw Exception("Format " + format + " is not supported for output.");
+}
+
diff --git a/src/Bpp/Phyl/Io/IoDistanceMatrixFactory.h b/src/Bpp/Phyl/Io/IoDistanceMatrixFactory.h
new file mode 100644
index 0000000..978e044
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoDistanceMatrixFactory.h
@@ -0,0 +1,101 @@
+//
+// File IODistanceMatrixFactory.h
+// Created by: Julien Dutheil
+// Created on: Tue 18/04/06 10:24
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for sequences analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _IODISTANCEMATRIXFACTORY_H_
+#define _IODISTANCEMATRIXFACTORY_H_
+
+#include "../Distance/DistanceEstimation.h"
+#include "IoDistanceMatrix.h"
+#include <Bpp/Exceptions.h>
+
+//From the STL:
+#include <string>
+
+namespace bpp
+{
+
+/**
+ * @brief Utilitary class for creating distance matrix readers and writers.
+ *
+ * @see IOSequenceFactory
+ * @see IOTreeFactory
+ */
+class IODistanceMatrixFactory
+{
+public:
+  static const std::string PHYLIP_FORMAT;  
+
+public:
+
+  /**
+   * @brief Creates a new factory object.
+   *
+   * Example:
+   * @code
+   * IDistanceMatrix * matReader = IODistanceMatrixFactory().createReader(IODistanceMatrixFactory::PHYLIP);
+   * DistanceMatrix * matrix = matReader->read("file.ph");
+   * delete matReader;
+   * @endcode
+   */
+  IODistanceMatrixFactory() {}
+  virtual ~IODistanceMatrixFactory() {}
+  
+  /**
+   * @brief Get a new dynamically created IDistanceMatrix object.
+   *
+   * @param format The input file format.
+   * @return A pointer toward a new IDistanceMatrix object.
+   * @throw Exception If the format name do not match any available format.
+   */
+  virtual IDistanceMatrix* createReader(const std::string& format) throw (Exception);
+  
+  /**
+   * @brief Get a new dynamically created ODistanceMatrix object.
+   *
+   * @param format The output file format.
+   * @return A pointer toward a new ODistanceMatrix object.
+   * @throw Exception If the format name do not match any available format.
+   */
+  virtual ODistanceMatrix * createWriter(const std::string& format) throw (Exception);
+};
+
+} //end of namespace bpp.
+
+#endif //_IODISTANCEMATRIXFACTORY_H_
+
diff --git a/src/Bpp/Phyl/Io/IoFrequenciesSet.h b/src/Bpp/Phyl/Io/IoFrequenciesSet.h
new file mode 100644
index 0000000..180c18f
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoFrequenciesSet.h
@@ -0,0 +1,129 @@
+//
+// File: IoFrequenciesSet.h
+// Created by: Laurent Guéguen
+// Created on: lundi 9 juillet 2012, à 12h 49
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _IOFREQUENCIESSET_H_
+#define _IOFREQUENCIESSET_H_
+
+#include "../Model/FrequenciesSet/FrequenciesSet.h"
+
+//From bpp-core:
+#include <Bpp/Exceptions.h>
+#include <Bpp/Io/IoFormat.h>
+#include <Bpp/Io/OutputStream.h>
+
+//From bpp-seq:
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+namespace bpp
+{
+
+  class FrequenciesSet;
+
+  /**
+   * @brief General interface for model I/O.
+   */
+  class IoFrequenciesSet:
+    public virtual IOFormat
+  {
+  public:
+    IoFrequenciesSet() {}
+    virtual ~IoFrequenciesSet() {}
+
+  public:
+    virtual const std::string getDataType() const { return "Frequencies Set"; }
+  };
+
+  /**
+   * @brief General interface for distance matrix readers.
+   */
+  class IFrequenciesSet:
+    public virtual IoFrequenciesSet
+  {
+  public:
+    IFrequenciesSet() {}
+    virtual ~IFrequenciesSet() {}
+
+  public:
+    /**
+     * @brief Read a frequencies set from a string.
+     *
+     * @param alphabet         The alpabet to use in the model.
+     * @param freqDescription  A string describing the frequencies set.
+     * @param data             A SiteContainer with the data to use to initialize fequency parameters. Can be set to 0.
+     * @param parseArguments   Attempt to parse function arguments. If not, only store them and use default values instead.
+     * @return A new FrequenciesSet object according to options specified.
+     * @throw Exception if an error occured.
+     */
+    virtual FrequenciesSet* read(const Alphabet* alphabet, const std::string& freqDescription, const SiteContainer* data, bool parseArguments) = 0;
+
+    /**
+     * @return The arguments and their unparsed values from the last call of the read function, if there are any.
+     */
+    virtual const std::map<std::string, std::string>& getUnparsedArguments() const = 0;
+  };
+
+  /**
+   * @brief General interface for distance matrix writers.
+   */
+  class OFrequenciesSet:
+    public virtual IoFrequenciesSet
+  {
+  public:
+    OFrequenciesSet() {}
+    virtual ~OFrequenciesSet() {}
+
+  public:
+    /**
+     * @brief Write a substitution model to a stream.
+     *
+     * @param pfreqset A pointer towards a frequencies set object;
+     * @param out The output stream;
+     * @param writtenNames is the vector of the written
+     * parameters so far [in, out];
+     */
+    virtual void write(const FrequenciesSet* pfreqset,
+                       OutputStream& out,
+                       std::vector<std::string>& writtenNames) const = 0;
+  };
+
+
+} //end of namespace bpp.
+
+#endif //_IOFREQUENCIESSET_H_
+
diff --git a/src/Bpp/Phyl/Io/IoFrequenciesSetFactory.cpp b/src/Bpp/Phyl/Io/IoFrequenciesSetFactory.cpp
new file mode 100644
index 0000000..cd95717
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoFrequenciesSetFactory.cpp
@@ -0,0 +1,57 @@
+//
+// File IOFrequenciesSetFactory.cpp
+// Created by: Laurent Guéguen
+// Created on: lundi 9 juillet 2012, à 12h 59
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for sequences analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "BppOFrequenciesSetFormat.h"
+
+using namespace bpp;
+
+const std::string IOFrequenciesSetFactory::BPPO_FORMAT = "Bpp0"; 
+
+IFrequenciesSet* IOFrequenciesSetFactory::createReader(const std::string& format) throw (Exception)
+{
+  if(format == BPPO_FORMAT) return new BppOFrequenciesSetFormat(BppOFrequenciesSetFormat::ALL, true);
+  else throw Exception("Format " + format + " is not supported for input.");
+}
+  
+OFrequenciesSet* IOFrequenciesSetFactory::createWriter(const std::string& format) throw (Exception)
+{
+  if(format == BPPO_FORMAT) return new BppOFrequenciesSetFormat(BppOFrequenciesSetFormat::ALL, true);
+  else throw Exception("Format " + format + " is not supported for output.");
+}
+
diff --git a/src/Bpp/Phyl/Io/IoFrequenciesSetFactory.h b/src/Bpp/Phyl/Io/IoFrequenciesSetFactory.h
new file mode 100644
index 0000000..8996104
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoFrequenciesSetFactory.h
@@ -0,0 +1,101 @@
+//
+// File IOFrequenciesSetFactory.h
+// Created by: Laurent Guéguen
+// Created on: lundi 9 juillet 2012, à 12h 58
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for sequences analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _IOFREQUENCIESSETFACTORY_H_
+#define _IOFREQUENCIESSETFACTORY_H_
+
+#include "../Model/SubstitutionModel.h"
+#include "IoFrequenciesSet.h"
+#include <Bpp/Exceptions.h>
+
+//From the STL:
+#include <string>
+
+namespace bpp
+{
+
+/**
+ * @brief Utilitary class for creating frequencies set readers and writers.
+ *
+ * @see IOSequenceFactory
+ * @see IOTreeFactory
+ */
+class IOFrequenciesSetFactory
+{
+public:
+  static const std::string BPPO_FORMAT;  
+
+public:
+
+  /**
+   * @brief Creates a new factory object.
+   *
+   * Example:
+   * @code
+   * IFrequenciesSet * freqReader = IOFrequenciesSetFactory().createReader(IOFrequenciesSetFactory::BPP_FORMAT);
+   * FrequenciesSet * freqset = freqReader->read(...);
+   * delete freqReader;
+   * @endcode
+   */
+  IOFrequenciesSetFactory() {}
+  virtual ~IOFrequenciesSetFactory() {}
+  
+  /**
+   * @brief Get a new dynamically created IFrequenciesSet object.
+   *
+   * @param format The input file format.
+   * @return A pointer toward a new IFrequenciesSet object.
+   * @throw Exception If the format name do not match any available format.
+   */
+  virtual IFrequenciesSet* createReader(const std::string& format) throw (Exception);
+  
+  /**
+   * @brief Get a new dynamically created OFrequenciesSet object.
+   *
+   * @param format The output file format.
+   * @return A pointer toward a new OFrequenciesSet object.
+   * @throw Exception If the format name do not match any available format.
+   */
+  virtual OFrequenciesSet * createWriter(const std::string& format) throw (Exception);
+};
+
+} //end of namespace bpp.
+
+#endif //_IOFREQUENCIESSETFACTORY_H_
+
diff --git a/src/Bpp/Phyl/Io/IoPairedSiteLikelihoods.cpp b/src/Bpp/Phyl/Io/IoPairedSiteLikelihoods.cpp
new file mode 100644
index 0000000..f37c75f
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoPairedSiteLikelihoods.cpp
@@ -0,0 +1,276 @@
+//
+// File: PairedSiteLikelihoods.cpp
+// Created by: Nicolas Rochette
+// Created on: January 10, 2011
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+// From the STL
+#include <vector>
+#include <numeric>
+
+// From Bio++
+#include <Bpp/Text/TextTools.h>
+#include "../Likelihood/PairedSiteLikelihoods.h"
+
+#include "IoPairedSiteLikelihoods.h"
+
+using namespace std;
+using namespace bpp;
+
+/*
+ * Read from a stream in Tree-puzzle, phylip-like format
+ */
+PairedSiteLikelihoods IOTreepuzzlePairedSiteLikelihoods::read(std::istream& is) throw (Exception)
+{
+  // The first line contains the number of models and the number of sites
+  string line;
+  getline(is, line);
+  istringstream iss (line);
+  size_t nmodels, nsites;
+  iss >> nmodels;
+  iss >> nsites;
+
+  // Then each line contains a model name and site loglikelihoods under this model
+  vector<string> names;
+  vector<vector<double> > loglikelihoods;
+  loglikelihoods.reserve(nmodels);
+
+  // The exact format is determined upon the first line
+  // Name and likelihoods fields can be delimited by either a tab or two spaces
+  string delim;
+  streampos pos (is.tellg());
+  getline(is, line);
+  if (line.find("\t") != string::npos)
+    delim = "\t";
+  else if (line.find("  ") != string::npos)
+    delim = "  ";
+  else
+    throw;
+  is.seekg(pos);
+
+  // Read the data
+  while (getline(is, line))
+  {
+    size_t delim_pos (line.find(delim));
+    if (delim_pos == string::npos)
+    {
+      ostringstream msg;
+      msg << "IOTreepuzzlePairedSiteLikelihoods::read: Couldn't find delimiter. The beggining of the line was : "
+          << endl << line.substr(0, 100);
+      throw Exception(msg.str());
+    }
+
+    // The name
+    names.push_back( TextTools::removeSurroundingWhiteSpaces(line.substr(0, delim_pos)) );
+
+    // The sites
+    loglikelihoods.push_back(vector<double>());
+    loglikelihoods.back().reserve(nsites);
+
+    istringstream liks_stream ( line.substr(delim_pos) );
+    double currllik;
+    while (liks_stream >> currllik)
+      loglikelihoods.back().push_back(currllik);
+
+    // Check the number of sites
+    if (loglikelihoods.back().size() != nsites)
+    {
+      ostringstream oss;
+      oss << "IOTreepuzzlePairedSiteLikelihoods::read: Model '" << names.back()
+          << "' does not have the correct number of sites. ("
+          << loglikelihoods.back().size() << ", expected: " << nsites << ")";
+      throw Exception(oss.str());
+    }
+  }
+
+  // Check the number of models
+  if (loglikelihoods.size() != nmodels)
+    throw Exception("IOTreepuzzlePairedSiteLikelihoods::read: Wrong number of models.");
+
+  PairedSiteLikelihoods psl (loglikelihoods, names);
+
+  return psl;
+}
+
+/*
+ * Read from a file in Tree-puzzle, phylip-like format
+ */
+PairedSiteLikelihoods IOTreepuzzlePairedSiteLikelihoods::read(const std::string& path) throw (Exception)
+{
+  ifstream iF (path.c_str());
+  PairedSiteLikelihoods psl (IOTreepuzzlePairedSiteLikelihoods::read(iF));
+  return psl;
+}
+
+/*
+ * Write to stream in Tree-puzzle, phylip-like format
+ */
+void IOTreepuzzlePairedSiteLikelihoods::write(const bpp::PairedSiteLikelihoods& psl, ostream& os, const string& delim)
+{
+  if (!psl.getLikelihoods().size() > 0)
+    throw Exception("Writing an empty PairedSiteLikelihoods object to file.");
+
+  // Header line
+  os << psl.getNumberOfModels() << " " << psl.getNumberOfSites() << endl;
+
+  // Data lines
+
+  if (delim == "\t")
+  {
+    // The delimiter is a tab
+    for (size_t i = 0; i < psl.getNumberOfModels(); ++i)
+    {
+      os << psl.getModelNames().at(i) << "\t";
+      for (vector<double>::const_iterator sitelik = psl.getLikelihoods().at(i).begin();
+           sitelik != psl.getLikelihoods().at(i).end();
+           ++sitelik)
+      {
+        if (sitelik == psl.getLikelihoods().at(i).end() - 1)
+          os << *sitelik;
+        else
+          os << *sitelik << " ";
+      }
+      os << endl;
+    }
+  }
+
+  else if (delim == "  ")
+  // The delimiter is two spaces
+  {
+    // First we must get the length of the names field
+    vector<size_t> name_sizes;
+    for (vector<string>::const_iterator name = psl.getModelNames().begin();
+         name != psl.getModelNames().end();
+         ++name)
+    {
+      name_sizes.push_back(name->size());
+    }
+    size_t names_field_size = *max_element(name_sizes.begin(), name_sizes.end()) + 2;
+
+    // Data lines
+    for (size_t i = 0; i < psl.getNumberOfModels(); ++i)
+    {
+      // name field
+      string name (psl.getModelNames().at(i));
+      while (name.size() != names_field_size)
+        name.append(" ");
+      os << name;
+
+      // site-likelihoods field
+      for (vector<double>::const_iterator sitelik = psl.getLikelihoods().at(i).begin();
+           sitelik != psl.getLikelihoods().at(i).end();
+           ++sitelik)
+      {
+        if (sitelik == psl.getLikelihoods().at(i).end() - 1)
+          os << *sitelik;
+        else
+          os << *sitelik << " ";
+      }
+      os << endl;
+    }
+  }
+
+  else
+  {
+    ostringstream msg;
+    msg << "IOTreepuzzlePairedSiteLikelihoods::write: Unknown field delimiter "
+        << "\"" << delim << "\".";
+    os << msg.str() << endl;
+    throw Exception(msg.str());
+  }
+}
+
+
+/*
+ * Write to file in Tree-puzzle, phylip-like format
+ */
+void IOTreepuzzlePairedSiteLikelihoods::write(const bpp::PairedSiteLikelihoods& psl, const std::string& path, const string& delim)
+{
+  ofstream oF (path.c_str());
+  IOTreepuzzlePairedSiteLikelihoods::write(psl, oF, delim);
+}
+
+
+/*
+ * Read from a stream in Phyml format
+ */
+vector<double> IOPhymlPairedSiteLikelihoods::read(std::istream& is) throw (Exception)
+{
+  vector<double> loglikelihoods;
+  string str;
+
+  // check the format, with first line
+  getline(is, str);
+  string expected ("Note : P(D|M) is the probability of site D given the model M (i.e., the site likelihood)");
+  if (str.find(expected) == string::npos) // \r\n handling
+  {
+    ostringstream msg;
+    msg << "IOPhymlPairedSiteLikelihoods::read: The first line was expected to be :"
+        << expected << endl
+        << "and was :" << endl
+        << str << endl;
+    throw Exception(msg.str());
+  }
+
+  // skip header lines
+  for (int i = 0; i < 6; ++i)
+  {
+    getline(is, str);
+  }
+
+  while (getline(is, str))
+  {
+    // the site likelihood is the second field on the line
+    istringstream ss (str);
+    ss >> str;
+    double lik;
+    ss >> lik;
+    loglikelihoods.push_back(log(lik));
+  }
+
+  return loglikelihoods;
+}
+
+/*
+ * Read from a file in Phyml format
+ */
+vector<double> IOPhymlPairedSiteLikelihoods::read(const std::string& path) throw (Exception)
+{
+  ifstream iF (path.c_str());
+  vector<double> loglikelihoods(IOPhymlPairedSiteLikelihoods::read(iF));
+  return loglikelihoods;
+}
+
diff --git a/src/Bpp/Phyl/Io/IoPairedSiteLikelihoods.h b/src/Bpp/Phyl/Io/IoPairedSiteLikelihoods.h
new file mode 100644
index 0000000..b893f13
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoPairedSiteLikelihoods.h
@@ -0,0 +1,126 @@
+//
+// File: PairedSiteLikelihoods.h
+// Created by: Nicolas Rochette
+// Created on: January 10, 2011
+//
+
+/*
+   Copyright or © or Copr. Bio++ Developent Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _IOPAIREDSITELIKELIHOODS_H_
+#define _IOPAIREDSITELIKELIHOODS_H_
+
+// From the STL:
+#include <vector>
+#include <string>
+#include <sstream>
+
+// From Bio++
+#include <Bpp/Io/IoFormat.h>
+#include "../Likelihood/PairedSiteLikelihoods.h"
+
+namespace bpp
+{
+/**
+ * @brief Base class for I/O on paired-site likelihoods.
+ *
+ * @author Nicolas Rochette
+ */
+class IOPairedSiteLikelihoods : public virtual IOFormat
+{};
+
+
+/**
+ * @brief This class provides I/O for the Tree-Puzzle/RAxML (phylip-like) paired-site likelihoods format.
+ *
+ * @author Nicolas Rochette
+ */
+class IOTreepuzzlePairedSiteLikelihoods : public virtual IOPairedSiteLikelihoods
+{
+public:
+  /**
+   * @brief Read paired-site likelihoods from a Treepuzzle/RAxML-formatted stream.
+   *
+   * @throw Exception If the format is not recognized.
+   */
+  static PairedSiteLikelihoods read(std::istream& is) throw (Exception);
+
+  /**
+   * @brief Read paired-site likelihoods from a Treepuzzle/RAxML-formatted file.
+   *
+   * @throw Exception If the format is not recognized.
+   */
+  static PairedSiteLikelihoods read(const std::string& path) throw (Exception);
+
+  /**
+   * @brief Write paired-site likelihoods to a stream.
+   *
+   * @param psl The PairedSiteLikelihoods object to write.
+   * @param os The output stream.
+   * @param delim The delimiter between model names and likelihoods. The defaut is a tab but two spaces might be used.
+   */
+  static void write(const PairedSiteLikelihoods& psl, std::ostream& os, const std::string& delim = "\t");
+
+  /**
+   * @brief Write paired-site likelihoods to a file.
+   *
+   * @param psl The PairedSiteLikelihoods object to write.
+   * @param path The path of the output file.
+   * @param delim The delimiter between model names and likelihoods. (The defaut is a tab but two spaces might be used.)
+   */
+  static void write(const PairedSiteLikelihoods& psl, const std::string& path, const std::string& delim = "\t");
+};
+
+
+/**
+ * @brief This class provides input for the Phyml paired-site likelihoods format.
+ *
+ * @author Nicolas Rochette
+ */
+class IOPhymlPairedSiteLikelihoods : public virtual IOPairedSiteLikelihoods
+{
+public:
+  /**
+   * @brief Read paired-site likelihoods from a Phyml-formatted stream.
+   * @throw Exception If the format is not recognized.
+   */
+  static std::vector<double> read(std::istream& is) throw (Exception);
+
+  /**
+   * @brief Read Phyml paired-site likelihoods from a Phyml-formatted file.
+   * @throw Exception If the format is not recognized.
+   */
+  static std::vector<double> read(const std::string& path) throw (Exception);
+};
+} // namespace bpp
+#endif
diff --git a/src/Bpp/Phyl/Io/IoSubstitutionModel.h b/src/Bpp/Phyl/Io/IoSubstitutionModel.h
new file mode 100755
index 0000000..2c7d119
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoSubstitutionModel.h
@@ -0,0 +1,138 @@
+//
+// File: IoSubstitutionModel.h
+// Created by: Laurent Guéguen
+// Created on: mercredi 4 juillet 2012, à 13h 03
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _IOSUBSTITUTIONMODEL_H_
+#define _IOSUBSTITUTIONMODEL_H_
+
+#include "../Model/SubstitutionModel.h"
+
+//From bpp-core:
+#include <Bpp/Exceptions.h>
+#include <Bpp/Io/IoFormat.h>
+#include <Bpp/Io/OutputStream.h>
+
+//From bpp-seq:
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+namespace bpp
+{
+
+  class SubstitutionModel;
+
+  /**
+   * @brief General interface for model I/O.
+   */
+  class IoSubstitutionModel:
+    public virtual IOFormat
+  {
+  public:
+    IoSubstitutionModel() {}
+    virtual ~IoSubstitutionModel() {}
+
+  public:
+    virtual const std::string getDataType() const { return "Substitution Model"; }
+  };
+
+  /**
+   * @brief General interface for distance matrix readers.
+   */
+  class ISubstitutionModel:
+    public virtual IoSubstitutionModel
+  {
+  public:
+    ISubstitutionModel() {}
+    virtual ~ISubstitutionModel() {}
+
+  public:
+    /**
+     * @brief Read a substitution model from a string.
+     *
+     * @param alphabet         The alpabet to use in the model.
+     * @param modelDescription A string describing the model in the format.
+     * @param data             A pointer toward a SiteContainer, which can be used to initial some parmaeters like frequencies.
+     * @param parseArguments Attempt to parse function arguments. If not, only store them and use default values instead.
+     * @return A new SubstitutionModel object according to options specified.
+     * @throw Exception if an error occured.
+     */
+
+    virtual SubstitutionModel* read(const Alphabet* alphabet,
+                                    const std::string& modelDescription,
+                                    const SiteContainer* data = 0,
+                                    bool parseArguments = true) = 0;
+
+    /**
+     * @return The arguments and their unparsed values from the last call of the read function, if there are any.
+     */
+    virtual const std::map<std::string, std::string>& getUnparsedArguments() const = 0;
+
+
+  };
+
+  /**
+   * @brief General interface for distance matrix writers.
+   */
+  class OSubstitutionModel:
+    public virtual IoSubstitutionModel
+  {
+  public:
+    OSubstitutionModel() {}
+    virtual ~OSubstitutionModel() {}
+
+  public:
+    /**
+     * @brief Write a substitution model to a stream.
+     *
+     * @param model A substitution model object;
+     * @param out The output stream;
+     * @param globalAliases parameters linked to global alias. 
+     * @param writtenNames is the vector of the written
+     * parameters so far [in, out];
+     * @throw Exception if an error occured.
+     */
+    virtual void write(const SubstitutionModel& model,
+                       OutputStream& out,
+                       std::map<std::string, std::string>& globalAliases,
+                       std::vector<std::string>& writtenNames) const = 0;
+  };
+
+
+} //end of namespace bpp.
+
+#endif //_IOSUBSTITUTIONMODEL_H_
+
diff --git a/src/Bpp/Phyl/Io/IoSubstitutionModelFactory.cpp b/src/Bpp/Phyl/Io/IoSubstitutionModelFactory.cpp
new file mode 100644
index 0000000..babe7aa
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoSubstitutionModelFactory.cpp
@@ -0,0 +1,57 @@
+//
+// File IOSubstitutionModelFactory.cpp
+// Created by: Laurent Guéguen
+// Created on: mercredi 4 juillet 2012, à 13h 22
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for sequences analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "BppOSubstitutionModelFormat.h"
+
+using namespace bpp;
+
+const std::string IOSubstitutionModelFactory::BPPO_FORMAT = "Bpp0"; 
+
+ISubstitutionModel* IOSubstitutionModelFactory::createReader(const std::string& format) throw (Exception)
+{
+  if (format == BPPO_FORMAT) return new BppOSubstitutionModelFormat(BppOSubstitutionModelFormat::ALL, true, true, true, true);
+  else throw Exception("Format " + format + " is not supported for input.");
+}
+  
+OSubstitutionModel* IOSubstitutionModelFactory::createWriter(const std::string& format) throw (Exception)
+{
+  if(format == BPPO_FORMAT) return new BppOSubstitutionModelFormat(BppOSubstitutionModelFormat::ALL, true, true, true, true);
+  else throw Exception("Format " + format + " is not supported for output.");
+}
+
diff --git a/src/Bpp/Phyl/Io/IoSubstitutionModelFactory.h b/src/Bpp/Phyl/Io/IoSubstitutionModelFactory.h
new file mode 100644
index 0000000..092c0a9
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoSubstitutionModelFactory.h
@@ -0,0 +1,102 @@
+//
+// File IOSubstitutionModelFactory.h
+// Created by: Laurent Guéguen
+// Created on: mercredi 4 juillet 2012, à 13h 20
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for sequences analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _IOSUBSTITUTIONMODELFACTORY_H_
+#define _IOSUBSTITUTIONMODELFACTORY_H_
+
+#include "../Model/SubstitutionModel.h"
+#include "IoSubstitutionModel.h"
+#include <Bpp/Exceptions.h>
+
+//From the STL:
+#include <string>
+
+namespace bpp
+{
+
+/**
+ * @brief Utilitary class for creating substitution model readers and
+ * writers.
+ *
+ * @see IOSequenceFactory
+ * @see IOTreeFactory
+ */
+class IOSubstitutionModelFactory
+{
+public:
+  static const std::string BPPO_FORMAT;  
+
+public:
+
+  /**
+   * @brief Creates a new factory object.
+   *
+   * Example:
+   * @code
+   * ISubstitutionModel * modReader = IOSubstitutionModelFactory().createReader(IOSubstitutionModelFactory::BPP_FORMAT);
+   * SubstitutionModel * model = modReader->read(...);
+   * delete modReader;
+   * @endcode
+   */
+  IOSubstitutionModelFactory() {}
+  virtual ~IOSubstitutionModelFactory() {}
+  
+  /**
+   * @brief Get a new dynamically created ISubstitutionModel object.
+   *
+   * @param format The input file format.
+   * @return A pointer toward a new ISubstitutionModel object.
+   * @throw Exception If the format name do not match any available format.
+   */
+  virtual ISubstitutionModel* createReader(const std::string& format) throw (Exception);
+  
+  /**
+   * @brief Get a new dynamically created OSubstitutionModel object.
+   *
+   * @param format The output file format.
+   * @return A pointer toward a new OSubstitutionModel object.
+   * @throw Exception If the format name do not match any available format.
+   */
+  virtual OSubstitutionModel * createWriter(const std::string& format) throw (Exception);
+};
+
+} //end of namespace bpp.
+
+#endif //_IOSUBSTITUTIONMODELFACTORY_H_
+
diff --git a/src/Bpp/Phyl/Io/IoTree.h b/src/Bpp/Phyl/Io/IoTree.h
new file mode 100755
index 0000000..97ad791
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoTree.h
@@ -0,0 +1,295 @@
+//
+// File: IOTree.h
+// Created by: Julien Dutheil
+// Created on: Thu Oct 23 15:19:06 2003
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _IOTREE_H_
+#define _IOTREE_H_
+
+#include "../Tree.h"
+
+// From the STL:
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include <Bpp/Exceptions.h>
+#include <Bpp/Io/IoFormat.h>
+
+namespace bpp
+{
+
+/**
+ * @brief General interface for tree I/O.
+ */
+class IOTree:
+  public virtual IOFormat
+{
+	public:
+		IOTree() {}
+		virtual ~IOTree() {}
+
+	public:
+		virtual const std::string getDataType() const { return "Tree"; }
+};
+
+/**
+ * @brief General interface for tree readers.
+ */
+class ITree:
+  public virtual IOTree
+{
+	public:
+		ITree() {}
+		virtual ~ITree() {}
+
+	public:
+    /**
+     * @brief Read a tree from a file.
+     *
+     * @param path The file path.
+     * @return A new tree object.
+     * @throw Exception If an error occured.
+     */
+		virtual Tree* read(const std::string& path) const throw (Exception) = 0;
+    /**
+     * @brief Read a tree from a stream.
+     *
+     * @param in The input stream.
+     * @return A new tree object.
+     * @throw Exception If an error occured.
+     */
+		virtual Tree* read(std::istream& in) const throw (Exception) = 0;
+};
+
+/**
+ * @brief General interface for tree writers.
+ */
+class OTree:
+  public virtual IOTree
+{
+	public:
+		OTree() {}
+		virtual ~OTree() {}
+
+	public:
+    /**
+     * @brief Write a tree to a file.
+     *
+     * @param tree A tree object.
+     * @param path The file path.
+     * @param overwrite Tell if existing file must be overwritten.
+     * Otherwise append to the file.
+     * @throw Exception If an error occured.
+     */
+		virtual void write(const Tree& tree, const std::string& path, bool overwrite) const throw (Exception) = 0;
+    /**
+     * @brief Write a tree to a stream.
+     *
+     * @param tree A tree object.
+     * @param out The output stream.
+     * @throw Exception If an error occured.
+     */
+		virtual void write(const Tree& tree, std::ostream& out) const throw (Exception) = 0;
+};
+
+/**
+ * @brief Partial implementation of the ITree interface.
+ */
+class AbstractITree:
+  public virtual ITree
+{
+	public:
+		AbstractITree() {}
+		virtual ~AbstractITree() {}
+
+	public:
+		virtual Tree* read(std::istream& in) const throw (Exception) = 0;
+		virtual Tree* read(const std::string& path) const throw (Exception)
+		{
+      std::ifstream input(path.c_str(), std::ios::in);
+			Tree* tree = read(input);
+			input.close();
+			return tree;
+		}
+
+};
+
+/**
+ * @brief Partial implementation of the OTree interface.
+ */
+class AbstractOTree:
+  public virtual OTree
+{
+	public:
+		AbstractOTree() {}
+		virtual ~AbstractOTree() {}
+
+	public:
+		void write(const Tree& tree, std::ostream& out) const throw (Exception) = 0;
+		virtual void write(const Tree& tree, const std::string& path, bool overwrite) const throw (Exception)
+		{
+		  try {
+			// Open file in specified mode
+		    std::ofstream output(path.c_str(), overwrite ? (std::ios::out) : (std::ios::out|std::ios::app));
+		    write(tree, output);
+		    output.close();
+		  }
+		  catch (IOException e)
+		    {
+		      std::stringstream ss ;
+		      ss << e.what() <<"\nProblem writing tree to file "<< path <<"\n Is the file path correct and do \
+you have the proper authorizations? ";
+		      throw (IOException ( ss.str() ) );
+		    }
+
+		}
+};
+
+
+
+
+
+
+
+/**
+ * @brief General interface for multiple trees readers.
+ */
+class IMultiTree:
+  public virtual IOTree
+{
+	public:
+		IMultiTree() {}
+		virtual ~IMultiTree() {}
+
+	public:
+    /**
+     * @brief Read trees from a file.
+     *
+     * @param path The file path.
+     * @param trees The output trees container.
+     * @throw Exception If an error occured.
+     */
+		virtual void read(const std::string& path, std::vector<Tree*>& trees) const throw (Exception) = 0;
+    /**
+     * @brief Read trees from a stream.
+     *
+     * @param in The input stream.
+     * @param trees The output trees container.
+     * @throw Exception If an error occured.
+     */
+		virtual void read(std::istream& in, std::vector<Tree*>& trees) const throw (Exception) = 0;
+};
+
+/**
+ * @brief General interface for tree writers.
+ */
+class OMultiTree:
+  public virtual IOTree
+{
+	public:
+		OMultiTree() {}
+		virtual ~OMultiTree() {}
+
+	public:
+    /**
+     * @brief Write trees to a file.
+     *
+     * @param trees A vector of tree objects.
+     * @param path The file path.
+     * @param overwrite Tell if existing file must be overwritten.
+     * Otherwise append to the file.
+     * @throw Exception If an error occured.
+     */
+		virtual void write(const std::vector<Tree*>& trees, const std::string& path, bool overwrite) const throw (Exception) = 0;
+    /**
+     * @brief Write trees to a stream.
+     *
+     * @param trees A vector of tree objects.
+     * @param out The output stream.
+     * @throw Exception If an error occured.
+     */
+		virtual void write(const std::vector<Tree*>& trees, std::ostream& out) const throw (Exception) = 0;
+};
+
+/**
+ * @brief Partial implementation of the IMultiTree interface.
+ */
+class AbstractIMultiTree:
+  public virtual IMultiTree
+{
+	public:
+		AbstractIMultiTree() {}
+		virtual ~AbstractIMultiTree() {}
+
+	public:
+		virtual void read(std::istream& in, std::vector<Tree*>& trees) const throw (Exception) = 0;
+		virtual void read(const std::string& path, std::vector<Tree*>& trees) const throw (Exception)
+		{
+      std::ifstream input(path.c_str(), std::ios::in);
+			read(input, trees);
+			input.close();
+		}
+
+};
+
+/**
+ * @brief Partial implementation of the OTree interface.
+ */
+class AbstractOMultiTree:
+  public virtual OMultiTree
+{
+	public:
+		AbstractOMultiTree() {}
+		virtual ~AbstractOMultiTree() {}
+
+	public:
+		void write(const std::vector<Tree*>& trees, std::ostream& out) const throw (Exception) = 0;
+		virtual void write(const std::vector<Tree*>& trees, const std::string& path, bool overwrite) const throw (Exception)
+		{
+			// Open file in specified mode
+      std::ofstream output(path.c_str(), overwrite ? (std::ios::out) : (std::ios::out|std::ios::app));
+			write(trees, output);
+			output.close();
+		}
+};
+
+} //end of namespace bpp.
+
+#endif	//_IOTREE_H_
+
diff --git a/src/Bpp/Phyl/Io/IoTreeFactory.cpp b/src/Bpp/Phyl/Io/IoTreeFactory.cpp
new file mode 100644
index 0000000..758182c
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoTreeFactory.cpp
@@ -0,0 +1,66 @@
+//
+// File IOTreeFactory.cpp
+// Created by: Julien Dutheil
+// Created on: Tue 18/04/06 10:24
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for sequences analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "IoTreeFactory.h"
+#include "Newick.h"
+#include "NexusIoTree.h"
+#include "Nhx.h"
+
+using namespace bpp;
+
+const std::string IOTreeFactory::NEWICK_FORMAT = "Newick"; 
+const std::string IOTreeFactory::NEXUS_FORMAT = "Nexus"; 
+const std::string IOTreeFactory::NHX_FORMAT = "Nhx"; 
+
+ITree* IOTreeFactory::createReader(const std::string& format) throw (Exception)
+{
+       if (format == NEWICK_FORMAT) return new Newick();
+  else if (format == NEXUS_FORMAT) return new NexusIOTree();
+  else if (format == NHX_FORMAT) return new Nhx();
+  else throw Exception("Format " + format + " is not supported for input.");
+}
+  
+OTree* IOTreeFactory::createWriter(const std::string& format) throw (Exception)
+{
+       if (format == NEWICK_FORMAT) return new Newick();
+  else if (format == NEXUS_FORMAT) return new NexusIOTree();
+  else if (format == NHX_FORMAT) return new Nhx();
+  else throw Exception("Format " + format + " is not supported for output.");
+}
+
diff --git a/src/Bpp/Phyl/Io/IoTreeFactory.h b/src/Bpp/Phyl/Io/IoTreeFactory.h
new file mode 100644
index 0000000..f87e594
--- /dev/null
+++ b/src/Bpp/Phyl/Io/IoTreeFactory.h
@@ -0,0 +1,98 @@
+//
+// File IOTreeFactory.h
+// Created by: Julien Dutheil
+// Created on: Tue 18/04/06 10:24
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for sequences analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _IOTREEFACTORY_H_
+#define _IOTREEFACTORY_H_
+
+#include "IoTree.h"
+
+namespace bpp
+{
+
+/**
+ * @brief Utilitary class for creating tree readers and writers.
+ *
+ * @see IOSequenceFactory
+ * @see IODistanceMatrixFactory
+ */
+class IOTreeFactory
+{
+public:
+  static const std::string NEWICK_FORMAT;  
+  static const std::string NEXUS_FORMAT;  
+  static const std::string NHX_FORMAT;  
+
+public:
+
+  /**
+   * @brief Creates a new factory object.
+   *
+   * Example:
+   * @code
+   * ITree * treeReader = IOTreeFactory().createReader(IOTreeFactory::NEWICK);
+   * Tree * tree = treeReader->read("file.dnd");
+   * delete treeReader;
+   * @endcode
+   */
+  IOTreeFactory() {}
+  virtual ~IOTreeFactory() {}
+  
+  /**
+   * @brief Get a new dynamically created ITree object.
+   *
+   * @param format The input file format.
+   * @return A pointer toward a new ITree object.
+   * @throw Exception If the format name do not match any available format.
+   */
+  virtual ITree* createReader(const std::string& format) throw (Exception);
+  
+  /**
+   * @brief Get a new dynamically created OTree object.
+   *
+   * @param format The output file format.
+   * @return A pointer toward a new OTree object.
+   * @throw Exception If the format name do not match any available format.
+   */
+  virtual OTree* createWriter(const std::string& format) throw (Exception);
+};
+
+} //end of namespace bpp.
+
+#endif //_IOTREEFACTORY_H_
+
diff --git a/src/Bpp/Phyl/Io/Newick.cpp b/src/Bpp/Phyl/Io/Newick.cpp
new file mode 100755
index 0000000..37f0aa3
--- /dev/null
+++ b/src/Bpp/Phyl/Io/Newick.cpp
@@ -0,0 +1,198 @@
+//
+// File: Newick.cpp
+// Created by: Julien Dutheil
+// Created on: Thu Oct 23 15:35:03 2003
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "Newick.h"
+#include "../Tree.h"
+#include "../TreeTemplate.h"
+#include "../TreeTemplateTools.h"
+
+#include <Bpp/Text/TextTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+
+/******************************************************************************/
+
+const string Newick::getFormatName() const { return "Newick"; }
+
+/******************************************************************************/
+
+const string Newick::getFormatDescription() const
+{
+  return string("New hampshire parenthesis format. ") +
+    "See http://evolution.genetics.washington.edu/phylip/newicktree.html for more info.";
+}
+
+/******************************************************************************/
+
+#if defined(NO_VIRTUAL_COV)
+    Tree*
+#else
+    TreeTemplate<Node> * 
+#endif
+Newick::read(istream& in) const throw (Exception)
+{
+  // Checking the existence of specified file
+  if (! in) { throw IOException ("Newick::read: failed to read from stream"); }
+  
+  //We concatenate all line in file till we reach the ending semi colon:
+  string temp, description;// Initialization
+  // Main loop : for all file lines
+  while (getline(in, temp, '\n'))
+  {
+    string::size_type index = temp.find(";");
+    if(index != string::npos)
+    {
+      description += temp.substr(0, index + 1);
+      break;
+    }
+    else description += temp;
+  }
+
+  if (allowComments_) description = TextTools::removeSubstrings(description, '[', ']');
+  if (TextTools::isEmpty(description))
+    throw IOException("Newick::read: no tree was found!");
+  return TreeTemplateTools::parenthesisToTree(description, useBootstrap_, bootstrapPropertyName_);
+}
+
+/******************************************************************************/
+
+void Newick::write_(const Tree& tree, ostream& out) const throw (Exception)
+{
+  // Checking the existence of specified file, and possibility to open it in write mode
+  if (! out) { throw IOException ("Newick::writeTree: failed to write to stream"); }
+  if(useBootstrap_)
+  {
+    out << TreeTools::treeToParenthesis(tree, writeId_);
+  }
+  else
+  {
+    out << TreeTools::treeToParenthesis(tree, false, bootstrapPropertyName_);
+  }
+}
+
+/******************************************************************************/
+
+template<class N>
+void Newick::write_(const TreeTemplate<N>& tree, ostream& out) const throw (Exception)
+{
+  // Checking the existence of specified file, and possibility to open it in write mode
+  if (! out) { throw IOException ("Newick::writeTree: failed to write to stream"); }
+  if(useBootstrap_)
+  {
+    out << TreeTemplateTools::treeToParenthesis(tree, writeId_);
+  }
+  else
+  {
+    out << TreeTemplateTools::treeToParenthesis(tree, false, bootstrapPropertyName_);
+  }
+}
+
+/******************************************************************************/
+
+void Newick::read(istream& in, vector<Tree*>& trees) const throw (Exception)
+{
+  // Checking the existence of specified file
+  if (! in) { throw IOException ("Newick::read: failed to read from stream"); }
+  
+  // Main loop : for all file lines
+  string temp, description;// Initialization
+  string::size_type index;
+  //We concatenate all line in file till we reach the ending semi colon:
+  while (getline(in, temp, '\n'))
+  {
+    index = temp.find(";");
+    if (index != string::npos)
+    {
+      description += temp.substr(0, index + 1);
+      if (allowComments_) description = TextTools::removeSubstrings(description, '[', ']');
+      trees.push_back(TreeTemplateTools::parenthesisToTree(description, useBootstrap_, bootstrapPropertyName_));
+      description = temp.substr(index + 1);
+    }
+    else description += temp;
+  }
+  //In case the file is empty, the method will not add any neww tree to the vector.
+}
+
+/******************************************************************************/
+
+void Newick::write_(const vector<Tree*>& trees, ostream& out) const throw (Exception)
+{
+  // Checking the existence of specified file, and possibility to open it in write mode
+  if (! out) { throw IOException ("Newick::write: failed to write to stream"); }
+  for(unsigned int i = 0; i < trees.size(); i++)
+  {
+    if(useBootstrap_)
+    {
+      out << TreeTools::treeToParenthesis(*trees[i], writeId_);
+    }
+    else
+    {
+      out << TreeTools::treeToParenthesis(*trees[i], false, bootstrapPropertyName_);
+    }
+  }
+}
+
+/******************************************************************************/
+
+template<class N>
+void Newick::write_(const vector<TreeTemplate<N>*>& trees, ostream& out) const throw (Exception)
+{
+  // Checking the existence of specified file, and possibility to open it in write mode
+  if (! out) { throw IOException ("Newick::write: failed to write to stream"); }
+  for(unsigned int i = 0; i < trees.size(); i++)
+  {
+    if(useBootstrap_)
+    {
+      out << TreeTemplateTools::treeToParenthesis(*trees[i], writeId_);
+    }
+    else
+    {
+      out << TreeTemplateTools::treeToParenthesis(*trees[i], false, bootstrapPropertyName_);
+    }
+  }
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Io/Newick.h b/src/Bpp/Phyl/Io/Newick.h
new file mode 100755
index 0000000..bac7a56
--- /dev/null
+++ b/src/Bpp/Phyl/Io/Newick.h
@@ -0,0 +1,207 @@
+//
+// File: Newick.h
+// Created by: Julien Dutheil
+// Created on: Thu Oct 23 15:35:03 2003
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _NEWICK_H_
+#define _NEWICK_H_
+
+#include "IoTree.h"
+#include "../TreeTemplate.h"
+
+namespace bpp
+{
+
+/**
+ * @brief The so-called 'newick' parenthetic format.
+ *
+ * Branch lengths and bootstraps are supported:
+ *
+ * ex:
+ * <code>
+ * ((A:0.1, B:0.15)90:0.2, C:0.27);
+ * </code>
+ *
+ * Code example:
+ * @code
+ * #include <Phyl/Newick.h>
+ * #include <Phyl/Tree.h>
+ * 
+ * Newick * newickReader = new Newick(false); //No comment allowed!
+ * try {
+ * 	Tree * tree = newickReader->read("MyTestTree.dnd"); // Tree in file MyTestTree.dnd
+ * 	cout << "Tree has " << tree->getNumberOfLeaves() << " leaves." << endl;
+ * } catch (Exception e) {
+ *	cout << "Error when reading tree." << endl;
+ * }
+ * delete tree;
+ * delete newickReader;
+ * @endcode
+ *
+ * Bootstrap values are stored as node properties, as Number<double> objects and with the tag TreeTools::BOOTSTRAP.
+ *
+ * This is also possible to read a "tagged" tree, where additional info is provided in place of bootstrap values:
+ * ((A,B)N2,(C,D)N3)N1;
+ * This is achieved by calling the enableExtendedBootstrapProperty method, and providing a property name to use.
+ * The additional information will be stored at each node as a property, in a String object.
+ * The disableExtendedBootstrapProperty method restores the default behavior.
+ */
+class Newick:
+  public AbstractITree,
+  public AbstractOTree,
+  public AbstractIMultiTree,
+  public AbstractOMultiTree
+{
+	protected:
+		bool allowComments_;
+    bool writeId_;
+    bool useBootstrap_;
+    std::string bootstrapPropertyName_;
+	
+	public:
+		
+		/**
+		 * @brief Build a new Newick reader/writer.
+		 *
+		 * Some newick format allow comments between hooks ('[' ']').
+		 * 
+		 * @param allowComments Tell if comments between [] are allowed in file.
+		 * @param writeId       If true, nodes ids will be written in place of bootstrap values.
+		 */
+		Newick(bool allowComments = false, bool writeId = false):
+      allowComments_(allowComments),
+      writeId_(writeId),
+      useBootstrap_(true),
+      bootstrapPropertyName_(TreeTools::BOOTSTRAP) {}
+
+		virtual ~Newick() {}
+	
+	public:
+
+    void enableExtendedBootstrapProperty(const std::string& propertyName)
+    {
+      useBootstrap_ = false;
+      bootstrapPropertyName_ = propertyName;
+    }
+    void disableExtendedBootstrapProperty()
+    {
+      useBootstrap_ = true;
+      bootstrapPropertyName_ = TreeTools::BOOTSTRAP;
+    }
+
+		/**
+		 * @name The IOTree interface
+		 *
+		 * @{
+		 */
+		const std::string getFormatName() const;
+		const std::string getFormatDescription() const;
+		/* @} */
+
+		/**
+		 * @name The ITree interface
+		 *
+		 * @{
+		 */		
+		TreeTemplate<Node>* read(const std::string& path) const throw (Exception)
+		{
+			return dynamic_cast<TreeTemplate<Node>*>(AbstractITree::read(path));
+		}
+		
+		TreeTemplate<Node>* read(std::istream& in) const throw (Exception);
+		/** @} */
+
+		/**
+		 * @name The OTree interface
+		 *
+		 * @{
+		 */
+		void write(const Tree& tree, const std::string& path, bool overwrite = true) const throw (Exception)
+		{
+			AbstractOTree::write(tree, path, overwrite);
+		}
+		
+    void write(const Tree& tree, std::ostream& out) const throw (Exception)
+    {
+      write_(tree, out);
+    }
+		/** @} */
+
+		/**
+		 * @name The IMultiTree interface
+		 *
+		 * @{
+		 */
+		void read(const std::string& path, std::vector<Tree*>& trees) const throw (Exception)
+		{
+			AbstractIMultiTree::read(path, trees);
+		}
+		void read(std::istream& in, std::vector<Tree*>& trees) const throw (Exception);
+    /**@}*/
+
+		/**
+		 * @name The OMultiTree interface
+		 *
+		 * @{
+		 */
+		void write(const std::vector<Tree*>& trees, const std::string& path, bool overwrite = true) const throw (Exception)
+		{
+			AbstractOMultiTree::write(trees, path, overwrite);
+		}
+		void write(const std::vector<Tree*>& trees, std::ostream& out) const throw (Exception)
+    {
+      write_(trees, out);
+    }
+		/** @} */
+
+  protected:
+    void write_(const Tree& tree, std::ostream& out) const throw (Exception);
+    
+    template<class N>
+    void write_(const TreeTemplate<N>& tree, std::ostream& out) const throw (Exception);
+		
+    void write_(const std::vector<Tree*>& trees, std::ostream& out) const throw (Exception);
+    
+    template<class N>
+    void write_(const std::vector<TreeTemplate<N>*>& trees, std::ostream& out) const throw (Exception);
+
+};
+
+} //end of namespace bpp.
+
+#endif	//_NEWICK_H_
+
diff --git a/src/Bpp/Phyl/Io/NexusIoTree.cpp b/src/Bpp/Phyl/Io/NexusIoTree.cpp
new file mode 100755
index 0000000..740ece3
--- /dev/null
+++ b/src/Bpp/Phyl/Io/NexusIoTree.cpp
@@ -0,0 +1,320 @@
+//
+// File: NexusIOTree.cpp
+// Created by: Julien Dutheil
+// Created on: Wed May 27 19:06 2009
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "NexusIoTree.h"
+#include "../Tree.h"
+#include "../TreeTemplate.h"
+#include "../TreeTemplateTools.h"
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Io/FileTools.h>
+#include <Bpp/Text/StringTokenizer.h>
+#include <Bpp/Text/NestedStringTokenizer.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+//From SeqLib:
+#include <Bpp/Seq/Io/NexusTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+
+/******************************************************************************/
+
+const string NexusIOTree::getFormatName() const { return "Nexus"; }
+
+/******************************************************************************/
+
+const string NexusIOTree::getFormatDescription() const
+{
+	return string("Nexus format (trees only). ");
+}
+
+/******************************************************************************/
+
+#if defined(NO_VIRTUAL_COV)
+		Tree *
+#else
+		TreeTemplate<Node> * 
+#endif
+NexusIOTree::read(istream &in) const throw (Exception)
+{
+  vector<Tree*> trees;
+  read(in, trees);
+  if (trees.size() == 0)
+    throw IOException("NexusIOTree::read(). No tree found in file.");
+  for (size_t i = trees.size() - 1; i > 0; i--)
+    delete trees[i];
+  return dynamic_cast<TreeTemplate<Node>*>(trees[0]);
+}
+
+/******************************************************************************/
+
+void NexusIOTree::read(std::istream& in, std::vector<Tree*>& trees) const throw (Exception)
+{
+	// Checking the existence of specified file
+	if (! in) { throw IOException ("NexusIOTree::read(). Failed to read from stream"); }
+	
+  //Look for the TREES block:
+  string line = "";
+  while (TextTools::toUpper(line) != "BEGIN TREES;")
+  {
+    if (in.eof())
+      throw Exception("NexusIOTree::read(). No trees block was found.");
+    line = TextTools::removeSurroundingWhiteSpaces(FileTools::getNextLine(in));
+  }
+  
+  string cmdName = "", cmdArgs = "";
+  bool cmdFound = NexusTools::getNextCommand(in, cmdName, cmdArgs, false);
+  if (! cmdFound)
+    throw Exception("NexusIOTree::read(). Missing tree command.");
+  cmdName = TextTools::toUpper(cmdName);
+
+  //Look for the TRANSLATE command:
+  map<string, string> translation;
+  bool hasTranslation = false;
+  if (cmdName == "TRANSLATE")
+  {
+    //Parse translation:
+    StringTokenizer st(cmdArgs, ",");
+    while (st.hasMoreToken())
+    {
+      string tok = TextTools::removeSurroundingWhiteSpaces(st.nextToken());
+      NestedStringTokenizer nst(tok, "'", "'", " \t");
+      if (nst.numberOfRemainingTokens() != 2)
+        throw Exception("NexusIOTree::read(). Unvalid translation description.");
+      string name = nst.nextToken();
+      string tln  = nst.nextToken();
+      translation[name] = tln;
+    }
+    hasTranslation = true;
+    cmdFound = NexusTools::getNextCommand(in, cmdName, cmdArgs, false);
+    if (! cmdFound)
+      throw Exception("NexusIOTree::read(). Missing tree command.");
+    else
+      cmdName = TextTools::toUpper(cmdName);
+  }
+
+  //Now parse the trees:
+  while (cmdFound && cmdName != "END")
+  {
+    if (cmdName != "TREE")
+      throw Exception("NexusIOTree::read(). Unvalid command found: " + cmdName);
+    string::size_type pos = cmdArgs.find("=");
+    if (pos == string::npos)
+      throw Exception("NexusIOTree::read(). unvalid format, should be tree-name=tree-description");
+    string description = cmdArgs.substr(pos + 1);
+	  TreeTemplate<Node>* tree = TreeTemplateTools::parenthesisToTree(description + ";", true);
+
+    //Now translate leaf names if there is a translation:
+    //(we assume that all trees share the same translation! ===> check!)
+    if (hasTranslation)
+    {
+      vector<Node*> leaves = tree->getLeaves();
+      for (size_t i = 0; i < leaves.size(); i++)
+      {
+        string name = leaves[i]->getName();
+        if (translation.find(name) == translation.end())
+        {
+          throw Exception("NexusIOTree::read(). No translation was given for this leaf: " + name);
+        }
+        leaves[i]->setName(translation[name]);
+      }
+    }
+    trees.push_back(tree);
+    cmdFound = NexusTools::getNextCommand(in, cmdName, cmdArgs, false);
+    if (cmdFound) cmdName = TextTools::toUpper(cmdName);
+  }
+}
+
+/******************************************************************************/
+
+void NexusIOTree::write_(const Tree& tree, ostream& out) const throw (Exception)
+{
+  vector<Tree*> trees;
+  trees.push_back(&const_cast<Tree&>(tree));
+  write(trees, out);
+}
+
+/******************************************************************************/
+
+template<class N>
+void NexusIOTree::write_(const TreeTemplate<N>& tree, ostream& out) const throw (Exception)
+{
+  vector<Tree*> trees;
+  trees.push_back(&const_cast<Tree&>(tree));
+  write(trees, out);
+}
+
+/******************************************************************************/
+
+void NexusIOTree::write_(const vector<Tree*>& trees, ostream& out) const throw (Exception)
+{
+	// Checking the existence of specified file, and possibility to open it in write mode
+	if (! out) { throw IOException ("NexusIOTree::write: failed to write to stream"); }
+  
+  out << "#NEXUS" << endl;
+  out << endl;
+  out << "BEGIN TREES;" << endl;
+
+  //First, we retrieve all leaf names from all trees:
+  vector<string> names;
+  for (size_t i = 0; i < trees.size(); i++)
+  {
+    names = VectorTools::vectorUnion(names, trees[i]->getLeavesNames());
+  }
+  //... and create a translation map:
+  map<string, size_t> translation;
+  size_t code = 0;
+  for (size_t i = 0; i < names.size(); i++)
+  {
+    translation[names[i]] = code++;
+  }
+
+  //Second we translate all leaf names to their corresponding code:
+  vector<Tree*> translatedTrees(trees.size());
+  for (size_t i = 0; i < trees.size(); i++)
+  {
+    vector<int> leavesId = trees[i]->getLeavesId();
+    Tree* tree = dynamic_cast<Tree*>(trees[i]->clone());
+    for (size_t j = 0; j < leavesId.size(); j++)
+    {
+      tree->setNodeName(leavesId[j], TextTools::toString(translation[tree->getNodeName(leavesId[j])]));
+    }
+    translatedTrees[i] = tree;
+  }
+  
+  //Third we print the translation command:
+  out << "  TRANSLATE";
+  size_t count = 0;
+  for (map<string, size_t>::iterator it = translation.begin(); it != translation.end(); it++)
+  {
+    out << endl << "    " << it->second << "\t" << it->first;
+    count++;
+    if (count < translation.size())
+      out << ",";
+  }
+  out << ";";
+  
+  //Finally we print all tree descriptions:
+  for (size_t i = 0; i < trees.size(); i++)
+  {
+    out << endl << "  TREE tree" << (i+1) << " = " << TreeTools::treeToParenthesis(*translatedTrees[i]);
+  }
+  out << "END;" << endl;
+  
+  //Clean trees:
+  for (size_t i = 0; i < translatedTrees.size(); i++)
+  {
+    delete translatedTrees[i];
+  }
+}
+
+/******************************************************************************/
+
+template<class N>
+void NexusIOTree::write_(const vector<TreeTemplate<N>*>& trees, ostream& out) const throw (Exception)
+{
+	// Checking the existence of specified file, and possibility to open it in write mode
+	if (! out) { throw IOException ("NexusIOTree::write: failed to write to stream"); }
+  
+  out << "#NEXUS" << endl;
+  out << endl;
+  out << "BEGIN TREES;" << endl;
+
+  //First, we retrieve all leaf names from all trees:
+  vector<string> names;
+  for (size_t i = 0; i < trees.size(); i++)
+  {
+    names = VectorTools::vectorUnion(names, trees[i]->getLeavesNames());
+  }
+  //... and create a translation map:
+  map<string, size_t> translation;
+  size_t code = 0;
+  for (size_t i = 0; i < names.size(); i++)
+  {
+    translation[names[i]] = code++;
+  }
+
+  //Second we translate all leaf names to their corresponding code:
+  vector<Tree*> translatedTrees(trees.size());
+  for (size_t i = 0; i < trees.size(); i++)
+  {
+    vector<int> leavesId = trees[i]->getLeavesId();
+    Tree* tree = dynamic_cast<Tree*>(trees[i]->clone());
+    for (size_t j = 0; j < leavesId.size(); j++)
+    {
+      tree->setNodeName(leavesId[j], TextTools::toString(translation[tree->getNodeName(leavesId[j])]));
+    }
+    translatedTrees[i] = tree;
+  }
+  
+  //Third we print the translation command:
+  out << "  TRANSLATE";
+  size_t count = 0;
+  for (map<string, size_t>::iterator it = translation.begin(); it != translation.end(); it++)
+  {
+    out << endl << "    " << it->second << "\t" << it->first;
+    count++;
+    if (count < translation.size())
+      out << ",";
+  }
+  out << ";";
+  
+  //Finally we print all tree descriptions:
+  for (size_t i = 0; i < trees.size(); i++)
+  {
+    out << endl << "  TREE tree" << (i+1) << " = " << TreeTemplateTools::treeToParenthesis(*translatedTrees[i]);
+  }
+  out << "END;" << endl;
+  
+  //Clean trees:
+  for (size_t i = 0; i < translatedTrees.size(); i++)
+  {
+    delete translatedTrees[i];
+  }
+}
+
+/******************************************************************************/
+
+
diff --git a/src/Bpp/Phyl/Io/NexusIoTree.h b/src/Bpp/Phyl/Io/NexusIoTree.h
new file mode 100755
index 0000000..6712650
--- /dev/null
+++ b/src/Bpp/Phyl/Io/NexusIoTree.h
@@ -0,0 +1,170 @@
+//
+// File: NexusIOTree.h
+// Created by: Julien Dutheil
+// Created on: Wed May 27 19:06 2009
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _NEXUSIOTREE_H_
+#define _NEXUSIOTREE_H_
+
+#include "IoTree.h"
+#include "../TreeTemplate.h"
+
+namespace bpp
+{
+
+/**
+ * @brief a simple parser for reading trees from a Nexus file.
+ *
+ * This reader is not supposed to be a full parser of the Nexus files,
+ * but only extract the tree data. Only a basic subset of the options
+ * are and will be supported.
+ *
+ * This format is described in the following paper:
+ * Maddison D, Swofford D, and Maddison W (1997), _Syst Biol_ 46(4):590-621
+ *
+ * @author Julien Dutheil
+ */
+class NexusIOTree:
+  public virtual AbstractITree,
+  public virtual AbstractOTree,
+  public virtual AbstractIMultiTree,
+  public virtual AbstractOMultiTree
+{
+	public:
+		
+		/**
+		 * @brief Build a new Nexus tree parser.
+		 */
+		NexusIOTree() {}
+
+		virtual ~NexusIOTree() {}
+	
+	public:
+
+		/**
+		 * @name The IOTree interface
+		 *
+		 * @{
+		 */
+		const std::string getFormatName() const;
+		const std::string getFormatDescription() const;
+		/* @} */
+
+		/**
+		 * @name The ITree interface
+		 *
+		 * @{
+		 */
+#if defined(NO_VIRTUAL_COV)
+		Tree* read(const std::string& path) const throw (Exception)
+		{
+			return AbstractITree::read(path);
+		}
+#else
+		TreeTemplate<Node>* read(const std::string& path) const throw (Exception)
+		{
+			return dynamic_cast<TreeTemplate<Node>*>(AbstractITree::read(path));
+		}
+#endif
+		
+#if defined(NO_VIRTUAL_COV)
+		Tree*
+#else
+		TreeTemplate<Node>* 
+#endif
+		read(std::istream& in) const throw (Exception);
+		/** @} */
+
+    /**
+		 * @name The OTree interface
+		 *
+		 * @{
+		 */
+		void write(const Tree& tree, const std::string& path, bool overwrite = true) const throw (Exception)
+		{
+			AbstractOTree::write(tree, path, overwrite);
+		}
+		void write(const Tree& tree, std::ostream& out) const throw (Exception)
+    {
+      write_(tree, out);
+    }
+		/** @} */
+
+		/**
+		 * @name The IMultiTree interface
+		 *
+		 * @{
+		 */
+		void read(const std::string& path, std::vector<Tree*>& trees) const throw (Exception)
+		{
+			AbstractIMultiTree::read(path, trees);
+		}
+		void read(std::istream& in, std::vector<Tree*>& trees) const throw (Exception);
+    /**@}*/
+
+		/**
+		 * @name The OMultiTree interface
+		 *
+		 * @{
+		 */
+		void write(const std::vector<Tree*>& trees, const std::string& path, bool overwrite = true) const throw (Exception)
+		{
+			AbstractOMultiTree::write(trees, path, overwrite);
+		}
+		void write(const std::vector<Tree*>& trees, std::ostream& out) const throw (Exception)
+    {
+      write_(trees, out);
+    }
+		/** @} */
+
+  protected:
+    void write_(const Tree& tree, std::ostream& out) const throw (Exception);
+    
+    template<class N>
+    void write_(const TreeTemplate<N>& tree, std::ostream& out) const throw (Exception);
+
+    void write_(const std::vector<Tree*>& trees, std::ostream& out) const throw (Exception);
+    
+    template<class N>
+    void write_(const std::vector<TreeTemplate<N>*>& trees, std::ostream& out) const throw (Exception);
+
+};
+
+} //end of namespace bpp.
+
+#endif	//_NEXUSIOTREE_H_
+
diff --git a/src/Bpp/Phyl/Io/Nhx.cpp b/src/Bpp/Phyl/Io/Nhx.cpp
new file mode 100755
index 0000000..30f265d
--- /dev/null
+++ b/src/Bpp/Phyl/Io/Nhx.cpp
@@ -0,0 +1,572 @@
+//
+// File: Nhx.cpp
+// Created by: Bastien Boussau
+// Created on: Thu Oct 19 11:06:03 2010
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "Nhx.h"
+#include "../Tree.h"
+#include "../TreeTemplate.h"
+
+//From bpp-core:
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/BppString.h>
+#include <Bpp/BppBoolean.h>
+#include <Bpp/Numeric/Number.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+
+/******************************************************************************/
+
+Nhx::Nhx(bool useTagsAsPptNames):
+  supportedProperties_(),
+  useTagsAsPropertyNames_(useTagsAsPptNames),
+  hasIds_(false)
+{
+  registerProperty(Property("Gene name", "GN", false, 0));
+  registerProperty(Property("Sequence accession", "AC", false, 0));
+  registerProperty(Property("Node ID", "ND", false, 0));
+  registerProperty(Property(TreeTools::BOOTSTRAP, "B", true, 2));
+  registerProperty(Property("Event", "Ev", true, 0));
+  registerProperty(Property("EC number", "E", false, 0));
+  registerProperty(Property("Function", "Fu", false, 0));
+  registerProperty(Property("Domain structure", "DS", false, 0));
+  registerProperty(Property("Species name", "S", false, 0));
+  registerProperty(Property("Taxonomy ID", "T", false, 1));
+  registerProperty(Property("Width of parent branch", "W", true, 1));
+  registerProperty(Property("Color of parent branch", "C", true, 0));
+  registerProperty(Property("Collapse", "C", false, 3));
+  registerProperty(Property("Custom", "XB", true, 0));
+  registerProperty(Property("Custom", "XN", false, 0));
+  registerProperty(Property("Orthologous", "O", false, 1));
+  registerProperty(Property("Subtree neighbors", "SN", false, 1));
+  registerProperty(Property("Super orthologous", "SO", false, 1));
+}
+
+/******************************************************************************/
+
+const string Nhx::getFormatName() const { return "Nhx"; }
+
+/******************************************************************************/
+
+const string Nhx::getFormatDescription() const
+{
+  return string("New Hampshire eXtended parenthesis format. ") +
+    "See http://www.phylosoft.org/NHX/ for more info.";
+}
+
+/******************************************************************************/
+
+#if defined(NO_VIRTUAL_COV)
+    Tree*
+#else
+    TreeTemplate<Node>* 
+#endif
+Nhx::read(istream& in) const throw (Exception)
+{
+  // Checking the existence of specified file
+  if (! in) { throw IOException ("Nhx ::read: failed to read from stream"); }
+  
+  //We concatenate all line in file till we reach the ending semi colon:
+  string temp, description;// Initialization
+  // Main loop : for all file lines
+  while (! in.eof())
+  {
+    getline(in, temp, '\n');  // Copy current line in temporary string
+    string::size_type index = temp.find(";");
+    if (index != string::npos)
+    {
+      description += temp.substr(0, index + 1);
+      break;
+    }
+    else description += temp;
+  }
+  vector<string> beginnings, endings;
+  beginnings.push_back("[&&NHX:");
+  description = TextTools::removeSubstrings(description, '[', ']', beginnings, endings);
+  return parenthesisToTree(description);
+}
+
+/******************************************************************************/
+
+void Nhx::write_(const Tree& tree, ostream& out) const throw (Exception)
+{
+  // Checking the existence of specified file, and possibility to open it in write mode
+  if (! out) { throw IOException ("Nhx::writeTree: failed to write to stream"); }
+    out << treeToParenthesis(tree);
+}
+
+/******************************************************************************/
+
+template<class N>
+void Nhx::write_(const TreeTemplate<N>& tree, ostream& out) const throw (Exception)
+{
+  // Checking the existence of specified file, and possibility to open it in write mode
+  if (! out) { throw IOException ("Nhx::writeTree: failed to write to stream"); }
+    out << treeToParenthesis(tree);
+}
+
+/******************************************************************************/
+
+void Nhx::read(istream& in, vector<Tree*>& trees) const throw (Exception)
+{
+  // Checking the existence of specified file
+  if (! in) { throw IOException ("Nhx::read: failed to read from stream"); }
+  
+  // Main loop : for all file lines
+  string temp, description;// Initialization
+  string::size_type index;
+  vector <string > beginnings, endings;
+  beginnings.push_back("[&&NHX:");
+  while (!in.eof())
+  {
+    //We concatenate all line in file till we reach the ending semi colon:
+    while (!in.eof())
+    {
+      getline(in, temp, '\n');  // Copy current line in temporary string
+      index = temp.find(";");
+      if (index != string::npos)
+      {
+        description += temp.substr(0, index + 1);
+        description = TextTools::removeSubstrings(description, '[', ']', beginnings, endings);
+        trees.push_back(parenthesisToTree(description));
+        description = temp.substr(index + 1);
+      }
+      else description += temp;
+    }
+  }
+}
+
+/******************************************************************************/
+
+void Nhx::write_(const vector<Tree*>& trees, ostream& out) const throw (Exception)
+{
+  // Checking the existence of specified file, and possibility to open it in write mode
+  if (! out) { throw IOException ("Nhx::write: failed to write to stream"); }
+  for(unsigned int i = 0; i < trees.size(); i++)
+  {
+      out << treeToParenthesis(*trees[i]);
+  }
+}
+
+/******************************************************************************/
+
+template<class N>
+void Nhx::write_(const vector<TreeTemplate<N>*>& trees, ostream& out) const throw (Exception)
+{
+  // Checking the existence of specified file, and possibility to open it in write mode
+  if (! out) { throw IOException ("Nhx::write: failed to write to stream"); }
+  for(unsigned int i = 0; i < trees.size(); i++)
+  {
+      out << treeToParenthesis(*trees[i]);
+  }
+}
+
+/******************************************************************************/
+
+Nhx::Element Nhx::getElement(const string& elt) const throw (IOException)
+{
+  Element element;
+  element.length     = ""; //default
+  element.annotation = ""; //default
+  element.isLeaf     = false; // default
+ 
+  //cout << "ELT=" << elt << endl;
+  size_t lastP = elt.rfind(")"), firstP;
+  size_t beginAnno = string::npos;
+  if (lastP == string::npos)
+    beginAnno = elt.rfind("[&&NHX:");
+  else
+    beginAnno = elt.find("[&&NHX:", lastP + 1);
+  string elementWithoutAnnotation;
+  if (beginAnno != string::npos) {
+    size_t endAnno = elt.find("]", beginAnno + 7);
+    element.annotation = elt.substr(beginAnno + 7, endAnno - beginAnno - 7);
+    elementWithoutAnnotation = elt.substr(0, beginAnno);
+  } else {
+    element.annotation = "";
+    elementWithoutAnnotation = elt;
+  } 
+  //cout << "ANNO=" << element.annotation << endl;
+  //cout << "ELT =" << elementWithoutAnnotation << endl;
+
+  size_t colonIndex;
+  bool hasColon = false;
+  for (colonIndex = elementWithoutAnnotation.size() - 1; colonIndex > 0 && elementWithoutAnnotation[colonIndex] != ')' && !hasColon; --colonIndex)
+  {
+    if (elementWithoutAnnotation[colonIndex] == ':')
+    {
+      hasColon = true;
+    }
+  }
+  try
+  {
+    string elt2;
+    if (hasColon)
+    {
+      //this is an element with length:
+      elt2 = elementWithoutAnnotation.substr(0, colonIndex + 1);
+      element.length = elementWithoutAnnotation.substr(colonIndex + 2);
+    }
+    else
+    {
+      //this is an element without length;
+      elt2 = elementWithoutAnnotation;
+    }
+  
+    lastP = elt2.rfind(')');
+    firstP = elt2.find('(');
+    if (firstP == string::npos)
+    {
+      //This is a leaf:
+      element.content = elt2;
+      element.isLeaf  = true;
+    }
+    else
+    {
+      //This is a node:
+      if (lastP < firstP) throw IOException("Nhx::getElement(). Invalid format: bad closing parenthesis in " + elt2);
+      element.content = elt2.substr(firstP + 1, lastP - firstP - 1);
+    }
+  }
+  catch (exception& e)
+  {
+    throw IOException("Bad tree description: " + elt);
+  }
+  //cout << endl;
+  //cout << "CONTENT:" << endl << element.content << endl;
+  //cout << endl;
+  //cout << "ANNOTATION:" << endl << element.annotation << endl;
+  //cout << endl;
+ 
+  return element;
+}  
+
+/******************************************************************************/
+
+
+Node* Nhx::parenthesisToNode(const string& description) const
+{
+  //cout << "NODE: " << description << endl;
+  Element elt = getElement(description);
+  
+  //New node:
+  Node* node = new Node();
+  if (!TextTools::isEmpty(elt.length))
+  {
+    node->setDistanceToFather(TextTools::toDouble(elt.length));
+  }
+  if (!TextTools::isEmpty(elt.annotation))
+  {
+    bool hasId = setNodeProperties(*node, elt.annotation);
+    if (!hasIds_ && hasId)
+      hasIds_ = true;
+    if (hasIds_ && !hasId)
+      throw Exception("Nhx::parenthesisToNode. At least one one is missing an id (ND tag).");
+  }
+ 
+  NestedStringTokenizer nt(elt.content, "(", ")", ",");
+  vector<string> elements;
+  while (nt.hasMoreToken())
+  {
+    elements.push_back(nt.nextToken());
+  }
+  if (elt.isLeaf)
+  {
+    //This is a leaf:
+    string name = TextTools::removeSurroundingWhiteSpaces(elements[0]);
+    node->setName(name);
+  }
+  else
+  {
+    //This is a node:
+    for (size_t i = 0; i < elements.size(); ++i)
+    {
+      //cout << "NODE: SUBNODE: " << i << ", " << elements[i] << endl;
+      Node* son = parenthesisToNode(elements[i]);
+      node->addSon(son);
+    }
+  }
+  return node;
+}
+
+/******************************************************************************/
+
+TreeTemplate<Node>* Nhx::parenthesisToTree(const string& description) const throw (Exception) 
+{
+  hasIds_ = false;
+  string::size_type semi = description.rfind(';');
+  if (semi == string::npos)
+    throw Exception("Nhx::parenthesisToTree(). Bad format: no semi-colon found.");
+  string content = description.substr(0, semi);
+  Node* node = parenthesisToNode(content);
+  TreeTemplate<Node>* tree = new TreeTemplate<Node>();
+  tree->setRootNode(node);
+  if (!hasIds_)
+  {
+    tree->resetNodesId();
+  }
+  return tree;
+}
+
+/******************************************************************************/
+
+string Nhx::propertyToString_(const Clonable* pptObject, short type) throw (Exception)
+{
+  if (type == 0) {
+    const BppString* castedPptObject = dynamic_cast<const BppString*>(pptObject);
+    if (castedPptObject)
+      return castedPptObject->toSTL();
+    else
+      throw Exception("Nhx::propertyToString_. Unvalid property type, should be of class BppString.");
+  } else if (type == 1) {
+    const Number<int>* castedPptObject = dynamic_cast<const Number<int>*>(pptObject);
+    if (castedPptObject)
+      return TextTools::toString(castedPptObject->getValue());
+    else
+      throw Exception("Nhx::propertyToString_. Unvalid property type, should be of class Number<int>.");
+  } else if (type == 2) {
+    const Number<double>* castedPptObject = dynamic_cast<const Number<double>*>(pptObject);
+    if (castedPptObject)
+      return TextTools::toString(castedPptObject->getValue());
+    else
+      throw Exception("Nhx::propertyToString_. Unvalid property type, should be of class Number<double>.");
+  } else if (type == 3) {
+    const BppBoolean* castedPptObject = dynamic_cast<const BppBoolean*>(pptObject);
+    if (castedPptObject)
+      return TextTools::toString(castedPptObject->getValue());
+    else
+      throw Exception("Nhx::propertyToString_. Unvalid property type, should be of class BppBoolean.");
+  } else {
+    throw Exception("Nhx::propertyToString_. Unsupported type: " + TextTools::toString(type));
+  }
+}
+
+/******************************************************************************/
+
+Clonable* Nhx::stringToProperty_(const string& pptDesc, short type) throw (Exception)
+{
+  if (type == 0) {
+    return new BppString(pptDesc);
+  } else if (type == 1) {
+    return new Number<int>(TextTools::toInt(pptDesc));
+  } else if (type == 2) {
+    return new Number<double>(TextTools::toDouble(pptDesc));
+  } else if (type == 3) {
+    return new BppBoolean(TextTools::to<bool>(pptDesc));
+  } else {
+    throw Exception("Nhx::stringToProperty_. Unsupported type: " + TextTools::toString(type));
+  }
+}
+
+
+/******************************************************************************/
+
+string Nhx::propertiesToParenthesis(const Node& node) const
+{
+  ostringstream s;
+  s << "[&&NHX";
+  for (set<Property>::iterator it = supportedProperties_.begin(); it != supportedProperties_.end(); ++it) {
+    string ppt = (useTagsAsPropertyNames_ ? it->tag : it->name);
+    if (it->onBranch) {
+      if (node.hasBranchProperty(ppt)) {
+        const Clonable* pptObject = node.getBranchProperty(ppt);
+        s << ":" << it->tag << "=" << propertyToString_(pptObject, it->type);
+      }
+    } else {
+      if (node.hasNodeProperty(ppt)) {
+        const Clonable* pptObject = node.getNodeProperty(ppt);
+        s << ":" << it->tag << "=" << propertyToString_(pptObject, it->type);
+      }
+    }
+  }
+  //If no special node id is provided, we output the one from the tree:
+  if (!node.hasNodeProperty(useTagsAsPropertyNames_ ? "ND" : "Node ID"))
+  {
+    s << ":ND="<<TextTools::toString(node.getId());
+  }
+  s << "]";
+  return s.str();  
+}
+
+/******************************************************************************/
+
+string Nhx::nodeToParenthesis(const Node& node) const
+{
+  ostringstream s;
+  if (node.isLeaf())
+  {
+    s << node.getName();
+  }
+  else
+  {
+    s << "(";
+    s << nodeToParenthesis(* node[0]);
+    for (int i = 1; i < static_cast<int>(node.getNumberOfSons()); i++)
+    {
+      s << "," << nodeToParenthesis(*node[i]);
+    }
+    s << ")";
+  }
+  if (node.hasDistanceToFather()) s << ":" << node.getDistanceToFather();
+  s << propertiesToParenthesis(node);
+  return s.str();  
+}
+
+/******************************************************************************/
+
+string Nhx::treeToParenthesis(const TreeTemplate<Node>& tree) const
+{
+  ostringstream s;
+  s << "(";
+
+  const Node* node = tree.getRootNode();
+
+  if (node->isLeaf())
+  {
+    s << node->getName();
+    for (size_t i = 0; i < node->getNumberOfSons(); ++i)
+    {
+      s << "," << nodeToParenthesis(*node->getSon(i));
+    }
+  }
+  else
+  {
+    s << nodeToParenthesis(* node->getSon(0));
+    for (size_t i = 1; i < node->getNumberOfSons(); ++i)
+    {
+      s << "," << nodeToParenthesis(*node->getSon(i));
+    }
+  }
+
+  s << ")" ;
+  if (node->hasDistanceToFather()) s << ":" << node->getDistanceToFather();
+  s << propertiesToParenthesis(*node);
+  s << ";" << endl;
+  return s.str();  
+}
+
+/******************************************************************************/
+
+bool Nhx::setNodeProperties(Node& node, const string properties) const
+{
+  string propsDesc = TextTools::removeChar(properties, ']');
+  StringTokenizer st(propsDesc, ":", true, true);
+  map<string, string> props; 
+  while (st.hasMoreToken())
+  {
+    string token = st.nextToken();
+    if (TextTools::hasSubstring(token, "=")) {
+      StringTokenizer pt(token, "=", true, true);
+      string tag = pt.nextToken();
+      string value = pt.nextToken();
+      props[tag] = value;
+    }
+  }
+
+  for (set<Property>::iterator it = supportedProperties_.begin(); it != supportedProperties_.end(); ++it) {
+    if (props.find(it->tag) != props.end()) {
+      //Property found
+      string ppt = (useTagsAsPropertyNames_ ? it->tag : it->name);
+      if (it->onBranch) {
+        node.setBranchProperty(ppt, *auto_ptr<Clonable>(stringToProperty_(props[it->tag], it->type)));
+      } else {
+        node.setNodeProperty(ppt, *auto_ptr<Clonable>(stringToProperty_(props[it->tag], it->type)));
+      }
+    }
+  }
+     
+  //If the ND tag is present and is decimal, we use it has the node id:
+  bool hasId = false;
+  if (props.find("ND") != props.end()) {
+    string prop = props["ND"];
+    if (TextTools::isDecimalNumber(prop))
+    {
+      node.setId(TextTools::toInt(prop));
+      hasId = true;   
+    }
+  }
+  return hasId;
+}
+
+/******************************************************************************/
+
+void Nhx::changeTagsToNames(Node& node) const {
+  for (set<Property>::iterator it = supportedProperties_.begin(); it != supportedProperties_.end(); ++it) {
+    if (it->onBranch) {
+      if (node.hasBranchProperty(it->tag)) {
+        node.setBranchProperty(it->name, *node.getBranchProperty(it->tag));
+        node.deleteBranchProperty(it->tag);
+      }
+    } else {
+      if (node.hasNodeProperty(it->tag)) {
+        node.setNodeProperty(it->name, *node.getNodeProperty(it->tag));
+        node.deleteNodeProperty(it->tag);
+      }
+    }
+  }
+  for (unsigned int i = 0; i < node.getNumberOfSons(); ++i)
+    changeTagsToNames(*node.getSon(i));
+}
+
+/******************************************************************************/
+
+void Nhx::changeNamesToTags(Node& node) const {
+  for (set<Property>::iterator it = supportedProperties_.begin(); it != supportedProperties_.end(); ++it) {
+    if (it->onBranch) {
+      if (node.hasBranchProperty(it->name)) {
+        node.setBranchProperty(it->tag, *node.getBranchProperty(it->name));
+        node.deleteBranchProperty(it->name);
+      }
+    } else {
+      if (node.hasNodeProperty(it->name)) {
+        node.setNodeProperty(it->tag, *node.getNodeProperty(it->name));
+        node.deleteNodeProperty(it->name);
+      }
+    }
+  }
+  for (unsigned int i = 0; i < node.getNumberOfSons(); ++i)
+    changeNamesToTags(*node.getSon(i));
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Io/Nhx.h b/src/Bpp/Phyl/Io/Nhx.h
new file mode 100755
index 0000000..88d5b87
--- /dev/null
+++ b/src/Bpp/Phyl/Io/Nhx.h
@@ -0,0 +1,282 @@
+//
+// File: Nhx.h
+// Created by: Bastien Boussau
+// Created on: Tu Oct 19 10:24:03 2010
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _NHX_H_
+#define _NHX_H_
+
+#include "IoTree.h"
+#include "../TreeTemplate.h"
+
+//From the STL:
+#include <set>
+
+namespace bpp
+{
+
+/**
+ * @brief The so-called 'Nhx - New Hampshire eXtended' parenthetic format. 
+ *
+ * See http://www.phylosoft.org/Nhx/ for details.
+ *
+ * Branch lengths and node annotations are supported:
+ *
+ * ex:
+ * <code>
+ * ((A:0.1[&&NHX:S=human], B:0.15[&&NHX:S=chimp]):0.2[&&NHX:B=90:D=N:S=primates], C:0.27[&&NHX:S=mouse]);
+ * </code>
+ *
+ * Where e.g. "S=human" means that the sequence A comes from species "human", "B=90" stands for a support value, 
+ * and "D=N" means that there was no duplication at the node. Other tags are allowed, see http://www.phylosoft.org/NHX/.
+ * By default, comments between "[" and "]" are removed, unless the opening bracket is followed by "&&NHX".
+ *
+ * Code example:
+ * @code
+ * #include <Phyl/Nhx.h>
+ * #include <Phyl/Tree.h>
+ * 
+ * Nhx * NhxReader = new Nhx();
+ * try {
+ *   Tree * tree = nhxReader->read("MyTestTree.dnd"); // Tree in file MyTestTree.dnd
+ *   cout << "Tree has " << tree->getNumberOfLeaves() << " leaves." << endl;
+ * } catch (Exception e) {
+ *  cout << "Error when reading tree." << endl;
+ * }
+ * delete tree;
+ * delete nhxReader;
+ * @endcode
+ *
+ * All node annotations are stored as node properties, with type bppString for all properties except for support values, where a Number is used.
+ *
+ */
+class Nhx:
+  public AbstractITree,
+  public AbstractOTree,
+  public AbstractIMultiTree,
+  public AbstractOMultiTree
+{
+  private:
+    struct Element
+    {
+      public:
+        std::string content;
+        std::string length;
+        std::string annotation;
+        bool isLeaf;
+  
+      public:
+        Element() : content(), length(), annotation(), isLeaf(false) {}
+    };
+  
+  public:
+    struct Property
+    {
+      public:
+        /**
+         * @brief The name of the property, which will be used in parsed trees.
+         */
+        std::string name;
+        /**
+         * @brief The tag of the property, as it will be found in the tree file.
+         */
+        std::string tag;
+        /**
+         * @brief Tells if the property is a branch property instead of a node property.
+         */
+        bool onBranch;
+        /**
+         * @brief The type of the property. 0 is string, 1 is integer, 2 is double, 3 is boolean.
+         */
+        short type;
+
+      public:
+        Property(const std::string& pptName, const std::string& pptTag, bool pptOnBranch = false, short pptType = 0):
+          name(pptName), tag(pptTag), onBranch(pptOnBranch), type(pptType) {}
+
+        bool operator<(const Property& ppt) const {
+          return (name < ppt.name);
+        }
+
+    };
+
+  private:
+    std::set<Property> supportedProperties_;
+    bool useTagsAsPropertyNames_;
+    mutable bool hasIds_;
+
+  public:
+    
+    /**
+     * @brief Build a new Nhx reader/writer.
+     *
+     * Comments between hooks ('[' ']') are ignored.
+     *
+     * @param useTagsAsPptNames Tells if the NHX tag should be used as a property name in the parsed tree.
+     */
+    Nhx(bool useTagsAsPptNames = true);
+    virtual ~Nhx() {}
+  
+  public:
+
+    /**
+     * @name The IOTree interface
+     *
+     * @{
+     */
+    const std::string getFormatName() const;
+    const std::string getFormatDescription() const;
+    /* @} */
+
+    /**
+     * @name The ITree interface
+     *
+     * @{
+     */    
+    TreeTemplate<Node>* read(const std::string& path) const throw (Exception)
+    {
+      return dynamic_cast<TreeTemplate<Node>*>(AbstractITree::read(path));
+    }
+    
+    TreeTemplate<Node>* read(std::istream& in) const throw (Exception);
+    /** @} */
+
+    /**
+     * @name The OTree interface
+     *
+     * @{
+     */
+    void write(const Tree& tree, const std::string& path, bool overwrite = true) const throw (Exception)
+    {
+      AbstractOTree::write(tree, path, overwrite);
+    }
+    
+    void write(const Tree& tree, std::ostream& out) const throw (Exception)
+    {
+      write_(tree, out);
+    }
+    /** @} */
+
+    /**
+     * @name The IMultiTree interface
+     *
+     * @{
+     */
+    void read(const std::string& path, std::vector<Tree*>& trees) const throw (Exception)
+    {
+      AbstractIMultiTree::read(path, trees);
+    }
+    void read(std::istream& in, std::vector<Tree*>& trees) const throw (Exception);
+    /**@}*/
+
+    /**
+     * @name The OMultiTree interface
+     *
+     * @{
+     */
+    void write(const std::vector<Tree*>& trees, const std::string& path, bool overwrite = true) const throw (Exception)
+    {
+      AbstractOMultiTree::write(trees, path, overwrite);
+    }
+    void write(const std::vector<Tree*>& trees, std::ostream& out) const throw (Exception)
+    {
+      write_(trees, out);
+    }
+    /** @} */
+
+    TreeTemplate<Node>* parenthesisToTree(const std::string& description) const throw (Exception);
+
+    std::string treeToParenthesis(const TreeTemplate<Node>& tree) const;
+
+    void registerProperty(const Property& property) {
+      supportedProperties_.insert(property);
+    }
+
+    /**
+     * @brief Convert property names from tag to names.
+     *
+     * If a tree has been parsed using useTagsAsPropertyNames=true,
+     * this method allows to convert the tree as is it was parsed using
+     * the option set to false.
+     *
+     * @param node The root node of the subtree to convert.
+     */
+    void changeTagsToNames(Node& node) const;
+
+    /**
+     * @brief Convert property names from names to tags.
+     *
+     * If a tree has been parsed using useTagsAsPropertyNames=false,
+     * this method allows to convert the tree as is it was parsed using
+     * the option set to true.
+     *
+     * @param node The root node of the subtree to convert.
+     */
+    void changeNamesToTags(Node& node) const;
+
+    void useTagsAsPropertyNames(bool yn) { useTagsAsPropertyNames_ = yn; }
+    bool useTagsAsPropertyNames() const { return useTagsAsPropertyNames_; }
+
+  protected:
+    void write_(const Tree& tree, std::ostream& out) const throw (Exception);
+    
+    template<class N>
+    void write_(const TreeTemplate<N>& tree, std::ostream& out) const throw (Exception);
+    
+    void write_(const std::vector<Tree*>& trees, std::ostream& out) const throw (Exception);
+    
+    template<class N>
+    void write_(const std::vector<TreeTemplate<N>*>& trees, std::ostream& out) const throw (Exception);
+
+    Element getElement(const std::string& elt) const throw (IOException);
+
+    Node* parenthesisToNode(const std::string& description) const;
+  
+    std::string propertiesToParenthesis(const Node& node) const;
+  
+    std::string nodeToParenthesis(const Node& node) const;
+  
+    bool setNodeProperties(Node& node, const std::string properties) const;
+
+    static std::string propertyToString_(const Clonable* pptObject, short type) throw (Exception);
+    static Clonable* stringToProperty_(const std::string& pptDesc, short type) throw (Exception);
+};
+
+} //end of namespace bpp.
+
+#endif  //_NHX_H_
+
diff --git a/src/Bpp/Phyl/Io/PhylipDistanceMatrixFormat.cpp b/src/Bpp/Phyl/Io/PhylipDistanceMatrixFormat.cpp
new file mode 100755
index 0000000..d61533b
--- /dev/null
+++ b/src/Bpp/Phyl/Io/PhylipDistanceMatrixFormat.cpp
@@ -0,0 +1,123 @@
+//
+// File: PhylipDistanceMatrixFormat.cpp
+// Created by: Julien Dutheil
+// Created on: Wed Jun 08 15:57 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "PhylipDistanceMatrixFormat.h"
+
+#include <Bpp/Io/FileTools.h>
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Text/StringTokenizer.h>
+
+// From SeqLib:
+#include <Bpp/Seq/DistanceMatrix.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iomanip>
+
+using namespace std;
+
+DistanceMatrix * PhylipDistanceMatrixFormat::read(istream& in) const throw (Exception)
+{
+	string s = FileTools::getNextLine(in);
+	// the size of the matrix:
+	unsigned int n = TextTools::fromString<unsigned int>(s);
+	DistanceMatrix * dist = new DistanceMatrix(n);
+	unsigned int rowNumber = 0;
+	unsigned int colNumber = 0;
+	s = FileTools::getNextLine(in);
+	while (in)
+  {
+		if (colNumber == 0)
+    { // New row
+      if (extended_) {
+        size_t pos = s.find("  ");
+        if (pos == string::npos)
+          throw Exception("PhylipDistanceMatrixFormat::read. Bad format, probably not 'extended' Phylip.");
+        dist->setName(rowNumber, s.substr(0, pos));
+        s = s.substr(pos + 2);
+      } else {
+        dist->setName(rowNumber, s.substr(0, 10));
+        s = s.substr(11);
+      }
+    }
+		StringTokenizer st(s, "\t ");
+		for (; colNumber < n && st.hasMoreToken(); colNumber++)
+    {
+			double d = TextTools::fromString<double>(st.nextToken());
+			(* dist)(rowNumber, colNumber) = d;
+		}
+		if (colNumber == n)
+    {
+			colNumber = 0;
+			rowNumber++;
+		}
+		s = FileTools::getNextLine(in);
+	}
+	return dist;
+}
+
+void PhylipDistanceMatrixFormat::write(const DistanceMatrix& dist, ostream& out) const throw (Exception)
+{
+	size_t n = dist.size();
+	out << "   " << n << endl;
+  size_t offset = 10;
+  if (extended_) {
+    offset = 0;
+    for (size_t i = 0; i < n; ++i) {
+      size_t s = dist.getName(i).size();
+      if (s > offset) offset = s;
+    }
+  }
+	for (unsigned int i = 0; i < n; i++)
+  {
+    out << TextTools::resizeRight(dist.getName(i), offset, ' ');
+    if (extended_) {
+      out << "  ";
+    } else {
+      out << " ";
+    }
+    for (unsigned int j = 0; j < n; j++) {
+      if (j > 0) out << " ";
+		  out << setprecision(8) << dist(i, j); 
+    }
+		out << endl;
+	}
+}
+
diff --git a/src/Bpp/Phyl/Io/PhylipDistanceMatrixFormat.h b/src/Bpp/Phyl/Io/PhylipDistanceMatrixFormat.h
new file mode 100755
index 0000000..dc1d61d
--- /dev/null
+++ b/src/Bpp/Phyl/Io/PhylipDistanceMatrixFormat.h
@@ -0,0 +1,87 @@
+//
+// File: PhylipDistanceMatrixFormat.h
+// Created by: Julien Dutheil
+// Created on: Wed Jun 08 15:57 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _PHYLIPDISTANCEMATRIXFORMAT_H_
+#define _PHYLIPDISTANCEMATRIXFORMAT_H_
+
+#include "IoDistanceMatrix.h"
+
+namespace bpp
+{
+
+/**
+ * @brief Distance matrix I/O in Phylip format.
+ *
+ * Entry names must be 10 characters long. If 'extended' is set to true, then
+ * entry names can be of any size, and should be separated from the data by at least two spaces.
+ * Names should therefor not contian more than one consecutive space.
+ */
+class PhylipDistanceMatrixFormat:
+  public AbstractIDistanceMatrix,
+  public AbstractODistanceMatrix
+{
+  private:
+    bool extended_;
+
+	public:
+		PhylipDistanceMatrixFormat(bool extended = false): extended_(extended) {}
+		virtual ~PhylipDistanceMatrixFormat() {}
+
+	public:
+		const std::string getFormatName() const { return "Phylip"; }
+
+		const std::string getFormatDescription() const {	return "Multiline space-delimited columns."; }
+		DistanceMatrix* read(const std::string& path) const throw (Exception)
+		{
+			return AbstractIDistanceMatrix::read(path); 
+		}
+		DistanceMatrix* read(std::istream& in) const throw (Exception);
+		
+		void write(const DistanceMatrix& dist, const std::string& path, bool overwrite = true) const throw (Exception)
+		{
+			AbstractODistanceMatrix::write(dist, path, overwrite);
+		}
+		void write(const DistanceMatrix& dist, std::ostream& out) const throw (Exception);
+
+};
+
+} //end of namespace bpp.
+
+#endif //_PHYLIPDISTANCEMATRIXFORMAT_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/AbstractDiscreteRatesAcrossSitesTreeLikelihood.cpp b/src/Bpp/Phyl/Likelihood/AbstractDiscreteRatesAcrossSitesTreeLikelihood.cpp
new file mode 100644
index 0000000..25c92da
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/AbstractDiscreteRatesAcrossSitesTreeLikelihood.cpp
@@ -0,0 +1,332 @@
+//
+// File: AbstractDiscreteRatesAcrossSitesTreeLikelihood.cpp
+// Created by: Julien Dutheil
+// Created on: Wue Jun 15 09:42 2005
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "AbstractDiscreteRatesAcrossSitesTreeLikelihood.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+
+using namespace std;
+
+/******************************************************************************/
+
+AbstractDiscreteRatesAcrossSitesTreeLikelihood::AbstractDiscreteRatesAcrossSitesTreeLikelihood(
+  DiscreteDistribution* rDist,
+  bool verbose)
+throw (Exception) :
+  rateDistribution_(rDist)
+{
+  AbstractTreeLikelihood::enableDerivatives(true);
+}
+
+/******************************************************************************/
+
+ParameterList AbstractDiscreteRatesAcrossSitesTreeLikelihood::getRateDistributionParameters() const
+{
+  if (!initialized_)
+    throw Exception("AbstractDiscreteRatesAcrossSitesTreeLikelihood::getRateDistributionParameters(). Object is not initialized.");
+  return rateDistribution_->getParameters().getCommonParametersWith(getParameters());
+}
+
+/******************************************************************************/
+
+ParameterList AbstractDiscreteRatesAcrossSitesTreeLikelihood::getDerivableParameters() const
+{
+  if (!initialized_)
+    throw Exception("AbstractDiscreteRatesAcrossSitesTreeLikelihood::getDerivableParameters(). Object is not initialized.");
+  return getBranchLengthsParameters();
+}
+
+/******************************************************************************/
+
+ParameterList AbstractDiscreteRatesAcrossSitesTreeLikelihood::getNonDerivableParameters() const
+{
+  if (!initialized_)
+    throw Exception("AbstractDiscreteRatesAcrossSitesTreeLikelihood::getNonDerivableParameters(). Object is not initialized.");
+  ParameterList tmp = getSubstitutionModelParameters();
+  tmp.addParameters(getRateDistributionParameters());
+  return tmp;
+}
+
+/******************************************************************************/
+
+VVdouble AbstractDiscreteRatesAcrossSitesTreeLikelihood::getLikelihoodForEachSiteForEachRateClass() const
+{
+  size_t nbSites   = getNumberOfSites();
+  size_t nbClasses = getNumberOfClasses();
+  VVdouble l(nbSites);
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    l[i].resize(nbClasses);
+    for (size_t j = 0; j < nbClasses; j++)
+    {
+      l[i][j] = getLikelihoodForASiteForARateClass(i, j);
+    }
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+double AbstractDiscreteRatesAcrossSitesTreeLikelihood::getLikelihoodForASiteForAState(size_t site, int state) const
+{
+  size_t nbClasses = getNumberOfClasses();
+  double l = 0;
+  for (size_t i = 0; i < nbClasses; i++)
+  {
+    l += getLikelihoodForASiteForARateClassForAState(site, i, state) * rateDistribution_->getProbability(i);
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+double AbstractDiscreteRatesAcrossSitesTreeLikelihood::getLogLikelihoodForASiteForAState(size_t site, int state) const
+{
+  size_t nbClasses = getNumberOfClasses();
+  double l = 0;
+  for (size_t i = 0; i < nbClasses; i++)
+  {
+    l += getLikelihoodForASiteForARateClassForAState(site, i, state) * rateDistribution_->getProbability(i);
+  }
+  // if(l <= 0.) cerr << "WARNING!!! Negative likelihood." << endl;
+  return log(l);
+}
+
+/******************************************************************************/
+
+VVdouble AbstractDiscreteRatesAcrossSitesTreeLikelihood::getLogLikelihoodForEachSiteForEachRateClass() const
+{
+  size_t nbSites   = getNumberOfSites();
+  size_t nbClasses = getNumberOfClasses();
+  VVdouble l(nbSites);
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    l[i] = Vdouble(nbClasses);
+    for (size_t j = 0; j < nbClasses; j++)
+    {
+      l[i][j] = getLogLikelihoodForASiteForARateClass(i, j);
+    }
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+VVVdouble AbstractDiscreteRatesAcrossSitesTreeLikelihood::getLikelihoodForEachSiteForEachRateClassForEachState() const
+{
+  size_t nbSites   = getNumberOfSites();
+  size_t nbClasses = getNumberOfClasses();
+  size_t nbStates  = getNumberOfStates();
+  VVVdouble l(nbSites);
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    l[i].resize(nbClasses);
+    for (size_t j = 0; j < nbClasses; j++)
+    {
+      l[i][j].resize(nbStates);
+      for (size_t x = 0; x < nbStates; x++)
+      {
+        l[i][j][x] = getLikelihoodForASiteForARateClassForAState(i, j, static_cast<int>(x));
+      }
+    }
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+VVVdouble AbstractDiscreteRatesAcrossSitesTreeLikelihood::getLogLikelihoodForEachSiteForEachRateClassForEachState() const
+{
+  size_t nbSites   = getNumberOfSites();
+  size_t nbClasses = getNumberOfClasses();
+  size_t nbStates  = getNumberOfStates();
+  VVVdouble l(nbSites);
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    l[i].resize(nbClasses);
+    for (size_t j = 0; j < nbClasses; j++)
+    {
+      l[i][j].resize(nbStates);
+      for (size_t x = 0; x < nbStates; x++)
+      {
+        l[i][j][x] = getLogLikelihoodForASiteForARateClassForAState(i, j, static_cast<int>(x));
+      }
+    }
+  }
+  return l;
+}
+
+/*******************************************************************************/
+
+VVdouble AbstractDiscreteRatesAcrossSitesTreeLikelihood::getPosteriorProbabilitiesOfEachRate() const
+{
+  size_t nbSites   = getNumberOfSites();
+  size_t nbClasses = getNumberOfClasses();
+  VVdouble pb = getLikelihoodForEachSiteForEachRateClass();
+  Vdouble l  = getLikelihoodForEachSite();
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    for (size_t j = 0; j < nbClasses; j++)
+    {
+      pb[i][j] = pb[i][j] * rateDistribution_->getProbability(j) / l[i];
+    }
+  }
+  return pb;
+}
+
+/******************************************************************************/
+
+Vdouble AbstractDiscreteRatesAcrossSitesTreeLikelihood::getPosteriorRateOfEachSite() const
+{
+  size_t nbSites   = getNumberOfSites();
+  size_t nbClasses = getNumberOfClasses();
+  VVdouble lr = getLikelihoodForEachSiteForEachRateClass();
+  Vdouble l  = getLikelihoodForEachSite();
+  Vdouble rates(nbSites, 0.);
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    for (size_t j = 0; j < nbClasses; j++)
+    {
+      rates[i] += (lr[i][j] / l[i]) * rateDistribution_->getProbability(j) *  rateDistribution_->getCategory(j);
+    }
+  }
+  return rates;
+}
+
+/******************************************************************************/
+
+vector<size_t> AbstractDiscreteRatesAcrossSitesTreeLikelihood::getRateClassWithMaxPostProbOfEachSite() const
+{
+  size_t nbSites = getNumberOfSites();
+  VVdouble l = getLikelihoodForEachSiteForEachRateClass();
+  vector<size_t> classes(nbSites);
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    classes[i] = VectorTools::whichMax<double>(l[i]);
+  }
+  return classes;
+}
+
+/******************************************************************************/
+
+Vdouble AbstractDiscreteRatesAcrossSitesTreeLikelihood::getRateWithMaxPostProbOfEachSite() const
+{
+  size_t nbSites = getNumberOfSites();
+  VVdouble l = getLikelihoodForEachSiteForEachRateClass();
+  Vdouble rates(nbSites);
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    rates[i] = rateDistribution_->getCategory(VectorTools::whichMax<double>(l[i]));
+  }
+  return rates;
+}
+
+/******************************************************************************/
+
+void AbstractDiscreteRatesAcrossSitesTreeLikelihood::resetLikelihoodArray(
+  VVVdouble& likelihoodArray)
+{
+  size_t nbSites   = likelihoodArray.size();
+  size_t nbClasses = likelihoodArray[0].size();
+  size_t nbStates  = likelihoodArray[0][0].size();
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    for (size_t c = 0; c < nbClasses; c++)
+    {
+      for (size_t s = 0; s < nbStates; s++)
+      {
+        likelihoodArray[i][c][s] = 1.;
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+void AbstractDiscreteRatesAcrossSitesTreeLikelihood::displayLikelihoodArray(
+  const VVVdouble& likelihoodArray)
+{
+  size_t nbSites   = likelihoodArray.size();
+  size_t nbClasses = likelihoodArray[0].size();
+  size_t nbStates  = likelihoodArray[0][0].size();
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    cout << "Site " << i << ":" << endl;
+    for (size_t c = 0; c < nbClasses; c++)
+    {
+      cout << "Rate class " << c;
+      for (size_t s = 0; s < nbStates; s++)
+      {
+        cout << "\t" << likelihoodArray[i][c][s];
+      }
+      cout << endl;
+    }
+    cout << endl;
+  }
+}
+
+/******************************************************************************/
+
+VVdouble AbstractDiscreteRatesAcrossSitesTreeLikelihood::getTransitionProbabilities(int nodeId, size_t siteIndex) const
+{
+  VVVdouble p3 = getTransitionProbabilitiesPerRateClass(nodeId, siteIndex);
+  VVdouble p2;
+  Vdouble probs = rateDistribution_->getProbabilities();
+  p2.resize(getNumberOfStates());
+  for (size_t i = 0; i < p2.size(); i++)
+  {
+    p2[i].resize(getNumberOfStates());
+    for (size_t j = 0; j < p2.size(); j++)
+    {
+      for (size_t k = 0; k < getNumberOfClasses(); k++)
+      {
+        p2[i][j] += p3[k][i][j] * probs[k];
+      }
+    }
+  }
+  return p2;
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Likelihood/AbstractDiscreteRatesAcrossSitesTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/AbstractDiscreteRatesAcrossSitesTreeLikelihood.h
new file mode 100755
index 0000000..41d471a
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/AbstractDiscreteRatesAcrossSitesTreeLikelihood.h
@@ -0,0 +1,147 @@
+//
+// File: AbstractDiscreteRatesAcrossSitesTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Wed Jun 15 09:42 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _ABSTRACTDISCRETERATEACROSSSITESTREELIKELIHOOD_H_
+#define _ABSTRACTDISCRETERATEACROSSSITESTREELIKELIHOOD_H_
+
+#include "AbstractTreeLikelihood.h"
+#include "DiscreteRatesAcrossSitesTreeLikelihood.h"
+#include "../Model/SubstitutionModel.h"
+
+namespace bpp
+{
+
+/**
+ * @brief Partial implementation of the DiscreteRatesAcrossSitesTreeLikelihood interface.
+ *
+ * It contains a pointer toward a DiscreteDistribution object.
+ * This object may be shared by several instances of the class.
+ */
+class AbstractDiscreteRatesAcrossSitesTreeLikelihood:
+	public AbstractTreeLikelihood,
+	public virtual DiscreteRatesAcrossSitesTreeLikelihood
+{
+	protected:
+		DiscreteDistribution* rateDistribution_;
+		
+	public:
+		AbstractDiscreteRatesAcrossSitesTreeLikelihood(
+			DiscreteDistribution* rDist,
+			bool verbose = true
+		)	throw (Exception);
+		
+    AbstractDiscreteRatesAcrossSitesTreeLikelihood(
+        const AbstractDiscreteRatesAcrossSitesTreeLikelihood& tl) :
+      AbstractTreeLikelihood(tl),
+      rateDistribution_(tl.rateDistribution_)
+    {}
+
+    AbstractDiscreteRatesAcrossSitesTreeLikelihood& operator=(
+        const AbstractDiscreteRatesAcrossSitesTreeLikelihood& tl)
+    {
+      AbstractTreeLikelihood::operator=(tl);
+      rateDistribution_ = tl.rateDistribution_;
+      return *this;
+    }
+
+		virtual ~AbstractDiscreteRatesAcrossSitesTreeLikelihood() {}
+		
+	public:
+		
+		/**
+		 * @name The TreeLikelihood interface.
+		 *
+		 * Other methods are implemented in the AbstractTreeLikelihood class.
+		 *
+		 * @{
+		 */
+		double getLikelihoodForASiteForAState (size_t site, int state) const;
+		double getLogLikelihoodForASiteForAState(size_t site, int state) const;
+		ParameterList getDerivableParameters() const;
+		ParameterList getNonDerivableParameters() const;
+    VVdouble getTransitionProbabilities(int nodeId, size_t siteIndex) const;
+	 		/** @} */
+
+		/**
+		 * @name The DiscreteRatesAcrossSites interface implementation:
+		 *
+		 * @{
+		 */
+		const DiscreteDistribution* getRateDistribution() const { return rateDistribution_; }
+		      DiscreteDistribution* getRateDistribution()       { return rateDistribution_; }
+		size_t getNumberOfClasses() const { return rateDistribution_->getNumberOfCategories(); } 
+		ParameterList getRateDistributionParameters() const;
+		VVdouble getLikelihoodForEachSiteForEachRateClass() const;
+		VVdouble getLogLikelihoodForEachSiteForEachRateClass() const;
+		VVVdouble getLikelihoodForEachSiteForEachRateClassForEachState() const;
+		VVVdouble getLogLikelihoodForEachSiteForEachRateClassForEachState() const;
+		VVdouble getPosteriorProbabilitiesOfEachRate() const;
+		Vdouble getRateWithMaxPostProbOfEachSite() const;
+    std::vector<size_t> getRateClassWithMaxPostProbOfEachSite() const;
+		Vdouble getPosteriorRateOfEachSite() const;
+		/** @} */
+
+		/**
+     * @name Generic tools to deal with likelihood arrays
+     *
+     * @{
+     */
+    
+    /**
+     * @brief Set all conditional likelihoods to 1.
+     *
+     * @param likelihoodArray the likelihood array.
+     */
+    static void resetLikelihoodArray(VVVdouble & likelihoodArray);
+
+    /**
+     * @brief Print the likelihood array to terminal (debugging tool).
+     * 
+     * @param likelihoodArray the likelihood array.
+     */
+		static void displayLikelihoodArray(const VVVdouble & likelihoodArray);
+
+    /** @} */
+    
+};
+
+} //end of namespace bpp.
+
+#endif //_ABSTRACTDISCRETERATEACROSSSITESTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/AbstractHomogeneousTreeLikelihood.cpp b/src/Bpp/Phyl/Likelihood/AbstractHomogeneousTreeLikelihood.cpp
new file mode 100644
index 0000000..849720f
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/AbstractHomogeneousTreeLikelihood.cpp
@@ -0,0 +1,415 @@
+//
+// File: AbstractHomogeneousTreeLikelihood.cpp
+// Created by: Julien Dutheil
+// Created on: Thr Dec 23 12:03 2004
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "AbstractHomogeneousTreeLikelihood.h"
+#include "../PatternTools.h"
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/App/ApplicationTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/SiteTools.h>
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+
+using namespace std;
+
+/******************************************************************************/
+
+AbstractHomogeneousTreeLikelihood::AbstractHomogeneousTreeLikelihood(
+  const Tree& tree,
+  SubstitutionModel* model,
+  DiscreteDistribution* rDist,
+  bool checkRooted,
+  bool verbose)
+throw (Exception) :
+  AbstractDiscreteRatesAcrossSitesTreeLikelihood(rDist, verbose),
+  model_(0),
+  brLenParameters_(),
+  pxy_(),
+  dpxy_(),
+  d2pxy_(),
+  rootFreqs_(),
+  nodes_(),
+  nbSites_(),
+  nbDistinctSites_(),
+  nbClasses_(),
+  nbStates_(),
+  nbNodes_(),
+  verbose_(),
+  minimumBrLen_(),
+  maximumBrLen_(),
+  brLenConstraint_()
+{
+  init_(tree, model, rDist, checkRooted, verbose);
+}
+
+/******************************************************************************/
+
+AbstractHomogeneousTreeLikelihood::AbstractHomogeneousTreeLikelihood(
+  const AbstractHomogeneousTreeLikelihood& lik) :
+  AbstractDiscreteRatesAcrossSitesTreeLikelihood(lik),
+  model_(lik.model_),
+  brLenParameters_(lik.brLenParameters_),
+  pxy_(lik.pxy_),
+  dpxy_(lik.dpxy_),
+  d2pxy_(lik.d2pxy_),
+  rootFreqs_(lik.rootFreqs_),
+  nodes_(),
+  nbSites_(lik.nbSites_),
+  nbDistinctSites_(lik.nbDistinctSites_),
+  nbClasses_(lik.nbClasses_),
+  nbStates_(lik.nbStates_),
+  nbNodes_(lik.nbNodes_),
+  verbose_(lik.verbose_),
+  minimumBrLen_(lik.minimumBrLen_),
+  maximumBrLen_(lik.maximumBrLen_),
+  brLenConstraint_(lik.brLenConstraint_->clone())
+{
+  nodes_ = tree_->getNodes();
+  nodes_.pop_back(); // Remove the root node (the last added!).
+}
+
+/******************************************************************************/
+
+AbstractHomogeneousTreeLikelihood& AbstractHomogeneousTreeLikelihood::operator=(
+  const AbstractHomogeneousTreeLikelihood& lik)
+{
+  AbstractDiscreteRatesAcrossSitesTreeLikelihood::operator=(lik);
+  model_           = lik.model_;
+  brLenParameters_ = lik.brLenParameters_;
+  pxy_             = lik.pxy_;
+  dpxy_            = lik.dpxy_;
+  d2pxy_           = lik.d2pxy_;
+  rootFreqs_       = lik.rootFreqs_;
+  nodes_ = tree_->getNodes();
+  nodes_.pop_back(); // Remove the root node (the last added!).
+  nbSites_         = lik.nbSites_;
+  nbDistinctSites_ = lik.nbDistinctSites_;
+  nbClasses_       = lik.nbClasses_;
+  nbStates_        = lik.nbStates_;
+  nbNodes_         = lik.nbNodes_;
+  verbose_         = lik.verbose_;
+  minimumBrLen_    = lik.minimumBrLen_;
+  maximumBrLen_    = lik.maximumBrLen_;
+  if (brLenConstraint_.get()) brLenConstraint_.release();
+  brLenConstraint_.reset(lik.brLenConstraint_->clone());
+  return *this;
+}
+
+/******************************************************************************/
+
+void AbstractHomogeneousTreeLikelihood::init_(
+  const Tree& tree,
+  SubstitutionModel* model,
+  DiscreteDistribution* rDist,
+  bool checkRooted,
+  bool verbose) throw (Exception)
+{
+  TreeTools::checkIds(tree, true);
+  tree_ = new TreeTemplate<Node>(tree);
+  if (checkRooted && tree_->isRooted())
+  {
+    if (verbose)
+      ApplicationTools::displayWarning("Tree has been unrooted.");
+    tree_->unroot();
+  }
+  nodes_ = tree_->getNodes();
+  nodes_.pop_back(); // Remove the root node (the last added!).
+  nbNodes_ = nodes_.size();
+  nbClasses_ = rateDistribution_->getNumberOfCategories();
+  setSubstitutionModel(model);
+
+  verbose_ = verbose;
+
+  minimumBrLen_ = 0.000001;
+  maximumBrLen_ = 10000;
+  brLenConstraint_.reset(new IntervalConstraint(minimumBrLen_, maximumBrLen_, true, true));
+}
+
+/******************************************************************************/
+
+void AbstractHomogeneousTreeLikelihood::setSubstitutionModel(SubstitutionModel* model) throw (Exception)
+{
+  // Check:
+  if (data_)
+  {
+    if (model->getAlphabet()->getAlphabetType() != data_->getAlphabet()->getAlphabetType())
+      throw Exception("AbstractHomogeneousTreeLikelihood::setSubstitutionModel(). Model alphabet do not match existing data.");
+  }
+
+  model_ = model;
+
+  if (data_)
+  {
+    if (model->getNumberOfStates() != model_->getNumberOfStates())
+      setData(*data_);  // Have to reinitialize the whole data structure.
+  }
+
+  nbStates_ = model->getNumberOfStates();
+
+  // Allocate transition probabilities arrays:
+  for (unsigned int l = 0; l < nbNodes_; l++)
+  {
+    // For each son node,i
+    Node* son = nodes_[l];
+
+    VVVdouble* pxy__son = &pxy_[son->getId()];
+    pxy__son->resize(nbClasses_);
+    for (unsigned int c = 0; c < nbClasses_; c++)
+    {
+      VVdouble* pxy__son_c = &(*pxy__son)[c];
+      pxy__son_c->resize(nbStates_);
+      for (unsigned int x = 0; x < nbStates_; x++)
+      {
+        (*pxy__son_c)[x].resize(nbStates_);
+      }
+    }
+
+    VVVdouble* dpxy__son = &dpxy_[son->getId()];
+    dpxy__son->resize(nbClasses_);
+    for (unsigned int c = 0; c < nbClasses_; c++)
+    {
+      VVdouble* dpxy__son_c = &(*dpxy__son)[c];
+      dpxy__son_c->resize(nbStates_);
+      for (unsigned int x = 0; x < nbStates_; x++)
+      {
+        (*dpxy__son_c)[x].resize(nbStates_);
+      }
+    }
+
+    VVVdouble* d2pxy__son = &d2pxy_[son->getId()];
+    d2pxy__son->resize(nbClasses_);
+    for (unsigned int c = 0; c < nbClasses_; c++)
+    {
+      VVdouble* d2pxy__son_c = &(*d2pxy__son)[c];
+      d2pxy__son_c->resize(nbStates_);
+      for (unsigned int x = 0; x < nbStates_; x++)
+      {
+        (*d2pxy__son_c)[x].resize(nbStates_);
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+void AbstractHomogeneousTreeLikelihood::initialize() throw (Exception)
+{
+  if (initialized_)
+    throw Exception("AbstractHomogeneousTreeLikelihood::initialize(). Object is already initialized.");
+  if (!data_)
+    throw Exception("AbstractHomogeneousTreeLikelihood::initialize(). Data are no set.");
+  initParameters();
+  initialized_ = true;
+  fireParameterChanged(getParameters());
+}
+
+/******************************************************************************/
+
+ParameterList AbstractHomogeneousTreeLikelihood::getBranchLengthsParameters() const
+{
+  if (!initialized_)
+    throw Exception("AbstractHomogeneousTreeLikelihood::getBranchLengthsParameters(). Object is not initialized.");
+  return brLenParameters_.getCommonParametersWith(getParameters());
+}
+
+/******************************************************************************/
+
+ParameterList AbstractHomogeneousTreeLikelihood::getSubstitutionModelParameters() const
+{
+  if (!initialized_)
+    throw Exception("AbstractHomogeneousTreeLikelihood::getSubstitutionModelParameters(). Object is not initialized.");
+  return model_->getParameters().getCommonParametersWith(getParameters());
+}
+
+/******************************************************************************/
+
+void AbstractHomogeneousTreeLikelihood::initParameters()
+{
+  // Reset parameters:
+  resetParameters_();
+
+  // Branch lengths:
+  initBranchLengthsParameters();
+  addParameters_(brLenParameters_);
+
+  // Substitution model:
+  addParameters_(model_->getIndependentParameters());
+
+  // Rate distribution:
+  addParameters_(rateDistribution_->getIndependentParameters());
+}
+
+/******************************************************************************/
+
+void AbstractHomogeneousTreeLikelihood::applyParameters() throw (Exception)
+{
+  if (!initialized_)
+    throw Exception("AbstractHomogeneousTreeLikelihood::applyParameters(). Object not initialized.");
+  // Apply branch lengths:
+  // brLenParameters_.matchParametersValues(parameters_); Not necessary!
+  for (unsigned int i = 0; i < nbNodes_; i++)
+  {
+    const Parameter* brLen = &getParameter(string("BrLen") + TextTools::toString(i));
+    if (brLen)
+      nodes_[i]->setDistanceToFather(brLen->getValue());
+  }
+  // Apply substitution model parameters:
+  model_->matchParametersValues(getParameters());
+  rootFreqs_ = model_->getFrequencies();
+  // Apply rate distribution parameters:
+  rateDistribution_->matchParametersValues(getParameters());
+}
+
+/******************************************************************************/
+
+void AbstractHomogeneousTreeLikelihood::initBranchLengthsParameters()
+{
+  brLenParameters_.reset();
+  for (unsigned int i = 0; i < nbNodes_; i++)
+  {
+    double d = minimumBrLen_;
+    if (!nodes_[i]->hasDistanceToFather())
+    {
+      ApplicationTools::displayWarning("Missing branch length " + TextTools::toString(i) + ". Value is set to " + TextTools::toString(minimumBrLen_));
+      nodes_[i]->setDistanceToFather(minimumBrLen_);
+    }
+    else
+    {
+      d = nodes_[i]->getDistanceToFather();
+      if (d < minimumBrLen_)
+      {
+        ApplicationTools::displayWarning("Branch length " + TextTools::toString(i) + " is too small: " + TextTools::toString(d) + ". Value is set to " + TextTools::toString(minimumBrLen_));
+        nodes_[i]->setDistanceToFather(minimumBrLen_);
+        d = minimumBrLen_;
+      }
+      if (d > maximumBrLen_)
+      {
+        ApplicationTools::displayWarning("Branch length " + TextTools::toString(i) + " is too big: " + TextTools::toString(d) + ". Value is set to " + TextTools::toString(maximumBrLen_));
+        nodes_[i]->setDistanceToFather(maximumBrLen_);
+        d = maximumBrLen_;
+      }
+    }
+    brLenParameters_.addParameter(Parameter("BrLen" + TextTools::toString(i), d, brLenConstraint_->clone(), true)); // Attach constraint to avoid clonage problems!
+  }
+}
+
+/*******************************************************************************/
+
+void AbstractHomogeneousTreeLikelihood::computeAllTransitionProbabilities()
+{
+  for (unsigned int l = 0; l < nbNodes_; l++)
+  {
+    // For each node,
+    Node* node = nodes_[l];
+    computeTransitionProbabilitiesForNode(node);
+  }
+  rootFreqs_ = model_->getFrequencies();
+}
+
+/*******************************************************************************/
+
+void AbstractHomogeneousTreeLikelihood::computeTransitionProbabilitiesForNode(const Node* node)
+{
+  double l = node->getDistanceToFather();
+
+  // Computes all pxy and pyx once for all:
+  VVVdouble* pxy__node = &pxy_[node->getId()];
+  for (unsigned int c = 0; c < nbClasses_; c++)
+  {
+    VVdouble* pxy__node_c = &(*pxy__node)[c];
+    RowMatrix<double> Q = model_->getPij_t(l * rateDistribution_->getCategory(c));
+    for (unsigned int x = 0; x < nbStates_; x++)
+    {
+      Vdouble* pxy__node_c_x = &(*pxy__node_c)[x];
+      for (unsigned int y = 0; y < nbStates_; y++)
+      {
+        (*pxy__node_c_x)[y] = Q(x, y);
+      }
+    }
+  }
+
+  if (computeFirstOrderDerivatives_)
+  {
+    // Computes all dpxy/dt once for all:
+    VVVdouble* dpxy__node = &dpxy_[node->getId()];
+    for (unsigned int c = 0; c < nbClasses_; c++)
+    {
+      VVdouble* dpxy__node_c = &(*dpxy__node)[c];
+      double rc = rateDistribution_->getCategory(c);
+      RowMatrix<double> dQ = model_->getdPij_dt(l * rc);
+      for (unsigned int x = 0; x < nbStates_; x++)
+      {
+        Vdouble* dpxy__node_c_x = &(*dpxy__node_c)[x];
+        for (unsigned int y = 0; y < nbStates_; y++)
+        {
+          (*dpxy__node_c_x)[y] = rc * dQ(x, y);
+        }
+      }
+    }
+  }
+
+  if (computeSecondOrderDerivatives_)
+  {
+    // Computes all d2pxy/dt2 once for all:
+    VVVdouble* d2pxy__node = &d2pxy_[node->getId()];
+    for (unsigned int c = 0; c < nbClasses_; c++)
+    {
+      VVdouble* d2pxy__node_c = &(*d2pxy__node)[c];
+      double rc =  rateDistribution_->getCategory(c);
+      RowMatrix<double> d2Q = model_->getd2Pij_dt2(l * rc);
+      for (unsigned int x = 0; x < nbStates_; x++)
+      {
+        Vdouble* d2pxy__node_c_x = &(*d2pxy__node_c)[x];
+        for (unsigned int y = 0; y < nbStates_; y++)
+        {
+          (*d2pxy__node_c_x)[y] = rc * rc * d2Q(x, y);
+        }
+      }
+    }
+  }
+}
+
+/*******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Likelihood/AbstractHomogeneousTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/AbstractHomogeneousTreeLikelihood.h
new file mode 100755
index 0000000..87d156f
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/AbstractHomogeneousTreeLikelihood.h
@@ -0,0 +1,261 @@
+//
+// File: AbstractHomogeneousTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Thr Dec 23 12:03 2004
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _ABSTRACTHOMOGENEOUSTREELIKELIHOOD_H_
+#define _ABSTRACTHOMOGENEOUSTREELIKELIHOOD_H_
+
+#include "AbstractDiscreteRatesAcrossSitesTreeLikelihood.h"
+#include "HomogeneousTreeLikelihood.h"
+
+//From STL:
+#include<memory>
+
+namespace bpp
+{
+
+/**
+ * @brief Partial implementation for homogeneous model of the TreeLikelihood interface.
+ *
+ * This class provides a pointer toward a single substitution model + several utilitary variables.
+ */
+class AbstractHomogeneousTreeLikelihood:
+  public virtual HomogeneousTreeLikelihood,
+  public AbstractDiscreteRatesAcrossSitesTreeLikelihood
+{
+  public:
+
+    class ConstHomogeneousSiteModelIterator :
+      public ConstSiteModelIterator
+    {
+      private:
+        ConstNoPartitionSiteModelDescription siteModelDescription_;
+        size_t index_;
+
+      public:
+        ConstHomogeneousSiteModelIterator(const Tree& tree, const SubstitutionModel* model) :
+          siteModelDescription_(model, tree.getBranchesId()), index_(0) {}
+
+      public:
+        ConstSiteModelDescription* next() throw (Exception)
+        {
+          if (!hasNext())
+            throw Exception("AbstractHomogeneousTreeLikelihood::ConstHomogeneousSiteModelIterator::next(). No more site in the set.");
+          index_++;
+          return &siteModelDescription_;
+        }
+
+        bool hasNext() const { return index_ == 0; }
+    };
+
+
+	protected:
+		SubstitutionModel* model_;
+		ParameterList brLenParameters_;
+		
+		mutable std::map<int, VVVdouble> pxy_;
+
+		mutable std::map<int, VVVdouble> dpxy_;
+
+		mutable std::map<int, VVVdouble> d2pxy_;
+
+    std::vector<double> rootFreqs_;
+				
+		/**
+		 * @brief Pointer toward all nodes in the tree.
+     *
+     * The position in the array is the number used in the parameter name.
+     * This may be different from the node id, unless you used the resetNodeId method on the input tree.
+ 		 */
+    std::vector<Node*> nodes_;
+
+		//some values we'll need:
+		size_t nbSites_,         //the number of sites in the container
+                 nbDistinctSites_, //the number of distinct sites
+		             nbClasses_,       //the number of rate classes
+		             nbStates_,        //the number of states in the alphabet
+		             nbNodes_;         //the number of nodes in the tree
+
+    bool verbose_;
+
+    double minimumBrLen_;
+    double maximumBrLen_;
+    std::auto_ptr<Constraint> brLenConstraint_;
+
+	public:
+		AbstractHomogeneousTreeLikelihood(
+			const Tree& tree,
+			SubstitutionModel* model,
+			DiscreteDistribution* rDist,
+      bool checkRooted = true,
+			bool verbose = true)
+      throw (Exception);
+
+    /**
+     * @brief Copy constructor
+     *
+     * This constructor is to be called by the derived class copy constructor.
+     */
+    AbstractHomogeneousTreeLikelihood(const AbstractHomogeneousTreeLikelihood& lik);
+    
+    /**
+     * @brief Assignation operator
+     *
+     * This operator is to be called by the derived class operator.
+     */
+    AbstractHomogeneousTreeLikelihood& operator=(const AbstractHomogeneousTreeLikelihood& lik);
+ 
+		virtual ~AbstractHomogeneousTreeLikelihood() {}
+		
+	private:
+
+    /**
+     * @brief Method called by constructor.
+     */
+    void init_(const Tree& tree,
+			SubstitutionModel* model,
+			DiscreteDistribution* rDist,
+      bool checkRooted,
+			bool verbose) throw (Exception);
+
+	public:
+		
+		/**
+		 * @name The TreeLikelihood interface.
+		 *
+		 * Other methods are implemented in the AbstractTreeLikelihood class.
+		 *
+		 * @{
+		 */
+    void initialize() throw(Exception);
+		
+    ParameterList getBranchLengthsParameters() const;
+		
+    ParameterList getSubstitutionModelParameters() const;
+		
+    ParameterList getRateDistributionParameters() const
+    {
+      return AbstractDiscreteRatesAcrossSitesTreeLikelihood::getRateDistributionParameters();
+    }
+    
+    const std::vector<double>& getRootFrequencies(size_t siteIndex) const { return model_->getFrequencies(); }
+    
+    VVVdouble getTransitionProbabilitiesPerRateClass(int nodeId, size_t siteIndex) const { return pxy_[nodeId]; }
+
+    ConstBranchModelIterator* getNewBranchModelIterator(int nodeId) const
+    {
+      return new ConstNoPartitionBranchModelIterator(model_, nbDistinctSites_);
+    }
+
+    ConstSiteModelIterator* getNewSiteModelIterator(size_t siteIndex) const
+    {
+      return new ConstHomogeneousSiteModelIterator(*tree_, model_);
+    }
+   
+    /** @} */
+
+		/**
+		 * @name The HomogeneousTreeLikelihood interface.
+		 *
+		 * Other methods are implemented in the AbstractTreeLikelihood class.
+		 *
+		 * @{
+		 */
+		const SubstitutionModel* getSubstitutionModel() const { return model_; }
+		
+		SubstitutionModel* getSubstitutionModel() { return model_; }
+		
+    void setSubstitutionModel(SubstitutionModel* model) throw (Exception);
+    /** @} */
+		
+	public: //Specific methods:
+
+		/**
+		 * @brief This builds the <i>parameters</i> list from all parametrizable objects,
+		 * <i>i.e.</i> substitution model, rate distribution and tree.
+		 */
+		virtual void initParameters();
+
+		/**
+		 * @brief All parameters are stored in a parameter list.
+		 * This function apply these parameters to the substitution model,
+		 * to the rate distribution and to the branch lengths.
+		 */
+		virtual void applyParameters() throw (Exception);	
+
+		virtual void initBranchLengthsParameters();
+
+    virtual void setMinimumBranchLength(double minimum) throw (Exception)
+    {
+      if (minimum > maximumBrLen_)
+        throw Exception("AbstractHomogeneousTreeLikelihood::setMinimumBranchLength. Minimum branch length sould be lower than the maximum one: " + TextTools::toString(maximumBrLen_));
+      minimumBrLen_ = minimum;
+      if (brLenConstraint_.get()) brLenConstraint_.release();
+      brLenConstraint_.reset(new IntervalConstraint(minimumBrLen_, maximumBrLen_, true, true));
+      initBranchLengthsParameters();
+    }
+
+    virtual void setMaximumBranchLength(double maximum) throw (Exception)
+    {
+      if (maximum < minimumBrLen_)
+        throw Exception("AbstractHomogeneousTreeLikelihood::setMaximumBranchLength. Maximum branch length sould be higher than the minimum one: " + TextTools::toString(minimumBrLen_));
+      maximumBrLen_ = maximum;
+      if (brLenConstraint_.get()) brLenConstraint_.release();
+      brLenConstraint_.reset(new IntervalConstraint(minimumBrLen_, maximumBrLen_, true, true));
+      initBranchLengthsParameters();
+    }
+
+    virtual double getMinimumBranchLength() const { return minimumBrLen_; }
+    virtual double getMaximumBranchLength() const { return maximumBrLen_; }
+
+  protected:
+    /**
+     * @brief Fill the pxy_, dpxy_ and d2pxy_ arrays for all nodes.
+     */
+    virtual void computeAllTransitionProbabilities();
+    /**
+     * @brief Fill the pxy_, dpxy_ and d2pxy_ arrays for one node.
+     */
+    virtual void computeTransitionProbabilitiesForNode(const Node * node);
+
+};
+
+} //end of namespace bpp.
+
+#endif //_ABSTRACTHOMOGENEOUSTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/AbstractNonHomogeneousTreeLikelihood.cpp b/src/Bpp/Phyl/Likelihood/AbstractNonHomogeneousTreeLikelihood.cpp
new file mode 100644
index 0000000..a3e72a0
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/AbstractNonHomogeneousTreeLikelihood.cpp
@@ -0,0 +1,469 @@
+//
+// File: AbstractNonHomogeneousTreeLikelihood.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Oct 09 16:07 2007
+// From file: AbstractHomogeneousTreeLikelihood.cpp
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "AbstractNonHomogeneousTreeLikelihood.h"
+#include "../PatternTools.h"
+
+//From SeqLib:
+#include <Bpp/Seq/SiteTools.h>
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/App/ApplicationTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+
+using namespace std;
+
+/******************************************************************************/
+
+AbstractNonHomogeneousTreeLikelihood::AbstractNonHomogeneousTreeLikelihood(
+  const Tree& tree,
+  SubstitutionModelSet* modelSet,
+  DiscreteDistribution* rDist,
+  bool verbose,
+  bool reparametrizeRoot)
+  throw (Exception) :
+  AbstractDiscreteRatesAcrossSitesTreeLikelihood(rDist, verbose),
+  modelSet_(0),
+  brLenParameters_(),
+  pxy_(),
+  dpxy_(),
+  d2pxy_(),
+  rootFreqs_(),
+  nodes_(),
+  idToNode_(),
+  nbSites_(),
+  nbDistinctSites_(),
+  nbClasses_(),
+  nbStates_(),
+  nbNodes_(),
+  verbose_(),
+  minimumBrLen_(),
+  maximumBrLen_(),
+  brLenConstraint_(0),
+  reparametrizeRoot_(reparametrizeRoot),
+  root1_(),
+  root2_()
+{
+  init_(tree, modelSet, rDist, verbose);
+}
+
+/******************************************************************************/
+
+AbstractNonHomogeneousTreeLikelihood::AbstractNonHomogeneousTreeLikelihood(
+    const AbstractNonHomogeneousTreeLikelihood& lik) :
+  AbstractDiscreteRatesAcrossSitesTreeLikelihood(lik),
+  modelSet_(lik.modelSet_),
+  brLenParameters_(lik.brLenParameters_),
+  pxy_(lik.pxy_),
+  dpxy_(lik.dpxy_),
+  d2pxy_(lik.d2pxy_),
+  rootFreqs_(lik.rootFreqs_),
+  nodes_(),
+  idToNode_(),
+	nbSites_(lik.nbSites_),
+  nbDistinctSites_(lik.nbDistinctSites_),
+	nbClasses_(lik.nbClasses_),
+	nbStates_(lik.nbStates_),
+	nbNodes_(lik.nbNodes_),
+  verbose_(lik.verbose_),
+  minimumBrLen_(lik.minimumBrLen_),
+  maximumBrLen_(lik.maximumBrLen_),
+  brLenConstraint_(dynamic_cast<Constraint*>(lik.brLenConstraint_->clone())),
+  reparametrizeRoot_(lik.reparametrizeRoot_),
+  root1_(lik.root1_),
+  root2_(lik.root2_)
+{ 
+  nodes_ = tree_->getNodes();
+  nodes_.pop_back(); //Remove the root node (the last added!).  
+  //Rebuild nodes index:
+  for (unsigned int i = 0; i < nodes_.size(); i++)
+  {
+    const Node* node = nodes_[i];
+    idToNode_[node->getId()] = node;
+  }
+}
+
+/******************************************************************************/
+
+AbstractNonHomogeneousTreeLikelihood& AbstractNonHomogeneousTreeLikelihood::operator=(
+    const AbstractNonHomogeneousTreeLikelihood& lik)
+{
+  AbstractDiscreteRatesAcrossSitesTreeLikelihood::operator=(lik);
+  modelSet_          = lik.modelSet_;
+  brLenParameters_   = lik.brLenParameters_;
+  pxy_               = lik.pxy_;
+  dpxy_              = lik.dpxy_;
+  d2pxy_             = lik.d2pxy_;
+  rootFreqs_         = lik.rootFreqs_;
+  nodes_             = tree_->getNodes();
+  nodes_.pop_back(); //Remove the root node (the last added!).  
+	nbSites_           = lik.nbSites_;
+  nbDistinctSites_   = lik.nbDistinctSites_;
+	nbClasses_         = lik.nbClasses_;
+	nbStates_          = lik.nbStates_;
+	nbNodes_           = lik.nbNodes_;
+  verbose_           = lik.verbose_;
+  minimumBrLen_      = lik.minimumBrLen_;
+  maximumBrLen_      = lik.maximumBrLen_;
+  if (brLenConstraint_.get()) brLenConstraint_.release();
+  brLenConstraint_.reset(lik.brLenConstraint_->clone());
+  reparametrizeRoot_ = lik.reparametrizeRoot_;
+  root1_             = lik.root1_;
+  root2_             = lik.root2_;
+  //Rebuild nodes index:
+  for( unsigned int i = 0; i < nodes_.size(); i++)
+  {
+    const Node * node = nodes_[i];
+    idToNode_[node->getId()] = node;
+  }
+  return *this;
+}
+
+/******************************************************************************/
+
+void AbstractNonHomogeneousTreeLikelihood::init_(
+    const Tree& tree,
+			SubstitutionModelSet* modelSet,
+			DiscreteDistribution* rDist,
+			bool verbose) throw (Exception)
+{
+  TreeTools::checkIds(tree, true);
+  tree_ = new TreeTemplate<Node>(tree);
+  root1_ = tree_->getRootNode()->getSon(0)->getId();
+  root2_ = tree_->getRootNode()->getSon(1)->getId();
+  nodes_ = tree_->getNodes();
+  nodes_.pop_back(); //Remove the root node (the last added!).  
+  nbNodes_ = nodes_.size();
+  //Build nodes index:
+  for (unsigned int i = 0; i < nodes_.size(); i++)
+  {
+    const Node * node = nodes_[i];
+    idToNode_[node->getId()] = node;
+  }
+  nbClasses_ = rateDistribution_->getNumberOfCategories();
+
+  verbose_ = verbose;
+
+  minimumBrLen_ = 0.000001;
+  maximumBrLen_ = 10000;
+  brLenConstraint_.reset(new IntervalConstraint(minimumBrLen_, maximumBrLen_, true, true));
+  setSubstitutionModelSet(modelSet);
+}
+
+/******************************************************************************/
+
+void AbstractNonHomogeneousTreeLikelihood::setSubstitutionModelSet(SubstitutionModelSet* modelSet) throw (Exception)
+{
+  //Check:
+  if (data_)
+  {
+    if (modelSet->getAlphabet()->getAlphabetType() != data_->getAlphabet()->getAlphabetType())
+      throw Exception("AbstractBranchNonHomogeneousTreeLikelihood::setSubstitutionModelSet(). Model alphabet do not match existing data.");
+  }
+
+  modelSet_ = modelSet;
+  
+  if (data_)
+  {
+    if (modelSet->getNumberOfStates() != modelSet_->getNumberOfStates())
+      setData(*data_); //Have to reinitialize the whole data structure.
+  }
+  
+  nbStates_ = modelSet->getNumberOfStates();
+
+  //Allocate transition probabilities arrays:
+  for (unsigned int l = 0; l < nbNodes_; l++)
+  {
+    //For each son node,i
+    Node* son = nodes_[l];
+
+    VVVdouble* pxy__son = & pxy_[son->getId()];
+    pxy__son->resize(nbClasses_);
+    for (unsigned int c = 0; c < nbClasses_; c++)
+    {
+      VVdouble * pxy__son_c = & (* pxy__son)[c];
+      pxy__son_c->resize(nbStates_);
+      for(unsigned int x = 0; x < nbStates_; x++)
+      {
+        (*pxy__son_c)[x].resize(nbStates_);
+      }
+    }
+  
+    VVVdouble* dpxy__son = & dpxy_[son->getId()];
+    dpxy__son->resize(nbClasses_);
+    for (unsigned int c = 0; c < nbClasses_; c++)
+    {
+      VVdouble * dpxy__son_c = & (* dpxy__son)[c];
+      dpxy__son_c->resize(nbStates_);
+      for(unsigned int x = 0; x < nbStates_; x++)
+      {
+        (* dpxy__son_c)[x].resize(nbStates_);
+      }
+    }
+      
+    VVVdouble* d2pxy__son = & d2pxy_[son->getId()];
+    d2pxy__son->resize(nbClasses_);
+    for (unsigned int c = 0; c < nbClasses_; c++)
+    {
+      VVdouble * d2pxy__son_c = & (* d2pxy__son)[c];
+      d2pxy__son_c->resize(nbStates_);
+      for(unsigned int x = 0; x < nbStates_; x++)
+      {
+        (* d2pxy__son_c)[x].resize(nbStates_);
+      }
+    }
+  }
+
+  //We have to reset parameters. If the instance is not initialized, this will be done by the initialize method.
+  if (initialized_) 
+  {
+    initParameters();
+    computeAllTransitionProbabilities();
+    fireParameterChanged(getParameters());
+  }
+}
+
+/******************************************************************************/
+
+void AbstractNonHomogeneousTreeLikelihood::initialize() throw (Exception)
+{
+  if (initialized_) throw Exception("AbstractBranchNonHomogeneousTreeLikelihood::initialize(). Object is already initialized.");
+  if (!data_) throw Exception("AbstractBranchNonHomogeneousTreeLikelihood::initialize(). Data are no set.");
+  initParameters();
+  initialized_ = true;
+  computeAllTransitionProbabilities();
+  fireParameterChanged(getParameters());
+}
+
+/******************************************************************************/
+
+ParameterList AbstractNonHomogeneousTreeLikelihood::getBranchLengthsParameters() const
+{
+  if (!initialized_) throw Exception("AbstractBranchNonHomogeneousTreeLikelihood::getBranchLengthsParameters(). Object is not initialized.");
+  return brLenParameters_.getCommonParametersWith(getParameters());
+}
+
+/******************************************************************************/
+
+ParameterList AbstractNonHomogeneousTreeLikelihood::getSubstitutionModelParameters() const
+{
+  if(!initialized_) throw Exception("AbstractBranchNonHomogeneousTreeLikelihood::getSubstitutionModelParameters(). Object is not initialized.");
+  return modelSet_->getParameters().getCommonParametersWith(getParameters());
+}
+
+/******************************************************************************/
+
+void AbstractNonHomogeneousTreeLikelihood::initParameters()
+{
+  // Reset parameters:
+  resetParameters_();
+  
+  // Branch lengths:
+  initBranchLengthsParameters();
+  addParameters_(brLenParameters_);
+  
+  // Substitution model:
+  addParameters_(modelSet_->getIndependentParameters());
+  
+  // Rate distribution:
+  addParameters_(rateDistribution_->getIndependentParameters());
+}
+
+/******************************************************************************/
+
+void AbstractNonHomogeneousTreeLikelihood::applyParameters() throw (Exception)
+{
+  if (!initialized_) throw Exception("AbstractBranchNonHomogeneousTreeLikelihood::applyParameters(). Object not initialized.");
+  //Apply branch lengths:
+  for (unsigned int i = 0; i < nbNodes_; i++)
+  {
+    int id = nodes_[i]->getId();
+    if (reparametrizeRoot_ && id == root1_)
+    {
+      const Parameter* rootBrLen = &getParameter("BrLenRoot");
+      const Parameter* rootPos = &getParameter("RootPosition");
+      nodes_[i]->setDistanceToFather(rootBrLen->getValue() * rootPos->getValue());
+    }
+    else if (reparametrizeRoot_ && id == root2_)
+    {
+      const Parameter* rootBrLen = &getParameter("BrLenRoot");
+      const Parameter* rootPos = &getParameter("RootPosition");
+      nodes_[i]->setDistanceToFather(rootBrLen->getValue() * (1. - rootPos->getValue()));
+    }
+    else
+    {
+      const Parameter* brLen = &getParameter(string("BrLen") + TextTools::toString(i));
+      if (brLen) nodes_[i]->setDistanceToFather(brLen->getValue());
+    }
+  }
+  //Apply substitution model parameters:
+  modelSet_->matchParametersValues(getParameters());
+  //Apply rate distribution parameters:
+  rateDistribution_->matchParametersValues(getParameters());
+}
+
+/******************************************************************************/
+
+void AbstractNonHomogeneousTreeLikelihood::initBranchLengthsParameters()
+{
+  brLenParameters_.reset();
+  double l1 = 0, l2 = 0;
+  for (unsigned int i = 0; i < nbNodes_; i++)
+  {
+    double d = minimumBrLen_;
+    if (!nodes_[i]->hasDistanceToFather())
+    {
+      ApplicationTools::displayWarning("Missing branch length " + TextTools::toString(i) + ". Value is set to " + TextTools::toString(minimumBrLen_));
+      nodes_[i]->setDistanceToFather(minimumBrLen_);
+    }
+    else
+    {
+      d = nodes_[i]->getDistanceToFather();
+      if (d < minimumBrLen_)
+      {
+        ApplicationTools::displayWarning("Branch length " + TextTools::toString(i) + " is too small: " + TextTools::toString(d) + ". Value is set to " + TextTools::toString(minimumBrLen_));
+        nodes_[i]->setDistanceToFather(minimumBrLen_);
+        d = minimumBrLen_;
+      }
+      if (d > maximumBrLen_)
+      {
+        ApplicationTools::displayWarning("Branch length " + TextTools::toString(i) + " is too big: " + TextTools::toString(d) + ". Value is set to " + TextTools::toString(maximumBrLen_));
+        nodes_[i]->setDistanceToFather(maximumBrLen_);
+        d = maximumBrLen_;
+      }
+    }
+    if (reparametrizeRoot_ && nodes_[i]->getId() == root1_)
+      l1 = d;
+    else if (reparametrizeRoot_ && nodes_[i]->getId() == root2_)
+      l2 = d;
+    else
+    {
+      brLenParameters_.addParameter(Parameter("BrLen" + TextTools::toString(i), d, brLenConstraint_->clone(), true)); //Attach constraint to avoid clonage problems!
+    }
+  }
+  if (reparametrizeRoot_) {
+    brLenParameters_.addParameter(Parameter("BrLenRoot", l1 + l2, brLenConstraint_->clone(), true));
+    brLenParameters_.addParameter(Parameter("RootPosition", l1 / (l1 + l2), &Parameter::PROP_CONSTRAINT_EX));
+  }
+}
+
+/*******************************************************************************/
+
+void AbstractNonHomogeneousTreeLikelihood::computeAllTransitionProbabilities()
+{
+  for(unsigned int l = 0; l < nbNodes_; l++)
+  {
+    //For each node,
+    Node * node = nodes_[l];
+    computeTransitionProbabilitiesForNode(node);
+  }
+  rootFreqs_ = modelSet_->getRootFrequencies();
+}
+
+/*******************************************************************************/
+
+void AbstractNonHomogeneousTreeLikelihood::computeTransitionProbabilitiesForNode(const Node* node)
+{
+  const SubstitutionModel* model = modelSet_->getModelForNode(node->getId());
+  double l = node->getDistanceToFather(); 
+
+  //Computes all pxy and pyx once for all:
+  VVVdouble * pxy__node = & pxy_[node->getId()];
+  for(unsigned int c = 0; c < nbClasses_; c++)
+  {
+    VVdouble * pxy__node_c = & (* pxy__node)[c];
+    RowMatrix<double> Q = model->getPij_t(l * rateDistribution_->getCategory(c));
+    for(unsigned int x = 0; x < nbStates_; x++)
+    {
+      Vdouble * pxy__node_c_x = & (* pxy__node_c)[x];
+      for(unsigned int y = 0; y < nbStates_; y++)
+      {
+        (* pxy__node_c_x)[y] = Q(x, y);
+      }
+    }
+  }
+  
+  if(computeFirstOrderDerivatives_)
+  {
+    //Computes all dpxy/dt once for all:
+    VVVdouble * dpxy__node = & dpxy_[node->getId()];
+
+    for(unsigned int c = 0; c < nbClasses_; c++)
+    {
+      VVdouble * dpxy__node_c = & (* dpxy__node)[c];
+      double rc = rateDistribution_->getCategory(c);
+
+      RowMatrix<double> dQ = model->getdPij_dt(l * rc);  
+
+      for(unsigned int x = 0; x < nbStates_; x++)
+      {
+        Vdouble * dpxy__node_c_x = & (* dpxy__node_c)[x];
+        for(unsigned int y = 0; y < nbStates_; y++)
+          (* dpxy__node_c_x)[y] = rc * dQ(x, y); 
+      }
+    }
+  }
+      
+  if(computeSecondOrderDerivatives_)
+  {
+    //Computes all d2pxy/dt2 once for all:
+    VVVdouble * d2pxy__node = & d2pxy_[node->getId()];
+    for(unsigned int c = 0; c < nbClasses_; c++)
+    {
+      VVdouble * d2pxy__node_c = & (* d2pxy__node)[c];
+      double rc =  rateDistribution_->getCategory(c);
+      RowMatrix<double> d2Q = model->getd2Pij_dt2(l * rc);
+      for(unsigned int x = 0; x < nbStates_; x++)
+      {
+        Vdouble * d2pxy__node_c_x = & (* d2pxy__node_c)[x];
+        for(unsigned int y = 0; y < nbStates_; y++)
+        {
+          (* d2pxy__node_c_x)[y] = rc * rc * d2Q(x, y);
+        }
+      }
+    }
+  }
+}
+
+/*******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Likelihood/AbstractNonHomogeneousTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/AbstractNonHomogeneousTreeLikelihood.h
new file mode 100644
index 0000000..c233f1a
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/AbstractNonHomogeneousTreeLikelihood.h
@@ -0,0 +1,289 @@
+//
+// File: AbstractNonHomogeneousTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Tue Oct 09 16:07 2007
+// From file: AbstractHomogeneousTreeLikelihood.h
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _ABSTRACTNONHOMOGENEOUSTREELIKELIHOOD_H_
+#define _ABSTRACTNONHOMOGENEOUSTREELIKELIHOOD_H_
+
+#include "NonHomogeneousTreeLikelihood.h"
+#include "AbstractDiscreteRatesAcrossSitesTreeLikelihood.h"
+
+//From the STL:
+#include <memory>
+
+namespace bpp
+{
+
+/**
+ * @brief Partial implementation for branch non-homogeneous models of the TreeLikelihood interface.
+ *
+ * This class provides a pointer toward a single substitution model + several utilitary variables.
+ */
+class AbstractNonHomogeneousTreeLikelihood:
+  public virtual NonHomogeneousTreeLikelihood,
+  public AbstractDiscreteRatesAcrossSitesTreeLikelihood
+{
+  public:
+
+    class ConstNonHomogeneousSiteModelIterator :
+      public ConstSiteModelIterator
+    {
+      private:
+        std::vector<ConstNoPartitionSiteModelDescription> siteModelDescriptions_;
+        size_t index_;
+        size_t nbModels_;
+
+      public:
+        ConstNonHomogeneousSiteModelIterator(const SubstitutionModelSet* modelSet) :
+          siteModelDescriptions_(), index_(0), nbModels_(modelSet->getNumberOfModels())
+        {
+          for (size_t i = 0; i < nbModels_; ++i)
+            siteModelDescriptions_.push_back(ConstNoPartitionSiteModelDescription(modelSet->getModel(i), modelSet->getNodesWithModel(i)));        
+        }
+
+      public:
+        ConstSiteModelDescription* next() throw (Exception)
+        {
+          if (!hasNext())
+            throw Exception("AbstractNonHomogeneousTreeLikelihood::ConstHomogeneousSiteModelIterator::next(). No more site in the set.");
+          return &siteModelDescriptions_[index_++];
+        }
+
+        bool hasNext() const { return index_ < nbModels_; }
+    };
+
+  protected:
+    SubstitutionModelSet* modelSet_;
+    ParameterList brLenParameters_;
+    
+    mutable std::map<int, VVVdouble> pxy_;
+
+    mutable std::map<int, VVVdouble> dpxy_;
+
+    mutable std::map<int, VVVdouble> d2pxy_;
+        
+    std::vector<double> rootFreqs_;
+        
+    /**
+     * @brief Pointer toward all nodes in the tree.
+     *
+     * The position in the array is the number used in the parameter name.
+     * This may be different from the node id, unless you used the resetNodeId method on the input tree.
+     */
+    std::vector<Node*> nodes_;
+
+    /**
+     * @brief An index linking nodes to their id, for faster access than the getNode() method.
+     */
+    mutable std::map<int, const Node*> idToNode_;
+ 
+    //some values we'll need:
+    size_t nbSites_,         //the number of sites in the container
+                 nbDistinctSites_, //the number of distinct sites
+                 nbClasses_,       //the number of rate classes
+                 nbStates_,        //the number of states in the alphabet
+                 nbNodes_;         //the number of nodes in the tree
+
+    bool verbose_;
+
+    double minimumBrLen_;
+    double maximumBrLen_;
+    std::auto_ptr<Constraint> brLenConstraint_;
+
+    bool reparametrizeRoot_;
+    int root1_, root2_;
+
+  public:
+    AbstractNonHomogeneousTreeLikelihood(
+      const Tree& tree,
+      SubstitutionModelSet* modelSet,
+      DiscreteDistribution* rDist,
+      bool verbose = true,
+      bool reparametrizeRoot = true)
+      throw (Exception);
+
+    /**
+     * @brief Copy constructor
+     *
+     * This constructor is to be called by the derived class copy constructor.
+     */
+    AbstractNonHomogeneousTreeLikelihood(const AbstractNonHomogeneousTreeLikelihood& lik);
+    
+    /**
+     * @brief Assignation operator
+     *
+     * This operator is to be called by the derived class operator.
+     */
+    AbstractNonHomogeneousTreeLikelihood& operator=(const AbstractNonHomogeneousTreeLikelihood& lik);
+ 
+    virtual ~AbstractNonHomogeneousTreeLikelihood() {}
+    
+  private:
+
+    /**
+     * @brief Method called by constructor.
+     */
+    void init_(
+        const Tree& tree,
+        SubstitutionModelSet* modelSet,
+        DiscreteDistribution* rDist,
+        bool verbose) throw (Exception);
+
+  public:
+    
+    /**
+     * @name The TreeLikelihood interface.
+     *
+     * Other methods are implemented in the AbstractTreeLikelihood class.
+     *
+     * @{
+     */
+    void initialize() throw(Exception);
+    
+    ParameterList getBranchLengthsParameters() const;
+    
+    ParameterList getSubstitutionModelParameters() const;
+    
+    ParameterList getRateDistributionParameters() const
+    {
+      return AbstractDiscreteRatesAcrossSitesTreeLikelihood::getRateDistributionParameters();
+    }
+
+    const SubstitutionModel* getSubstitutionModelForNode(int nodeId) const throw (NodeNotFoundException) 
+    {
+      return modelSet_->getModelForNode(nodeId);
+    }
+
+    SubstitutionModel* getSubstitutionModelForNode(int nodeId) throw (NodeNotFoundException)
+    {
+      return modelSet_->getModelForNode(nodeId);
+    }
+
+    const std::vector<double>& getRootFrequencies(size_t siteIndex) const { return rootFreqs_; }
+    
+    VVVdouble getTransitionProbabilitiesPerRateClass(int nodeId, size_t siteIndex) const { return pxy_[nodeId]; }
+
+    ConstBranchModelIterator* getNewBranchModelIterator(int nodeId) const
+    {
+      return new ConstNoPartitionBranchModelIterator(modelSet_->getModelForNode(nodeId), nbDistinctSites_);
+    }
+
+    ConstSiteModelIterator* getNewSiteModelIterator(size_t siteIndex) const
+    {
+      return new ConstNonHomogeneousSiteModelIterator(modelSet_);
+    }
+       
+    /** @} */
+
+    /**
+     * @name The NonHomogeneousTreeLikelihood interface.
+     *
+     * Other methods are implemented in the AbstractTreeLikelihood class.
+     *
+     * @{
+     */
+    const SubstitutionModelSet* getSubstitutionModelSet() const { return modelSet_; }
+    
+    SubstitutionModelSet* getSubstitutionModelSet() { return modelSet_; }
+    
+    void setSubstitutionModelSet(SubstitutionModelSet* modelSet) throw (Exception);
+
+    ParameterList getRootFrequenciesParameters() const
+    {
+      return modelSet_->getRootFrequenciesParameters();
+    }
+    /** @} */
+    
+  public: //Specific methods:
+
+    /**
+     * @brief This builds the <i>parameters</i> list from all parametrizable objects,
+     * <i>i.e.</i> substitution model, rate distribution and tree.
+     */
+    virtual void initParameters();
+
+    /**
+     * @brief All parameters are stored in a parameter list.
+     * This function apply these parameters to the substitution model,
+     * to the rate distribution and to the branch lengths.
+     */
+    virtual void applyParameters() throw (Exception);  
+
+    virtual void initBranchLengthsParameters();
+
+    virtual void setMinimumBranchLength(double minimum) throw (Exception)
+    {
+      if (minimum > maximumBrLen_)
+        throw Exception("AbstractNonHomogeneousTreeLikelihood::setMinimumBranchLength. Minimum branch length sould be lower than the maximum one: " + TextTools::toString(maximumBrLen_));
+      minimumBrLen_ = minimum;
+      if (brLenConstraint_.get()) brLenConstraint_.release();
+      brLenConstraint_.reset(new IntervalConstraint(minimumBrLen_, maximumBrLen_, true, true));
+      initBranchLengthsParameters();
+    }
+
+    virtual void setMaximumBranchLength(double maximum) throw (Exception)
+    {
+      if (maximum < minimumBrLen_)
+        throw Exception("AbstractNonHomogeneousTreeLikelihood::setMaximumBranchLength. Maximum branch length sould be higher than the minimum one: " + TextTools::toString(minimumBrLen_));
+      maximumBrLen_ = maximum;
+      if (brLenConstraint_.get()) brLenConstraint_.release();
+      brLenConstraint_.reset(new IntervalConstraint(minimumBrLen_, maximumBrLen_, true, true));
+      initBranchLengthsParameters();
+    }
+
+    virtual double getMinimumBranchLength() const { return minimumBrLen_; }
+    virtual double getMaximumBranchLength() const { return maximumBrLen_; }
+
+
+  protected:
+    /**
+     * @brief Fill the pxy_, dpxy_ and d2pxy_ arrays for all nodes.
+     */
+    virtual void computeAllTransitionProbabilities();
+    /**
+     * @brief Fill the pxy_, dpxy_ and d2pxy_ arrays for one node.
+     */
+    virtual void computeTransitionProbabilitiesForNode(const Node * node);
+
+};
+
+} //end of namespace bpp.
+
+#endif //_ABSTRACTNONHOMOGENEOUSTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/AbstractTreeLikelihood.cpp b/src/Bpp/Phyl/Likelihood/AbstractTreeLikelihood.cpp
new file mode 100755
index 0000000..c965733
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/AbstractTreeLikelihood.cpp
@@ -0,0 +1,97 @@
+//
+// File: AbstractTreeLikelihood.cpp
+// Created by: Julien Dutheil
+// Created on: Fri Oct 17 17:57:21 2003
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "AbstractTreeLikelihood.h"
+
+using namespace bpp;
+
+/******************************************************************************/
+
+Vdouble AbstractTreeLikelihood::getLikelihoodForEachSite() const
+{
+	Vdouble l(getNumberOfSites());
+	for (size_t i = 0; i < l.size(); i++) l[i] = getLikelihoodForASite(i);
+	return l;
+}
+
+/******************************************************************************/
+
+Vdouble AbstractTreeLikelihood::getLogLikelihoodForEachSite() const
+{
+	Vdouble l(getNumberOfSites());
+	for (size_t i = 0; i < l.size(); i++) l[i] = getLogLikelihoodForASite(i);
+	return l;
+}
+
+/******************************************************************************/
+
+VVdouble AbstractTreeLikelihood::getLikelihoodForEachSiteForEachState() const
+{
+	VVdouble l(getNumberOfSites());
+	for (size_t i = 0; i < l.size(); i++)
+  {
+		Vdouble* l_i = & l[i];
+		l_i->resize(getNumberOfStates());
+		for (size_t x = 0; x < l_i->size(); x++)
+    {
+			(* l_i)[x] = getLikelihoodForASiteForAState(i, static_cast<int>(x));
+		}
+	}
+	return l;
+}
+
+/******************************************************************************/
+
+VVdouble AbstractTreeLikelihood::getLogLikelihoodForEachSiteForEachState() const
+{
+	VVdouble l(getNumberOfSites());
+	for (size_t i = 0; i < l.size(); i++)
+  {
+		Vdouble* l_i = & l[i];
+		l_i->resize(getNumberOfStates());
+		for (size_t x = 0; x < l_i->size(); x++)
+    {
+			(* l_i)[x] = getLogLikelihoodForASiteForAState(i, static_cast<int>(x));
+		}
+	}
+	return l;
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Likelihood/AbstractTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/AbstractTreeLikelihood.h
new file mode 100755
index 0000000..902f640
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/AbstractTreeLikelihood.h
@@ -0,0 +1,318 @@
+//
+// File: AbstractTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Fri Oct 17 17:57:21 2003
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _ABSTRACTTREELIKELIHOOD_H_
+#define _ABSTRACTTREELIKELIHOOD_H_
+
+#include "TreeLikelihood.h"
+#include "../Tree.h"
+#include "../TreeTemplate.h"
+
+#include <Bpp/Numeric/AbstractParametrizable.h>
+
+//From SeqLib:
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+namespace bpp
+{
+
+/**
+ * @brief Partial implementation of the TreeLikelihood interface. 
+ *
+ * This class implements a few methods useful for most of likelihood
+ * computation methods.
+ *
+ * It includes a tree_ and a data_ pointers.
+ * This objects are owned by the class, and hence hard copied when cloning, and destroyed by the destructor.
+ * 
+ * - The Parametrizable interface;
+ * - The getTree() method;
+ * 
+ * It also adds an abstract method for recursive computations.
+ */
+class AbstractTreeLikelihood :
+	public virtual TreeLikelihood,
+	public AbstractParametrizable
+{
+  public:
+    /**
+     * @brief A very simple branch iterator.
+     *
+     * The constructor takes a vector of nodes id to iterate over.
+     */
+    class SimpleBranchIterator :
+      public BranchIterator
+    {
+      private:
+        std::vector<int> nodesId_;
+        size_t index_;
+
+      public:
+        SimpleBranchIterator(const std::vector<int>& nodesId) :
+          nodesId_(nodesId), index_(0) {}
+
+      public:
+        int next() throw (Exception)
+        {
+          if (!hasNext())
+            throw Exception("AbstractTreeLikelihood::SimpleBranchIterator::next(). No more branch in the set.");
+          return nodesId_[index_++];
+        }
+
+        bool hasNext() const { return index_ < nodesId_.size(); }
+        
+    };
+
+    /**
+     * @brief A very simple site iterator.
+     *
+     * This iterator loops over a continuous range of sites.
+     * The ocnstructor takes as input the number of sites to iterate over,
+     * and optionally an offset argument, specifying the index of the first site.
+     */
+    class SimpleSiteIterator :
+      public SiteIterator
+    {
+      private:
+        size_t maxIndex_;
+        size_t index_;
+        size_t offset_;
+
+      public:
+        SimpleSiteIterator(size_t nbSites, size_t offset = 0) :
+          maxIndex_(nbSites), index_(0), offset_(offset) {}
+
+      public:
+        size_t next() throw (Exception)
+        {
+          if (!hasNext())
+            throw Exception("AbstractTreeLikelihood::SimpleSiteIterator::next(). No more site in the set.");
+          return offset_ + index_++;
+        }
+
+        bool hasNext() const { return index_ < maxIndex_; }
+        
+    };
+   
+    /**
+     * @name Branch iterator for models without site partition.
+     *
+     * @{
+     */
+    class ConstNoPartitionBranchModelDescription :
+      public ConstBranchModelDescription
+    {
+      private:
+        const SubstitutionModel* model_;
+        size_t nbSites_;
+
+      public:
+        ConstNoPartitionBranchModelDescription(const SubstitutionModel* model, size_t nbSites) :
+          model_(model), nbSites_(nbSites) {}
+
+        ConstNoPartitionBranchModelDescription(const ConstNoPartitionBranchModelDescription& bmd) :
+          model_(bmd.model_),
+          nbSites_(bmd.nbSites_)
+        {}
+
+        ConstNoPartitionBranchModelDescription& operator=(const ConstNoPartitionBranchModelDescription& bmd)
+        {
+          model_ = bmd.model_;
+          nbSites_ = bmd.nbSites_;
+          return *this;
+        }
+
+      public:
+        const SubstitutionModel* getModel() const { return model_; }
+        
+        SiteIterator* getNewSiteIterator() const { return new SimpleSiteIterator(nbSites_); }
+    };
+
+    class ConstNoPartitionBranchModelIterator :
+      public ConstBranchModelIterator
+    {
+      private:
+        ConstNoPartitionBranchModelDescription branchModelDescription_;
+        size_t index_;
+
+      public:
+        ConstNoPartitionBranchModelIterator(const SubstitutionModel* model, size_t nbSites) :
+          branchModelDescription_(model, nbSites), index_(0) {}
+
+      public:
+        ConstNoPartitionBranchModelDescription* next() throw (Exception)
+        {
+          if (!hasNext())
+            throw Exception("AbstractHomogeneousTreeLikelihood::ConstHomogeneousBranchModelIterator::next(). No more branch in the set.");
+          index_++;
+          return &branchModelDescription_;
+        }
+
+        bool hasNext() const { return index_ == 0; }
+    };
+ 
+    class ConstNoPartitionSiteModelDescription :
+      public ConstSiteModelDescription
+    {
+      private:
+        const SubstitutionModel* model_;
+        std::vector<int> nodesId_;
+
+      public:
+        ConstNoPartitionSiteModelDescription(const SubstitutionModel* model, const std::vector<int> nodesId) :
+          model_(model), nodesId_(nodesId) {}
+
+        ConstNoPartitionSiteModelDescription(const ConstNoPartitionSiteModelDescription& smd) :
+          model_(smd.model_),
+          nodesId_(smd.nodesId_)
+        {}
+
+        ConstNoPartitionSiteModelDescription& operator=(const ConstNoPartitionSiteModelDescription& smd)
+        {
+          model_ = smd.model_;
+          nodesId_ = smd.nodesId_;
+          return *this;
+        }
+
+      public:
+        const SubstitutionModel* getModel() const { return model_; }
+        
+        BranchIterator* getNewBranchIterator() const { return new SimpleBranchIterator(nodesId_); }
+    };
+
+   /** @} */
+
+
+
+
+	protected:
+		const SiteContainer* data_;
+		mutable TreeTemplate<Node>* tree_;
+		bool computeFirstOrderDerivatives_;
+		bool computeSecondOrderDerivatives_;
+    bool initialized_;
+
+	public:
+		AbstractTreeLikelihood():
+      AbstractParametrizable(""),
+      data_(0),
+      tree_(0),
+      computeFirstOrderDerivatives_(true),
+      computeSecondOrderDerivatives_(true),
+      initialized_(false) {}
+
+    AbstractTreeLikelihood(const AbstractTreeLikelihood & lik):
+      AbstractParametrizable(lik),
+      data_(0),
+      tree_(0),
+      computeFirstOrderDerivatives_(lik.computeFirstOrderDerivatives_),
+      computeSecondOrderDerivatives_(lik.computeSecondOrderDerivatives_),
+      initialized_(lik.initialized_) 
+    {
+      if (lik.data_) data_ = dynamic_cast<SiteContainer*>(lik.data_->clone());
+      if (lik.tree_) tree_ = lik.tree_->clone();
+    }
+
+    AbstractTreeLikelihood & operator=(const AbstractTreeLikelihood& lik)
+    {
+      AbstractParametrizable::operator=(lik);
+      if (data_) delete data_;
+      if (lik.data_) data_ = dynamic_cast<SiteContainer*>(lik.data_->clone());
+      else           data_ = 0;
+      if (tree_) delete tree_;
+      if (lik.tree_) tree_ = lik.tree_->clone();
+      else           tree_ = 0;
+      computeFirstOrderDerivatives_ = lik.computeFirstOrderDerivatives_;
+      computeSecondOrderDerivatives_ = lik.computeSecondOrderDerivatives_;
+      initialized_ = lik.initialized_;
+      return *this;
+    }
+
+    /**
+     * @brief Abstract class destructor
+     *
+     * This destructor is empty.
+     */
+		virtual ~AbstractTreeLikelihood()
+    {
+      if (data_) delete data_;
+      if (tree_) delete tree_;
+    }
+	
+	public:
+		/**
+		 * @name The TreeLikelihood interface.
+		 *
+		 * @{
+		 */
+		const SiteContainer* getData() const { return data_; }
+		const Alphabet* getAlphabet() const { return data_->getAlphabet(); }	
+		Vdouble getLikelihoodForEachSite()                 const;
+		Vdouble getLogLikelihoodForEachSite()              const;
+		VVdouble getLikelihoodForEachSiteForEachState()    const;
+		VVdouble getLogLikelihoodForEachSiteForEachState() const;
+		size_t getNumberOfSites() const { return data_->getNumberOfSites(); }
+		size_t getNumberOfStates() const { return data_->getAlphabet()->getSize(); }
+		const Tree& getTree() const { return *tree_; }
+		void enableDerivatives(bool yn) { computeFirstOrderDerivatives_ = computeSecondOrderDerivatives_ = yn; }
+		void enableFirstOrderDerivatives(bool yn) { computeFirstOrderDerivatives_ = yn; }
+		void enableSecondOrderDerivatives(bool yn) { computeFirstOrderDerivatives_ = computeSecondOrderDerivatives_ = yn; }
+		bool enableFirstOrderDerivatives() const { return computeFirstOrderDerivatives_; }
+		bool enableSecondOrderDerivatives() const { return computeSecondOrderDerivatives_; }
+    bool isInitialized() const { return initialized_; }
+    void initialize() throw (Exception) { initialized_ = true; }
+		/** @} */
+
+//	protected:
+//		
+//		/**
+//		 * @brief Recompute pxy_, dpxy_ and d2pxy_ arrays, and derivatives if needed.
+//		 *
+//		 * This method is called when some parameter has changed.
+//		 *
+//		 * @param params The parameters that changed.
+//		 */
+//		virtual void fireParameterChanged(const ParameterList & params) = 0;
+		
+};
+
+} //end of namespace bpp.
+
+#endif	//_ABSTRACTTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/AbstractTreeLikelihoodData.h b/src/Bpp/Phyl/Likelihood/AbstractTreeLikelihoodData.h
new file mode 100644
index 0000000..42be3e9
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/AbstractTreeLikelihoodData.h
@@ -0,0 +1,145 @@
+//
+// File: AbstractTreeLikelihoodData.h
+// Created by: Julien Dutheil
+// Created on: Sat Dec 30 12:48 2006
+// From file AbstractTreeLikelihood.h
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _ABSTRACTTREELIKELIHOODDATA_H_
+#define _ABSTRACTTREELIKELIHOODDATA_H_
+
+#include "TreeLikelihoodData.h"
+
+//From the STL:
+#include <vector>
+#include <map>
+
+namespace bpp
+{
+
+/**
+ * @brief Partial implementation of the TreeLikelihoodData interface.
+ *
+ * This data structure provides a simple compression, by performing and storing computations
+ * only one time per identical sites.
+ *
+ * The compression is achieved by the TreeLikelihood object.
+ * The correspondance between sites in the dataset and the arrays in the structures is given
+ * by the rootPatternLinks_ array: the array indice for site @f$i at f$ if given by:
+ * @code
+ * rootPatternLinks_[i]
+ * @endcode
+ *
+ * Finally, the rootWeights_ array gives for each array position, the number of sites with this
+ * pattern.
+ * The global likelihood is then given by the product of all likelihoods for each array position,
+ * weighted by the corresponding number of sites.
+ */
+class AbstractTreeLikelihoodData :
+	public TreeLikelihoodData
+{
+	protected:
+		/**
+		 * @brief Links between sites and patterns.
+		 * 
+		 * The size of this vector is equal to the number of sites in the container,
+		 * each element corresponds to a site in the container and points to the
+		 * corresponding column in the likelihood array of the root node.
+		 * If the container contains no repeated site, there will be a strict
+		 * equivalence between each site and the likelihood array of the root node.
+		 * However, if this is not the case, some pointers may point toward the same
+		 * element in the likelihood array.
+		 */
+    std::vector<size_t> rootPatternLinks_;
+
+		/**
+		 * @brief The frequency of each site.
+		 */
+    std::vector<unsigned int> rootWeights_;
+
+		const TreeTemplate<Node>* tree_;
+
+		const Alphabet* alphabet_;
+
+  public:
+		AbstractTreeLikelihoodData(const TreeTemplate<Node>* tree):
+      rootPatternLinks_(), rootWeights_(), tree_(tree), alphabet_(0) {}
+
+		AbstractTreeLikelihoodData(const AbstractTreeLikelihoodData& atd) :
+      rootPatternLinks_(atd.rootPatternLinks_),
+      rootWeights_(atd.rootWeights_),
+      tree_(atd.tree_),
+      alphabet_(atd.alphabet_)
+    {}
+
+    AbstractTreeLikelihoodData& operator=(const AbstractTreeLikelihoodData& atd)
+    {
+      rootPatternLinks_ = atd.rootPatternLinks_;
+      rootWeights_      = atd.rootWeights_;
+      tree_             = atd.tree_;
+      alphabet_         = atd.alphabet_;
+      return *this;
+    }
+
+
+		virtual ~AbstractTreeLikelihoodData() {}
+
+	public:
+    std::vector<size_t>& getRootArrayPositions() { return rootPatternLinks_; }
+		const std::vector<size_t>& getRootArrayPositions() const { return rootPatternLinks_; }
+		size_t getRootArrayPosition(const size_t site) const
+		{
+			return rootPatternLinks_[site];
+		}
+		unsigned int getWeight(size_t pos) const
+		{
+			return rootWeights_[pos];
+		}
+		const std::vector<unsigned int>& getWeights() const
+		{ 
+			return rootWeights_;
+		}
+
+		const Alphabet* getAlphabet() const { return alphabet_; }
+
+		const TreeTemplate<Node>* getTree() const { return tree_; }  
+
+};
+
+} //end of namespace bpp.
+
+#endif //_ABSTRACTTREELIKELIHOODDATA_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/ClockTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/ClockTreeLikelihood.h
new file mode 100644
index 0000000..3c16ad4
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/ClockTreeLikelihood.h
@@ -0,0 +1,90 @@
+//
+// File: ClockTreeLikelihood.h
+// Created by: Benoît Nabholz
+//             Julien Dutheil
+// Created on: Fri Apr 06 14:11 2007
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _CLOCKTREELIKELIHOOD_H_
+#define _CLOCKTREELIKELIHOOD_H_
+
+#include "TreeLikelihood.h"
+#include "DiscreteRatesAcrossSitesTreeLikelihood.h"
+#include "../TreeTemplate.h"
+
+#include <Bpp/Numeric/ParameterList.h>
+
+namespace bpp
+{
+
+/**
+ * @brief Interface for likelihood computation with a global clock.
+ *
+ * @deprecated See GlobalClockTreeLikelihoodFunctionWrapper as a more general replacement.
+ */
+class ClockTreeLikelihood:
+  public virtual TreeLikelihood
+{
+  public:
+#ifndef NO_VIRTUAL_COV
+    ClockTreeLikelihood * clone() const = 0;
+#endif
+
+    virtual ~ClockTreeLikelihood() {}
+};
+
+/**
+ * @brief Interface for likelihood computation with a global clock and rate across sites variation.
+ *
+ * @deprecated See GlobalClockTreeLikelihoodFunctionWrapper as a more general replacement.
+ */
+class DiscreteRatesAcrossSitesClockTreeLikelihood:
+  public virtual ClockTreeLikelihood,
+  public virtual DiscreteRatesAcrossSitesTreeLikelihood
+{
+  public:
+#ifndef NO_VIRTUAL_COV
+    DiscreteRatesAcrossSitesClockTreeLikelihood * clone() const = 0;
+#endif
+
+    virtual ~DiscreteRatesAcrossSitesClockTreeLikelihood() {}
+
+};
+
+} //end of namespace bpp.
+
+#endif // _CLOCKTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/DRASDRTreeLikelihoodData.cpp b/src/Bpp/Phyl/Likelihood/DRASDRTreeLikelihoodData.cpp
new file mode 100644
index 0000000..91bebad
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DRASDRTreeLikelihoodData.cpp
@@ -0,0 +1,263 @@
+//
+// File: DRASDRTreeLikelihoodData.cpp
+// Created by: Julien Dutheil
+// Created on: Sat Dec 30 14:20 2006
+// From file DRHomogeneousTreeLikelihood.cpp
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "DRASDRTreeLikelihoodData.h"
+#include "../PatternTools.h"
+
+// From SeqLib:
+#include <Bpp/Seq/SiteTools.h>
+
+using namespace bpp;
+
+/******************************************************************************/
+
+void DRASDRTreeLikelihoodData::initLikelihoods(const SiteContainer& sites, const SubstitutionModel& model) throw (Exception)
+{
+  if (sites.getNumberOfSequences() == 1)
+    throw Exception("Error, only 1 sequence!");
+  if (sites.getNumberOfSequences() == 0)
+    throw Exception("Error, no sequence!");
+  if (sites.getAlphabet()->getAlphabetType()
+      != model.getAlphabet()->getAlphabetType())
+    throw AlphabetMismatchException("DRASDRTreeLikelihoodData::initLikelihoods. Data and model must have the same alphabet type.",
+                                    sites.getAlphabet(),
+                                    model.getAlphabet());
+  alphabet_ = sites.getAlphabet();
+  nbStates_ = model.getNumberOfStates();
+  nbSites_  = sites.getNumberOfSites();
+
+  SitePatterns pattern(&sites);
+  if (shrunkData_)
+    delete shrunkData_;
+  shrunkData_       = pattern.getSites();
+  rootWeights_      = pattern.getWeights();
+  rootPatternLinks_ = pattern.getIndices();
+  nbDistinctSites_  = shrunkData_->getNumberOfSites();
+
+  // Init data:
+  // Clone data for more efficiency on sequences access:
+  const SiteContainer* sequences = new AlignedSequenceContainer(*shrunkData_);
+  initLikelihoods(tree_->getRootNode(), *sequences, model);
+  delete sequences;
+
+  // Now initialize root likelihoods and derivatives:
+  rootLikelihoods_.resize(nbDistinctSites_);
+  rootLikelihoodsS_.resize(nbDistinctSites_);
+  rootLikelihoodsSR_.resize(nbDistinctSites_);
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    VVdouble* rootLikelihoods_i_ = &rootLikelihoods_[i];
+    Vdouble* rootLikelihoodsS_i_ = &rootLikelihoodsS_[i];
+    rootLikelihoods_i_->resize(nbClasses_);
+    rootLikelihoodsS_i_->resize(nbClasses_);
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* rootLikelihoods_i_c_ = &(*rootLikelihoods_i_)[c];
+      rootLikelihoods_i_c_->resize(nbStates_);
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        (*rootLikelihoods_i_c_)[x] = 1.;
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+void DRASDRTreeLikelihoodData::initLikelihoods(const Node* node, const SiteContainer& sites, const SubstitutionModel& model) throw (Exception)
+{
+  if (node->isLeaf())
+  {
+    // Init leaves likelihoods:
+    const Sequence* seq;
+    try
+    {
+      seq = &sites.getSequence(node->getName());
+    }
+    catch (SequenceNotFoundException& snfe)
+    {
+      throw SequenceNotFoundException("DRASDRTreeLikelihoodData::initlikelihoods. Leaf name in tree not found in site container: ", (node->getName()));
+    }
+    DRASDRTreeLikelihoodLeafData* leafData = &leafData_[node->getId()];
+    VVdouble* leavesLikelihoods_leaf = &leafData->getLikelihoodArray();
+    leafData->setNode(node);
+    leavesLikelihoods_leaf->resize(nbDistinctSites_);
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      Vdouble* leavesLikelihoods_leaf_i = &(*leavesLikelihoods_leaf)[i];
+      leavesLikelihoods_leaf_i->resize(nbStates_);
+      int state = seq->getValue(i);
+      double test = 0.;
+      for (size_t s = 0; s < nbStates_; s++)
+      {
+        // Leaves likelihood are set to 1 if the char correspond to the site in the sequence,
+        // otherwise value set to 0:
+        ( *leavesLikelihoods_leaf_i)[s] = model.getInitValue(s, state);
+        test += ( *leavesLikelihoods_leaf_i)[s];
+      }
+      if (test < 0.000001)
+        std::cerr << "WARNING!!! Likelihood will be 0 for this site." << std::endl;
+    }
+  }
+
+  // We initialize each son node first:
+  size_t nbSonNodes = node->getNumberOfSons();
+  for (size_t l = 0; l < nbSonNodes; l++)
+  {
+    // For each son node,
+    initLikelihoods(node->getSon(l), sites, model);
+  }
+
+  // Initialize likelihood vector:
+  DRASDRTreeLikelihoodNodeData* nodeData = &nodeData_[node->getId()];
+  std::map<int, VVVdouble>* likelihoods_node_ = &nodeData->getLikelihoodArrays();
+  nodeData->setNode(node);
+
+  int nbSons = static_cast<int>(node->getNumberOfSons());
+
+  for (int n = (node->hasFather() ? -1 : 0); n < nbSons; n++)
+  {
+    const Node* neighbor = (*node)[n];
+    VVVdouble* likelihoods_node_neighbor_ = &(*likelihoods_node_)[neighbor->getId()];
+
+    likelihoods_node_neighbor_->resize(nbDistinctSites_);
+
+    if (neighbor->isLeaf())
+    {
+      VVdouble* leavesLikelihoods_leaf_ = &leafData_[neighbor->getId()].getLikelihoodArray();
+      for (size_t i = 0; i < nbDistinctSites_; i++)
+      {
+        Vdouble* leavesLikelihoods_leaf_i_ = &(*leavesLikelihoods_leaf_)[i];
+        VVdouble* likelihoods_node_neighbor_i_ = &(*likelihoods_node_neighbor_)[i];
+        likelihoods_node_neighbor_i_->resize(nbClasses_);
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* likelihoods_node_neighbor_i_c_ = &(*likelihoods_node_neighbor_i_)[c];
+          likelihoods_node_neighbor_i_c_->resize(nbStates_);
+          for (size_t s = 0; s < nbStates_; s++)
+          {
+            (*likelihoods_node_neighbor_i_c_)[s] = (*leavesLikelihoods_leaf_i_)[s];
+          }
+        }
+      }
+    }
+    else
+    {
+      for (size_t i = 0; i < nbDistinctSites_; i++)
+      {
+        VVdouble* likelihoods_node_neighbor_i_ = &(*likelihoods_node_neighbor_)[i];
+        likelihoods_node_neighbor_i_->resize(nbClasses_);
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* likelihoods_node_neighbor_i_c_ = &(*likelihoods_node_neighbor_i_)[c];
+          likelihoods_node_neighbor_i_c_->resize(nbStates_);
+          for (size_t s = 0; s < nbStates_; s++)
+          {
+            (*likelihoods_node_neighbor_i_c_)[s] = 1.; // All likelihoods are initialized to 1.
+          }
+        }
+      }
+    }
+  }
+
+  // Initialize d and d2 likelihoods:
+  Vdouble* dLikelihoods_node_ = &nodeData->getDLikelihoodArray();
+  Vdouble* d2Likelihoods_node_ = &nodeData->getD2LikelihoodArray();
+  dLikelihoods_node_->resize(nbDistinctSites_);
+  d2Likelihoods_node_->resize(nbDistinctSites_);
+}
+
+/******************************************************************************/
+
+void DRASDRTreeLikelihoodData::reInit() throw (Exception)
+{
+  reInit(tree_->getRootNode());
+}
+
+void DRASDRTreeLikelihoodData::reInit(const Node* node) throw (Exception)
+{
+  if (node->isLeaf())
+  {
+    DRASDRTreeLikelihoodLeafData* leafData = &leafData_[node->getId()];
+    leafData->setNode(node);
+  }
+
+  DRASDRTreeLikelihoodNodeData* nodeData = &nodeData_[node->getId()];
+  nodeData->setNode(node);
+  nodeData->eraseNeighborArrays();
+
+  int nbSons = static_cast<int>(node->getNumberOfSons());
+
+  for (int n = (node->hasFather() ? -1 : 0); n < nbSons; n++)
+  {
+    const Node* neighbor = (*node)[n];
+    VVVdouble* array = &nodeData->getLikelihoodArrayForNeighbor(neighbor->getId());
+
+    array->resize(nbDistinctSites_);
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* array_i = &(*array)[i];
+      array_i->resize(nbClasses_);
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* array_i_c = &(*array_i)[c];
+        array_i_c->resize(nbStates_);
+        for (size_t s = 0; s < nbStates_; s++)
+        {
+          (*array_i_c)[s] = 1.; // All likelihoods are initialized to 1.
+        }
+      }
+    }
+  }
+
+  // We re-initialize each son node:
+  size_t nbSonNodes = node->getNumberOfSons();
+  for (size_t l = 0; l < nbSonNodes; l++)
+  {
+    // For each son node,
+    reInit(node->getSon(l));
+  }
+
+  nodeData->getDLikelihoodArray().resize(nbDistinctSites_);
+  nodeData->getD2LikelihoodArray().resize(nbDistinctSites_);
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Likelihood/DRASDRTreeLikelihoodData.h b/src/Bpp/Phyl/Likelihood/DRASDRTreeLikelihoodData.h
new file mode 100644
index 0000000..bb70f22
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DRASDRTreeLikelihoodData.h
@@ -0,0 +1,454 @@
+//
+// File: DRASDRTreeLikelihoodData.h
+// Created by: Julien Dutheil
+// Created on: Sat Dec 30 14:20 2006
+// From file DRHomogeneousTreeLikelihood.h
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _DRASDRHOMOGENEOUSTREELIKELIHOODDATA_H_
+#define _DRASDRHOMOGENEOUSTREELIKELIHOODDATA_H_
+
+#include "AbstractTreeLikelihoodData.h"
+#include "../Model/SubstitutionModel.h"
+#include "../PatternTools.h"
+#include "../SitePatterns.h"
+
+//From SeqLib:
+#include <Bpp/Seq/Container/AlignedSequenceContainer.h>
+
+// From the STL:
+#include <map>
+
+namespace bpp
+{
+
+/**
+ * @brief Likelihood data structure for a leaf.
+ * 
+ * This class is for use with the DRASDRTreeLikelihoodData class.
+ * 
+ * Store the likelihoods arrays associated to a leaf.
+ * 
+ * @see DRASDRTreeLikelihoodData
+ */
+class DRASDRTreeLikelihoodLeafData :
+  public virtual TreeLikelihoodNodeData
+{
+  private:
+    mutable VVdouble leafLikelihood_;
+    const Node* leaf_;
+
+  public:
+    DRASDRTreeLikelihoodLeafData() : leafLikelihood_(), leaf_(0) {}
+
+    DRASDRTreeLikelihoodLeafData(const DRASDRTreeLikelihoodLeafData& data) :
+      leafLikelihood_(data.leafLikelihood_), leaf_(data.leaf_) {}
+    
+    DRASDRTreeLikelihoodLeafData& operator=(const DRASDRTreeLikelihoodLeafData& data)
+    {
+      leafLikelihood_ = data.leafLikelihood_;
+      leaf_           = data.leaf_;
+      return *this;
+    }
+
+#ifndef NO_VIRTUAL_COV
+    DRASDRTreeLikelihoodLeafData*
+#else
+    Clonable*
+#endif
+    clone() const
+    { 
+      return new DRASDRTreeLikelihoodLeafData(*this);
+    }
+
+  public:
+    const Node* getNode() const { return leaf_; }
+    void setNode(const Node* node) { leaf_ = node; }
+
+    VVdouble& getLikelihoodArray()  { return leafLikelihood_;  }
+};
+
+/**
+ * @brief Likelihood data structure for a node.
+ * 
+ * This class is for use with the DRASDRTreeLikelihoodData class.
+ * 
+ * Store for each neighbor node an array with conditionnal likelihoods.
+ *
+ * @see DRASDRTreeLikelihoodData
+ */
+class DRASDRTreeLikelihoodNodeData :
+  public virtual TreeLikelihoodNodeData
+{
+  private:
+    /**
+     * @brief This contains all likelihood values used for computation.
+     *
+     * <pre>
+     * x[b][i][c][s]
+     *   |------------> Neighbor node of n (id)
+      *     |---------> Site i
+     *         |------> Rate class c
+     *            |---> Ancestral state s
+     * </pre>
+     * We call this the <i>likelihood array</i> for each node.
+     */
+
+    mutable std::map<int, VVVdouble> nodeLikelihoods_;
+    /**
+     * @brief This contains all likelihood first order derivatives values used for computation.
+     *
+     * <pre>
+     * x[i]
+     *   |---------> Site i
+     * </pre> 
+     * We call this the <i>dLikelihood array</i> for each node.
+     */
+    mutable Vdouble nodeDLikelihoods_;
+  
+    /**
+     * @brief This contains all likelihood second order derivatives values used for computation.
+     *
+     * <pre>
+     * x[i]
+         |---------> Site i
+     * </pre> 
+     * We call this the <i>d2Likelihood array</i> for each node.
+     */
+    mutable Vdouble nodeD2Likelihoods_;
+    
+    const Node* node_;
+
+  public:
+    DRASDRTreeLikelihoodNodeData() : nodeLikelihoods_(), nodeDLikelihoods_(), nodeD2Likelihoods_(), node_(0) {}
+    
+    DRASDRTreeLikelihoodNodeData(const DRASDRTreeLikelihoodNodeData& data) :
+      nodeLikelihoods_(data.nodeLikelihoods_),
+      nodeDLikelihoods_(data.nodeDLikelihoods_),
+      nodeD2Likelihoods_(data.nodeD2Likelihoods_),
+      node_(data.node_)
+    {}
+    
+    DRASDRTreeLikelihoodNodeData& operator=(const DRASDRTreeLikelihoodNodeData& data)
+    {
+      nodeLikelihoods_   = data.nodeLikelihoods_;
+      nodeDLikelihoods_  = data.nodeDLikelihoods_;
+      nodeD2Likelihoods_ = data.nodeD2Likelihoods_;
+      node_              = data.node_;
+      return *this;
+    }
+ 
+    virtual ~DRASDRTreeLikelihoodNodeData() {}
+
+#ifndef NO_VIRTUAL_COV
+    DRASDRTreeLikelihoodNodeData*
+#else 
+    Clonable*
+#endif
+    clone() const
+    { 
+      return new DRASDRTreeLikelihoodNodeData(*this);
+    }
+
+  public:
+    const Node* getNode() const { return node_; }
+    
+    void setNode(const Node* node) { node_ = node; }
+
+    const std::map<int, VVVdouble>& getLikelihoodArrays() const { return nodeLikelihoods_; }
+    
+    std::map<int, VVVdouble>& getLikelihoodArrays() { return nodeLikelihoods_; }
+    
+    VVVdouble& getLikelihoodArrayForNeighbor(int neighborId)
+    {
+      return nodeLikelihoods_[neighborId];
+    }
+    
+    const VVVdouble& getLikelihoodArrayForNeighbor(int neighborId) const
+    {
+      return nodeLikelihoods_[neighborId];
+    }
+    
+    Vdouble& getDLikelihoodArray() { return nodeDLikelihoods_;  }
+    
+    const Vdouble& getDLikelihoodArray() const  {  return nodeDLikelihoods_;  }
+    
+    Vdouble& getD2LikelihoodArray()  {  return nodeD2Likelihoods_; }
+    
+    const Vdouble& getD2LikelihoodArrayForNeighbor() const  { return nodeD2Likelihoods_; }
+
+    bool isNeighbor(int neighborId) const
+    {
+      return nodeLikelihoods_.find(neighborId) != nodeLikelihoods_.end();
+    }
+
+    void eraseNeighborArrays()
+    {
+      nodeLikelihoods_.erase(nodeLikelihoods_.begin(), nodeLikelihoods_.end());
+      nodeDLikelihoods_.erase(nodeDLikelihoods_.begin(), nodeDLikelihoods_.end());
+      nodeD2Likelihoods_.erase(nodeD2Likelihoods_.begin(), nodeD2Likelihoods_.end());
+    }
+};
+
+/**
+ * @brief Likelihood data structure for rate across sites models, using a double-recursive algorithm.
+ */
+class DRASDRTreeLikelihoodData :
+  public virtual AbstractTreeLikelihoodData
+{
+  private:
+
+    mutable std::map<int, DRASDRTreeLikelihoodNodeData> nodeData_;
+    mutable std::map<int, DRASDRTreeLikelihoodLeafData> leafData_;
+    mutable VVVdouble rootLikelihoods_;
+    mutable VVdouble  rootLikelihoodsS_;
+    mutable Vdouble   rootLikelihoodsSR_;
+
+    SiteContainer* shrunkData_;
+    size_t nbSites_; 
+    size_t nbStates_;
+    size_t nbClasses_;
+    size_t nbDistinctSites_; 
+
+  public:
+    DRASDRTreeLikelihoodData(const TreeTemplate<Node>* tree, size_t nbClasses) :
+      AbstractTreeLikelihoodData(tree),
+      nodeData_(), leafData_(), rootLikelihoods_(), rootLikelihoodsS_(), rootLikelihoodsSR_(),
+      shrunkData_(0), nbSites_(0), nbStates_(0), nbClasses_(nbClasses), nbDistinctSites_(0)
+    {}
+
+    DRASDRTreeLikelihoodData(const DRASDRTreeLikelihoodData& data):
+      AbstractTreeLikelihoodData(data),
+      nodeData_(data.nodeData_), leafData_(data.leafData_),
+      rootLikelihoods_(data.rootLikelihoods_),
+      rootLikelihoodsS_(data.rootLikelihoodsS_),
+      rootLikelihoodsSR_(data.rootLikelihoodsSR_),
+      shrunkData_(0),
+      nbSites_(data.nbSites_), nbStates_(data.nbStates_),
+      nbClasses_(data.nbClasses_), nbDistinctSites_(data.nbDistinctSites_)
+    {
+      if (data.shrunkData_)
+        shrunkData_ = dynamic_cast<SiteContainer*>(data.shrunkData_->clone());
+    }
+
+    DRASDRTreeLikelihoodData& operator=(const DRASDRTreeLikelihoodData& data)
+    {
+      AbstractTreeLikelihoodData::operator=(data);
+      nodeData_          = data.nodeData_;
+      leafData_          = data.leafData_;
+      rootLikelihoods_   = data.rootLikelihoods_;
+      rootLikelihoodsS_  = data.rootLikelihoodsS_;
+      rootLikelihoodsSR_ = data.rootLikelihoodsSR_;
+      nbSites_           = data.nbSites_;
+      nbStates_          = data.nbStates_;
+      nbClasses_         = data.nbClasses_;
+      nbDistinctSites_   = data.nbDistinctSites_;
+      if (shrunkData_) delete shrunkData_;
+      if (data.shrunkData_)
+        shrunkData_      = dynamic_cast<SiteContainer *>(data.shrunkData_->clone());
+      else
+        shrunkData_      = 0;
+      return *this;
+    }
+
+    virtual ~DRASDRTreeLikelihoodData() { delete shrunkData_; }
+
+    DRASDRTreeLikelihoodData* clone() const { return new DRASDRTreeLikelihoodData(*this); }
+
+  public:
+    /**
+     * @brief Set the tree associated to the data.
+     *
+     * All node data will be actualized accordingly by calling the setNode() method on the corresponding nodes.
+     * @warning: the old tree and the new tree must be two clones! And particularly, they have to share the
+     * same topology and nodes id.
+     *
+     * @param tree The tree to be associated to this data.
+     */
+    void setTree(const TreeTemplate<Node>* tree)
+    { 
+      tree_ = tree;
+      for (std::map<int, DRASDRTreeLikelihoodNodeData>::iterator it = nodeData_.begin(); it != nodeData_.end(); it++)
+      {
+        int id = it->second.getNode()->getId();
+        it->second.setNode(tree_->getNode(id));
+      }
+      for (std::map<int, DRASDRTreeLikelihoodLeafData>::iterator it = leafData_.begin(); it != leafData_.end(); it++)
+      {
+        int id = it->second.getNode()->getId();
+        it->second.setNode(tree_->getNode(id));
+      }
+    }
+
+    DRASDRTreeLikelihoodNodeData& getNodeData(int nodeId)
+    { 
+      return nodeData_[nodeId];
+    }
+    
+    const DRASDRTreeLikelihoodNodeData& getNodeData(int nodeId) const
+    { 
+      return nodeData_[nodeId];
+    }
+    
+    DRASDRTreeLikelihoodLeafData& getLeafData(int nodeId)
+    { 
+      return leafData_[nodeId];
+    }
+    
+    const DRASDRTreeLikelihoodLeafData& getLeafData(int nodeId) const
+    { 
+      return leafData_[nodeId];
+    }
+    
+    size_t getArrayPosition(int parentId, int sonId, size_t currentPosition) const
+    {
+      return currentPosition;
+    }
+
+    const std::map<int, VVVdouble>& getLikelihoodArrays(int nodeId) const 
+    {
+      return nodeData_[nodeId].getLikelihoodArrays();
+    }
+    
+    std::map<int, VVVdouble>& getLikelihoodArrays(int nodeId)
+    {
+      return nodeData_[nodeId].getLikelihoodArrays();
+    }
+
+    VVVdouble& getLikelihoodArray(int parentId, int neighborId)
+    {
+      return nodeData_[parentId].getLikelihoodArrayForNeighbor(neighborId);
+    }
+    
+    const VVVdouble& getLikelihoodArray(int parentId, int neighborId) const
+    {
+      return nodeData_[parentId].getLikelihoodArrayForNeighbor(neighborId);
+    }
+    
+    Vdouble& getDLikelihoodArray(int nodeId)
+    {
+      return nodeData_[nodeId].getDLikelihoodArray();
+    }
+    
+    const Vdouble& getDLikelihoodArray(int nodeId) const
+    {
+      return nodeData_[nodeId].getDLikelihoodArray();
+    }
+    
+    Vdouble& getD2LikelihoodArray(int nodeId)
+    {
+      return nodeData_[nodeId].getD2LikelihoodArray();
+    }
+
+    const Vdouble& getD2LikelihoodArray(int nodeId) const
+    {
+      return nodeData_[nodeId].getD2LikelihoodArray();
+    }
+
+    VVdouble& getLeafLikelihoods(int nodeId)
+    {
+      return leafData_[nodeId].getLikelihoodArray();
+    }
+    
+    const VVdouble& getLeafLikelihoods(int nodeId) const
+    {
+      return leafData_[nodeId].getLikelihoodArray();
+    }
+    
+    VVVdouble& getRootLikelihoodArray() { return rootLikelihoods_; }
+    const VVVdouble & getRootLikelihoodArray() const { return rootLikelihoods_; }
+    
+    VVdouble& getRootSiteLikelihoodArray() { return rootLikelihoodsS_; }
+    const VVdouble& getRootSiteLikelihoodArray() const { return rootLikelihoodsS_; }
+    
+    Vdouble& getRootRateSiteLikelihoodArray() { return rootLikelihoodsSR_; }
+    const Vdouble& getRootRateSiteLikelihoodArray() const { return rootLikelihoodsSR_; }
+
+    size_t getNumberOfDistinctSites() const { return nbDistinctSites_; }
+    
+    size_t getNumberOfSites() const { return nbSites_; }
+    
+    size_t getNumberOfStates() const { return nbStates_; }
+    
+    size_t getNumberOfClasses() const { return nbClasses_; }
+
+    const SiteContainer* getShrunkData() const { return shrunkData_; }
+    
+    /**
+     * @brief Resize and initialize all likelihood arrays according to the given data set and substitution model.
+     *
+     * @param sites The sequences to use as data.
+     * @param model The substitution model to use.
+     * @throw Exception if an error occures.
+     */
+    void initLikelihoods(const SiteContainer& sites, const SubstitutionModel& model) throw (Exception);
+    
+    /**
+     * @brief Rebuild likelihood arrays at inner nodes.
+     *
+     * This method is to be called when the topology of the tree has changed.
+     * Node arrays relationship are rebuilt according to the new topology of the tree.
+     * The leaves likelihood remain unchanged, so as for the first and second order derivatives.
+     */
+    void reInit() throw (Exception);
+    
+    void reInit(const Node* node) throw (Exception);
+
+  protected:
+    /**
+     * @brief This method initializes the leaves according to a sequence container.
+     *
+     * Here the container shrunkData_ is used.
+     * Likelihood is set to 1 for the state corresponding to the sequence site,
+     * otherwise it is set to 0.
+     *
+     * All likelihood arrays at each nodes are initialized according to alphabet
+     * size and sequences length, and filled with 1.
+     *
+     * NB: This method is recursive.
+     *
+     * @param node  The node defining the subtree to analyse.
+     * @param sites The sequence container to use.
+     * @param model The model, used for initializing leaves' likelihoods.
+     */
+    void initLikelihoods(const Node* node, const SiteContainer& sites, const SubstitutionModel& model) throw (Exception);
+    
+};
+
+} //end of namespace bpp.
+
+#endif //_DRASDRHOMOGENEOUSTREELIKELIHOODDATA_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/DRASRTreeLikelihoodData.cpp b/src/Bpp/Phyl/Likelihood/DRASRTreeLikelihoodData.cpp
new file mode 100644
index 0000000..b9ac775
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DRASRTreeLikelihoodData.cpp
@@ -0,0 +1,293 @@
+//
+// File: DRASRTreeLikelihoodData.cpp
+// Created by: Julien Dutheil
+// Created on: Sat Dec 30 14:20 2006
+// From file HomogeneousTreeLikelihood.cpp
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "DRASRTreeLikelihoodData.h"
+#include "../PatternTools.h"
+
+// From SeqLib:
+#include <Bpp/Seq/SiteTools.h>
+#include <Bpp/Seq/Container/AlignedSequenceContainer.h>
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+#include <Bpp/Seq/Container/VectorSiteContainer.h>
+
+using namespace bpp;
+
+/******************************************************************************/
+
+void DRASRTreeLikelihoodData::initLikelihoods(const SiteContainer& sites, const SubstitutionModel& model)
+throw (Exception)
+{
+  if (sites.getNumberOfSequences() == 1)
+    throw Exception("Error, only 1 sequence!");
+  if (sites.getNumberOfSequences() == 0)
+    throw Exception("Error, no sequence!");
+  if (sites.getAlphabet()->getAlphabetType()
+      != model.getAlphabet()->getAlphabetType())
+    throw AlphabetMismatchException("DRASDRTreeLikelihoodData::initLikelihoods. Data and model must have the same alphabet type.",
+                                    sites.getAlphabet(),
+                                    model.getAlphabet());
+  alphabet_ = sites.getAlphabet();
+  nbStates_ = model.getNumberOfStates();
+  nbSites_  = sites.getNumberOfSites();
+  if (shrunkData_)
+    delete shrunkData_;
+  SitePatterns* patterns;
+  if (usePatterns_)
+  {
+    patterns          = initLikelihoodsWithPatterns(tree_->getRootNode(), sites, model);
+    shrunkData_       = patterns->getSites();
+    rootWeights_      = patterns->getWeights();
+    rootPatternLinks_ = patterns->getIndices();
+    nbDistinctSites_  = shrunkData_->getNumberOfSites();
+  }
+  else
+  {
+    patterns          = new SitePatterns(&sites);
+    shrunkData_       = patterns->getSites();
+    rootWeights_      = patterns->getWeights();
+    rootPatternLinks_ = patterns->getIndices();
+    nbDistinctSites_  = shrunkData_->getNumberOfSites();
+    initLikelihoods(tree_->getRootNode(), *shrunkData_, model);
+  }
+  delete patterns;
+}
+
+/******************************************************************************/
+
+void DRASRTreeLikelihoodData::initLikelihoods(const Node* node, const SiteContainer& sequences, const SubstitutionModel& model) throw (Exception)
+{
+  // Initialize likelihood vector:
+  DRASRTreeLikelihoodNodeData* nodeData = &nodeData_[node->getId()];
+  nodeData->setNode(node);
+  VVVdouble* _likelihoods_node = &nodeData->getLikelihoodArray();
+  VVVdouble* _dLikelihoods_node = &nodeData->getDLikelihoodArray();
+  VVVdouble* _d2Likelihoods_node = &nodeData->getD2LikelihoodArray();
+
+  _likelihoods_node->resize(nbDistinctSites_);
+  _dLikelihoods_node->resize(nbDistinctSites_);
+  _d2Likelihoods_node->resize(nbDistinctSites_);
+
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    VVdouble* _likelihoods_node_i = &(*_likelihoods_node)[i];
+    VVdouble* _dLikelihoods_node_i = &(*_dLikelihoods_node)[i];
+    VVdouble* _d2Likelihoods_node_i = &(*_d2Likelihoods_node)[i];
+    _likelihoods_node_i->resize(nbClasses_);
+    _dLikelihoods_node_i->resize(nbClasses_);
+    _d2Likelihoods_node_i->resize(nbClasses_);
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _likelihoods_node_i_c = &(*_likelihoods_node_i)[c];
+      Vdouble* _dLikelihoods_node_i_c = &(*_dLikelihoods_node_i)[c];
+      Vdouble* _d2Likelihoods_node_i_c = &(*_d2Likelihoods_node_i)[c];
+      _likelihoods_node_i_c->resize(nbStates_);
+      _dLikelihoods_node_i_c->resize(nbStates_);
+      _d2Likelihoods_node_i_c->resize(nbStates_);
+      for (size_t s = 0; s < nbStates_; s++)
+      {
+        (*_likelihoods_node_i_c)[s] = 1; // All likelihoods are initialized to 1.
+        (*_dLikelihoods_node_i_c)[s] = 0; // All dLikelihoods are initialized to 0.
+        (*_d2Likelihoods_node_i_c)[s] = 0; // All d2Likelihoods are initialized to 0.
+      }
+    }
+  }
+
+  // Now initialize likelihood values and pointers:
+
+  if (node->isLeaf())
+  {
+    const Sequence* seq;
+    try
+    {
+      seq = &sequences.getSequence(node->getName());
+    }
+    catch (SequenceNotFoundException snfe)
+    {
+      throw SequenceNotFoundException("DRASRTreeLikelihoodData::initTreelikelihoods. Leaf name in tree not found in site conainer: ", (node->getName()));
+    }
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* _likelihoods_node_i = &(*_likelihoods_node)[i];
+      int state = seq->getValue(i);
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* _likelihoods_node_i_c = &(*_likelihoods_node_i)[c];
+        double test = 0.;
+        for (size_t s = 0; s < nbStates_; s++)
+        {
+          // Leaves likelihood are set to 1 if the char correspond to the site in the sequence,
+          // otherwise value set to 0:
+          // cout << "i=" << i << "\tc=" << c << "\ts=" << s << endl;
+          (*_likelihoods_node_i_c)[s] = model.getInitValue(s, state);
+          test += (*_likelihoods_node_i_c)[s];
+        }
+        if (test < 0.000001)
+          std::cerr << "WARNING!!! Likelihood will be 0 for this site." << std::endl;
+      }
+    }
+  }
+  else
+  {
+    // 'node' is an internal node.
+    std::map<int, std::vector<size_t> >* patternLinks__node = &patternLinks_[node->getId()];
+    size_t nbSonNodes = node->getNumberOfSons();
+    for (size_t l = 0; l < nbSonNodes; l++)
+    {
+      // For each son node,
+      const Node* son = (*node)[static_cast<int>(l)];
+      initLikelihoods(son, sequences, model);
+      std::vector<size_t>* patternLinks__node_son = &(*patternLinks__node)[son->getId()];
+
+      // Init map:
+      patternLinks__node_son->resize(nbDistinctSites_);
+
+      for (size_t i = 0; i < nbDistinctSites_; i++)
+      {
+        (*patternLinks__node_son)[i] = i;
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+SitePatterns* DRASRTreeLikelihoodData::initLikelihoodsWithPatterns(const Node* node, const SiteContainer& sequences, const SubstitutionModel& model) throw (Exception)
+{
+  SiteContainer* tmp = PatternTools::getSequenceSubset(sequences, *node);
+  SitePatterns* patterns = new SitePatterns(tmp, true);
+  SiteContainer* subSequences = patterns->getSites();
+
+  size_t nbSites = subSequences->getNumberOfSites();
+
+  // Initialize likelihood vector:
+  DRASRTreeLikelihoodNodeData* nodeData = &nodeData_[node->getId()];
+  nodeData->setNode(node);
+  VVVdouble* _likelihoods_node = &nodeData->getLikelihoodArray();
+  VVVdouble* _dLikelihoods_node = &nodeData->getDLikelihoodArray();
+  VVVdouble* _d2Likelihoods_node = &nodeData->getD2LikelihoodArray();
+  _likelihoods_node->resize(nbSites);
+  _dLikelihoods_node->resize(nbSites);
+  _d2Likelihoods_node->resize(nbSites);
+
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    VVdouble* _likelihoods_node_i = &(*_likelihoods_node)[i];
+    VVdouble* _dLikelihoods_node_i = &(*_dLikelihoods_node)[i];
+    VVdouble* _d2Likelihoods_node_i = &(*_d2Likelihoods_node)[i];
+    _likelihoods_node_i->resize(nbClasses_);
+    _dLikelihoods_node_i->resize(nbClasses_);
+    _d2Likelihoods_node_i->resize(nbClasses_);
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _likelihoods_node_i_c = &(*_likelihoods_node_i)[c];
+      Vdouble* _dLikelihoods_node_i_c = &(*_dLikelihoods_node_i)[c];
+      Vdouble* _d2Likelihoods_node_i_c = &(*_d2Likelihoods_node_i)[c];
+      _likelihoods_node_i_c->resize(nbStates_);
+      _dLikelihoods_node_i_c->resize(nbStates_);
+      _d2Likelihoods_node_i_c->resize(nbStates_);
+      for (size_t s = 0; s < nbStates_; s++)
+      {
+        (*_likelihoods_node_i_c)[s] = 1; // All likelihoods are initialized to 1.
+        (*_dLikelihoods_node_i_c)[s] = 0; // All dLikelihoods are initialized to 0.
+        (*_d2Likelihoods_node_i_c)[s] = 0; // All d2Likelihoods are initialized to 0.
+      }
+    }
+  }
+
+  // Now initialize likelihood values and pointers:
+
+  if (node->isLeaf())
+  {
+    const Sequence* seq;
+    try
+    {
+      seq = &subSequences->getSequence(node->getName());
+    }
+    catch (SequenceNotFoundException snfe)
+    {
+      throw SequenceNotFoundException("HomogeneousTreeLikelihood::initTreelikelihoodsWithPatterns. Leaf name in tree not found in site conainer: ", (node->getName()));
+    }
+    for (size_t i = 0; i < nbSites; i++)
+    {
+      VVdouble* _likelihoods_node_i = &(*_likelihoods_node)[i];
+      int state = seq->getValue(i);
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* _likelihoods_node_i_c = &(*_likelihoods_node_i)[c];
+        double test = 0.;
+        for (size_t s = 0; s < nbStates_; s++)
+        {
+          // Leaves likelihood are set to 1 if the char correspond to the site in the sequence,
+          // otherwise value set to 0:
+          // cout << "i=" << i << "\tc=" << c << "\ts=" << s << endl;
+          (*_likelihoods_node_i_c)[s] = model.getInitValue(s, state);
+          test += (*_likelihoods_node_i_c)[s];
+        }
+        if (test < 0.000001)
+          std::cerr << "WARNING!!! Likelihood will be 0 for this site." << std::endl;
+      }
+    }
+  }
+  else
+  {
+    // 'node' is an internal node.
+    std::map<int, std::vector<size_t> >* patternLinks__node = &patternLinks_[node->getId()];
+
+    // Now initialize pattern links:
+    size_t nbSonNodes = node->getNumberOfSons();
+    for (int l = 0; l < static_cast<int>(nbSonNodes); l++)
+    {
+      // For each son node,
+      const Node* son = (*node)[l];
+
+      std::vector<size_t>* patternLinks__node_son = &(*patternLinks__node)[son->getId()];
+
+      // Initialize subtree 'l' and retrieves corresponding subSequences:
+      SitePatterns* subPatterns = initLikelihoodsWithPatterns(son, *subSequences, model);
+      (*patternLinks__node_son) = subPatterns->getIndices();
+      delete subPatterns;
+    }
+  }
+  delete subSequences;
+  return patterns;
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Likelihood/DRASRTreeLikelihoodData.h b/src/Bpp/Phyl/Likelihood/DRASRTreeLikelihoodData.h
new file mode 100644
index 0000000..6c8b154
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DRASRTreeLikelihoodData.h
@@ -0,0 +1,311 @@
+//
+// File: DRASRTreeLikelihoodData.h
+// Created by: Julien Dutheil
+// Created on: Sat Dec 30 14:20 2006
+// From file HomogeneousTreeLikelihood.h
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _DRASRHOMOGENEOUSTREELIKELIHOODDATA_H_
+#define _DRASRHOMOGENEOUSTREELIKELIHOODDATA_H_
+
+#include "AbstractTreeLikelihoodData.h"
+#include "../Model/SubstitutionModel.h"
+#include "../SitePatterns.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+
+// From the STL:
+#include <map>
+
+namespace bpp
+{
+
+/**
+ * @brief Likelihood data structure for a node.
+ * 
+ * This class is for use with the DRASRTreeParsimonyData class.
+ * 
+ * Store all conditionnal likelihoods:
+ * <pre>
+ * x[i][c][s]
+ *   |---------> Site i
+ *      |------> Rate class c
+ *         |---> Ancestral state s
+ * </pre> 
+ * We call this the <i>likelihood array</i> for each node.
+ * In the same way, we store first and second order derivatives.
+ *
+ * @see DRASRTreeLikelihoodData
+ */
+class DRASRTreeLikelihoodNodeData :
+  public virtual TreeLikelihoodNodeData
+{
+  private:
+    mutable VVVdouble nodeLikelihoods_;
+    mutable VVVdouble nodeDLikelihoods_;
+    mutable VVVdouble nodeD2Likelihoods_;
+    const Node* node_;
+
+  public:
+    DRASRTreeLikelihoodNodeData() : nodeLikelihoods_(), nodeDLikelihoods_(), nodeD2Likelihoods_(), node_(0) {}
+    
+    DRASRTreeLikelihoodNodeData(const DRASRTreeLikelihoodNodeData& data) :
+      nodeLikelihoods_(data.nodeLikelihoods_),
+      nodeDLikelihoods_(data.nodeDLikelihoods_),
+      nodeD2Likelihoods_(data.nodeD2Likelihoods_),
+      node_(data.node_)
+    {}
+    
+    DRASRTreeLikelihoodNodeData& operator=(const DRASRTreeLikelihoodNodeData& data)
+    {
+      nodeLikelihoods_   = data.nodeLikelihoods_;
+      nodeDLikelihoods_  = data.nodeDLikelihoods_;
+      nodeD2Likelihoods_ = data.nodeD2Likelihoods_;
+      node_              = data.node_;
+      return *this;
+    }
+ 
+#ifndef NO_VIRTUAL_COV
+    DRASRTreeLikelihoodNodeData*
+#else
+    Clonable*
+#endif
+    clone() const
+    {
+      return new DRASRTreeLikelihoodNodeData(*this);
+    }
+
+  public:
+    const Node* getNode() const { return node_; }
+    void setNode(const Node* node) { node_ = node; }
+
+    VVVdouble& getLikelihoodArray() { return nodeLikelihoods_; }
+    const VVVdouble& getLikelihoodArray() const { return nodeLikelihoods_; }
+    
+    VVVdouble& getDLikelihoodArray() { return nodeDLikelihoods_; }
+    const VVVdouble& getDLikelihoodArray() const { return nodeDLikelihoods_; }
+
+    VVVdouble& getD2LikelihoodArray() { return nodeD2Likelihoods_; }
+    const VVVdouble& getD2LikelihoodArray() const { return nodeD2Likelihoods_; }
+};
+
+/**
+ * @brief discrete Rate Across Sites, (simple) Recursive likelihood data structure.
+ */
+class DRASRTreeLikelihoodData :
+  public virtual AbstractTreeLikelihoodData
+{
+  private:
+    /**
+     * @brief This contains all likelihood values used for computation.
+     *
+     */
+    mutable std::map<int, DRASRTreeLikelihoodNodeData> nodeData_;
+      
+    /**
+     * @brief This map defines the pattern network.
+     *
+     * Let n1 be the id of a node in the tree, and n11 and n12 the ids of its sons.
+     * Providing the likelihood array is known for nodes n11 and n12,
+     * the likelihood array for node n1 and site <i>i</i> (_likelihood[n1][i]) must be computed  
+     * using arrays patternLinks_[n1][n11][i] and patternLinks_[n1][n12][i].
+     * This network is intialized once for all in the constructor of this class.
+     *
+     * The double map contains the position of the site to use (second dimension)
+     * of the likelihoods array.
+     */
+    mutable std::map<int, std::map<int, std::vector<size_t> > > patternLinks_;
+    SiteContainer* shrunkData_;
+    size_t nbSites_; 
+    size_t nbStates_;
+    size_t nbClasses_;
+    size_t nbDistinctSites_; 
+    bool usePatterns_;
+
+  public:
+    DRASRTreeLikelihoodData(const TreeTemplate<Node>* tree, size_t nbClasses, bool usePatterns = true) :
+      AbstractTreeLikelihoodData(tree),
+      nodeData_(), patternLinks_(), shrunkData_(0), nbSites_(0), nbStates_(0),
+      nbClasses_(nbClasses), nbDistinctSites_(0), usePatterns_(usePatterns)
+    {}
+
+    DRASRTreeLikelihoodData(const DRASRTreeLikelihoodData& data):
+      AbstractTreeLikelihoodData(data),
+      nodeData_(data.nodeData_),
+      patternLinks_(data.patternLinks_),
+      shrunkData_(0),
+      nbSites_(data.nbSites_), nbStates_(data.nbStates_),
+      nbClasses_(data.nbClasses_), nbDistinctSites_(data.nbDistinctSites_),
+      usePatterns_(data.usePatterns_)
+    {
+      if (data.shrunkData_)
+        shrunkData_      = dynamic_cast<SiteContainer *>(data.shrunkData_->clone());
+    }
+
+    DRASRTreeLikelihoodData& operator=(const DRASRTreeLikelihoodData & data)
+    {
+      AbstractTreeLikelihoodData::operator=(data);
+      nodeData_          = data.nodeData_;
+      patternLinks_      = data.patternLinks_;
+      nbSites_           = data.nbSites_;
+      nbStates_          = data.nbStates_;
+      nbClasses_         = data.nbClasses_;
+      nbDistinctSites_   = data.nbDistinctSites_;
+      if (shrunkData_) delete shrunkData_;
+      if (data.shrunkData_)
+        shrunkData_      = dynamic_cast<SiteContainer*>(data.shrunkData_->clone());
+      else
+        shrunkData_      = 0;
+      usePatterns_       = data.usePatterns_;
+      return *this;
+    }
+
+    virtual ~DRASRTreeLikelihoodData() { delete shrunkData_; }
+
+    DRASRTreeLikelihoodData* clone() const { return new DRASRTreeLikelihoodData(*this); }
+
+  public:
+    /**
+     * @brief Set the tree associated to the data.
+     *
+     * All node data will be actualized accordingly by calling the setNode() method on the corresponding nodes.
+     * @warning: the old tree and the new tree must be two clones! And particularly, they have to share the
+     * same topology and nodes id.
+     *
+     * @param tree The tree to be associated to this data.
+     */
+    void setTree(const TreeTemplate<Node>* tree)
+    { 
+      tree_ = tree;
+      for (std::map<int, DRASRTreeLikelihoodNodeData>::iterator it = nodeData_.begin(); it != nodeData_.end(); it++)
+      {
+        int id = it->second.getNode()->getId();
+        it->second.setNode(tree_->getNode(id));
+      }
+    }
+ 
+    DRASRTreeLikelihoodNodeData& getNodeData(int nodeId)
+    { 
+      return nodeData_[nodeId];
+    }
+    const DRASRTreeLikelihoodNodeData& getNodeData(int nodeId) const
+    { 
+      return nodeData_[nodeId];
+    }
+    size_t getArrayPosition(int parentId, int sonId, size_t currentPosition) const
+    {
+      return patternLinks_[parentId][sonId][currentPosition];
+    }
+    size_t getRootArrayPosition(size_t currentPosition) const
+    {
+      return rootPatternLinks_[currentPosition];
+    }
+    const std::vector<size_t>& getArrayPositions(int parentId, int sonId) const
+    {
+      return patternLinks_[parentId][sonId];
+    }
+    std::vector<size_t>& getArrayPositions(int parentId, int sonId)
+    {
+      return patternLinks_[parentId][sonId];
+    }
+    size_t getArrayPosition(int parentId, int sonId, size_t currentPosition)
+    {
+      return patternLinks_[parentId][sonId][currentPosition];
+    }
+
+    VVVdouble& getLikelihoodArray(int nodeId)
+    {
+      return nodeData_[nodeId].getLikelihoodArray();
+    }
+    
+    VVVdouble& getDLikelihoodArray(int nodeId)
+    {
+      return nodeData_[nodeId].getDLikelihoodArray();
+    }
+    
+    VVVdouble& getD2LikelihoodArray(int nodeId)
+    {
+      return nodeData_[nodeId].getD2LikelihoodArray();
+    }
+
+    size_t getNumberOfDistinctSites() const { return nbDistinctSites_; }
+    size_t getNumberOfSites() const { return nbSites_; }
+    size_t getNumberOfStates() const { return nbStates_; }
+    size_t getNumberOfClasses() const { return nbClasses_; }
+    
+    void initLikelihoods(const SiteContainer& sites, const SubstitutionModel& model) throw (Exception);
+
+  protected:
+    /**
+     * @brief This method initializes the leaves according to a sequence file.
+     * likelihood is set to 1 for the state corresponding to the sequence site,
+     * otherwise it is set to 0.
+     *
+     * All likelihood arrays at each nodes are initialized according to alphabet
+     * size and sequences length, and filled with 1.
+     *
+     * NB: This method is recursive.
+     *
+     * @param node      The node defining the subtree to analyse.
+     * @param sequences The data to be used for initialization.
+     * @param model     The model to use.
+     */
+    virtual void initLikelihoods(const Node* node, const SiteContainer& sequences, const SubstitutionModel& model) throw (Exception);
+
+    /**
+     * @brief This method initializes the leaves according to a sequence file.
+     *
+     * likelihood is set to 1 for the state corresponding to the sequence site,
+     * otherwise it is set to 0.
+     *
+     * All likelihood arrays at each nodes are initialized according to alphabet
+     * size and sequences length, and filled with 1.
+     *
+     * NB: This method is recursive.
+     *
+     * @param node      The node defining the subtree to analyse.
+     * @param sequences The data to be used for initialization.
+     * @param model     The model to use.
+     * @return The shrunk sub-dataset + indices for the subtree defined by <i>node</i>.
+     */
+    virtual SitePatterns* initLikelihoodsWithPatterns(const Node* node, const SiteContainer& sequences, const SubstitutionModel& model) throw (Exception);
+  
+};
+
+} //end of namespace bpp.
+
+#endif //_DRASRHOMOGENEOUSTREELIKELIHOODDATA_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/DRHomogeneousMixedTreeLikelihood.cpp b/src/Bpp/Phyl/Likelihood/DRHomogeneousMixedTreeLikelihood.cpp
new file mode 100644
index 0000000..6dee6c9
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DRHomogeneousMixedTreeLikelihood.cpp
@@ -0,0 +1,522 @@
+//
+// File: DRHomogeneousMixedTreeLikelihood.cpp
+// Created by: Laurent Gueguen
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "DRHomogeneousMixedTreeLikelihood.h"
+
+
+// From the STL:
+#include <iostream>
+
+#include <math.h>
+#include "../PatternTools.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/App/ApplicationTools.h>
+
+using namespace bpp;
+using namespace std;
+
+DRHomogeneousMixedTreeLikelihood::DRHomogeneousMixedTreeLikelihood(
+  const Tree& tree,
+  SubstitutionModel* model,
+  DiscreteDistribution* rDist,
+  bool checkRooted,
+  bool verbose,
+  bool rootArray)  throw (Exception) :
+  DRHomogeneousTreeLikelihood(tree, model, rDist, checkRooted, verbose),
+  treeLikelihoodsContainer_(),
+  probas_(),
+  rootArray_(rootArray)
+{
+  MixedSubstitutionModel* mixedmodel;
+
+  if ((mixedmodel = dynamic_cast<MixedSubstitutionModel*>(model_)) == NULL)
+    throw Exception("Bad model: DRHomogeneousMixedTreeLikelihood needs a MixedSubstitutionModel.");
+
+  size_t s = mixedmodel->getNumberOfModels();
+  for (size_t i = 0; i < s; i++)
+  {
+    treeLikelihoodsContainer_.push_back(
+      new DRHomogeneousTreeLikelihood(tree, mixedmodel->getNModel(i), rDist, checkRooted, false));
+    probas_.push_back(mixedmodel->getNProbability(i));
+  }
+}
+
+DRHomogeneousMixedTreeLikelihood::DRHomogeneousMixedTreeLikelihood(
+  const Tree& tree,
+  const SiteContainer& data,
+  SubstitutionModel* model,
+  DiscreteDistribution* rDist,
+  bool checkRooted,
+  bool verbose,
+  bool rootArray)
+throw (Exception) :
+  DRHomogeneousTreeLikelihood(tree, model, rDist, checkRooted, verbose),
+  treeLikelihoodsContainer_(),
+  probas_(),
+  rootArray_(rootArray)
+{
+  MixedSubstitutionModel* mixedmodel;
+
+  if ((mixedmodel = dynamic_cast<MixedSubstitutionModel*>(model_)) == NULL)
+    throw Exception("Bad model: DRHomogeneousMixedTreeLikelihood needs a MixedSubstitutionModel.");
+
+  size_t s = mixedmodel->getNumberOfModels();
+
+  for (size_t i = 0; i < s; i++)
+  {
+    treeLikelihoodsContainer_.push_back(
+      new DRHomogeneousTreeLikelihood(tree, mixedmodel->getNModel(i), rDist, checkRooted, false));
+    probas_.push_back(mixedmodel->getNProbability(i));
+  }
+  setData(data);
+}
+
+
+DRHomogeneousMixedTreeLikelihood& DRHomogeneousMixedTreeLikelihood::operator=(const DRHomogeneousMixedTreeLikelihood& lik)
+{
+  DRHomogeneousTreeLikelihood::operator=(lik);
+  
+  treeLikelihoodsContainer_.clear();
+  probas_.clear();
+
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_.push_back(lik.treeLikelihoodsContainer_[i]->clone());
+    probas_.push_back(lik.probas_[i]);
+  }
+
+  rootArray_=lik.rootArray_;
+
+  return *this;
+}
+
+DRHomogeneousMixedTreeLikelihood::DRHomogeneousMixedTreeLikelihood(const DRHomogeneousMixedTreeLikelihood& lik) :
+  DRHomogeneousTreeLikelihood(lik),
+  treeLikelihoodsContainer_(lik.treeLikelihoodsContainer_.size()),
+  probas_(lik.probas_.size()),
+  rootArray_(lik.rootArray_)
+{
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_.push_back(lik.treeLikelihoodsContainer_[i]->clone());
+    probas_.push_back(lik.probas_[i]);
+  }
+}
+
+DRHomogeneousMixedTreeLikelihood::~DRHomogeneousMixedTreeLikelihood()
+{
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    delete treeLikelihoodsContainer_[i];
+  }
+}
+
+
+void DRHomogeneousMixedTreeLikelihood::initialize() throw (Exception)
+{
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->initialize();
+  }
+  DRHomogeneousTreeLikelihood::initialize();
+  if(rootArray_)
+    computeRootLikelihood();
+}
+
+void DRHomogeneousMixedTreeLikelihood::setData(const SiteContainer& sites) throw (Exception)
+{
+  DRHomogeneousTreeLikelihood::setData(sites);
+
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->setData(sites);
+  }
+}
+
+
+void DRHomogeneousMixedTreeLikelihood::fireParameterChanged(const ParameterList& params)
+{
+  applyParameters();
+
+  MixedSubstitutionModel* mixedmodel = dynamic_cast<MixedSubstitutionModel*>(model_);
+
+  size_t s = mixedmodel->getNumberOfModels();
+
+  const SubstitutionModel* pm;
+  for (size_t i = 0; i < s; i++)
+  {
+    ParameterList pl;
+    pm = mixedmodel->getNModel(i);
+    pl.addParameters(pm->getParameters());
+    pl.includeParameters(getParameters());
+    treeLikelihoodsContainer_[i]->matchParametersValues(pl);
+  }
+  probas_ = mixedmodel->getProbabilities();
+
+  minusLogLik_ = -getLogLikelihood();
+}
+
+void DRHomogeneousMixedTreeLikelihood::resetLikelihoodArrays(const Node* node)
+{
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->resetLikelihoodArrays(node);
+  }
+}
+
+void DRHomogeneousMixedTreeLikelihood::computeTreeLikelihood()
+{
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeTreeLikelihood();
+  }
+  if(rootArray_)
+    computeRootLikelihood();
+}
+
+/******************************************************************************
+*                           Likelihoods                          *
+******************************************************************************/
+
+double DRHomogeneousMixedTreeLikelihood::getLikelihood() const
+{
+  double l = 1.;
+  vector<Vdouble*> llik;
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    llik.push_back(&treeLikelihoodsContainer_[i]->likelihoodData_->getRootRateSiteLikelihoodArray());
+  }
+
+  double x;
+  const vector<unsigned int> * w = &likelihoodData_->getWeights();
+  for (unsigned int i = 0; i < nbDistinctSites_; i++)
+  {
+    x = 0;
+    for (unsigned int j = 0; j < treeLikelihoodsContainer_.size(); j++)
+    {
+      x += (*llik[j])[i] * probas_[j];
+    }
+    l *= std::pow(x, (int)(*w)[i]);
+  }
+  return l;
+}
+
+double DRHomogeneousMixedTreeLikelihood::getLogLikelihood() const
+{
+  double ll = 0;
+
+  vector<Vdouble*> llik;
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    llik.push_back(&treeLikelihoodsContainer_[i]->likelihoodData_->getRootRateSiteLikelihoodArray());
+  }
+
+  double x;
+  const vector<unsigned int> * w = &likelihoodData_->getWeights();
+  vector<double> la(nbDistinctSites_);
+  for (unsigned int i = 0; i < nbDistinctSites_; i++)
+  {
+    x = 0;
+    for (unsigned int j = 0; j < treeLikelihoodsContainer_.size(); j++)
+    {
+      x += (*llik[j])[i] * probas_[j];
+    }
+    la[i] = (*w)[i] * log(x);
+  }
+  sort(la.begin(), la.end());
+  for (size_t i = nbDistinctSites_; i > 0; i--)
+  {
+    ll += la[i - 1];
+  }
+
+  return ll;
+}
+
+
+double DRHomogeneousMixedTreeLikelihood::getLikelihoodForASite(unsigned int site) const
+{
+  double res = 0;
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    res += treeLikelihoodsContainer_[i]->getLikelihoodForASite(site) * probas_[i];
+  }
+
+  return res;
+}
+
+double DRHomogeneousMixedTreeLikelihood::getLogLikelihoodForASite(unsigned int site) const
+{
+  double x = getLikelihoodForASite(site);
+  if (x < 0) x = 0;
+  return log(x);
+}
+
+double DRHomogeneousMixedTreeLikelihood::getLikelihoodForASiteForARateClass(unsigned int site, unsigned int rateClass) const
+{
+  double res = 0;
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    res += treeLikelihoodsContainer_[i]->getLikelihoodForASiteForARateClass(site, rateClass) * probas_[i];
+  }
+
+  return res;
+}
+
+double DRHomogeneousMixedTreeLikelihood::getLogLikelihoodForASiteForARateClass(unsigned int site, unsigned int rateClass) const
+{
+  double x = getLikelihoodForASiteForARateClass(site, rateClass);
+  if (x < 0) x = 0;
+  return log(x);
+}
+
+double DRHomogeneousMixedTreeLikelihood::getLikelihoodForASiteForARateClassForAState(unsigned int site, unsigned int rateClass, int state) const
+{
+  double res = 0;
+
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    res += treeLikelihoodsContainer_[i]->getLikelihoodForASiteForARateClassForAState(site, rateClass, state) * probas_[i];
+  }
+
+  return res;
+}
+
+double DRHomogeneousMixedTreeLikelihood::getLogLikelihoodForASiteForARateClassForAState(unsigned int site, unsigned int rateClass, int state) const
+{
+  double x = getLikelihoodForASiteForARateClassForAState(site, rateClass, state);
+  if (x < 0) x = 0;
+  return log(x);
+}
+
+
+void DRHomogeneousMixedTreeLikelihood::computeSubtreeLikelihoodPostfix(const Node* node)
+{
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeSubtreeLikelihoodPostfix(node);
+  }
+}
+
+void DRHomogeneousMixedTreeLikelihood::computeSubtreeLikelihoodPrefix(const Node* node)
+{
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeSubtreeLikelihoodPostfix(node);
+  }
+}
+
+void DRHomogeneousMixedTreeLikelihood::computeRootLikelihood()
+{
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeRootLikelihood();
+  }
+}
+
+void DRHomogeneousMixedTreeLikelihood::computeLikelihoodAtNode_(const Node* node, VVVdouble& likelihoodArray) const
+{
+  likelihoodArray.resize(nbDistinctSites_);
+  for (unsigned int i = 0; i < nbDistinctSites_; i++){
+    VVdouble* likelihoodArray_i = &likelihoodArray[i];
+    likelihoodArray_i->resize(nbClasses_);
+    for (unsigned int c = 0; c < nbClasses_; c++) {
+      Vdouble* likelihoodArray_i_c = &(*likelihoodArray_i)[c];
+      likelihoodArray_i_c->resize(nbStates_);
+      for (unsigned int x = 0; x < nbStates_; x++)
+        (*likelihoodArray_i_c)[x] = 0;
+    }
+  }
+
+  VVVdouble lArray;
+  for (unsigned int nm = 0; nm < treeLikelihoodsContainer_.size(); nm++)
+  {
+    treeLikelihoodsContainer_[nm]->computeLikelihoodAtNode_(node, lArray);
+    
+    for (unsigned int i = 0; i < nbDistinctSites_; i++)
+      {
+        VVdouble* likelihoodArray_i = &likelihoodArray[i];
+        VVdouble* lArray_i = &lArray[i];
+        
+        for (unsigned int c = 0; c < nbClasses_; c++)
+          {
+            Vdouble* likelihoodArray_i_c = &(*likelihoodArray_i)[c];
+            Vdouble* lArray_i_c = &(*lArray_i)[c];
+            for (unsigned int x = 0; x < nbStates_; x++)
+              (*likelihoodArray_i_c)[x] += (*lArray_i_c)[x] * probas_[nm];
+         }
+      }
+    
+  }
+}
+
+/******************************************************************************
+*                           First Order Derivatives                          *
+******************************************************************************/
+
+void DRHomogeneousMixedTreeLikelihood::computeTreeDLikelihoods()
+{
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeTreeDLikelihoods();
+  }
+}
+
+double DRHomogeneousMixedTreeLikelihood::getFirstOrderDerivative(const std::string& variable) const
+throw (Exception)
+{
+  if (!hasParameter(variable))
+    throw ParameterNotFoundException("DRHomogeneousTreeLikelihood::getFirstOrderDerivative().", variable);
+  if (getRateDistributionParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to rate distribution parameters are not implemented.");
+  }
+  if (getSubstitutionModelParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to substitution model parameters are not implemented.");
+  }
+
+  //
+  // Computation for branch lengths:
+  //
+
+  // Get the node with the branch whose length must be derivated:
+  unsigned int brI = TextTools::to<unsigned int>(variable.substr(5));
+  const Node* branch = nodes_[brI];
+  vector< Vdouble*> _vdLikelihoods_branch;
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    _vdLikelihoods_branch.push_back(&treeLikelihoodsContainer_[i]->likelihoodData_->getDLikelihoodArray(branch->getId()));
+  }
+
+  double d = 0;
+  double x;
+  const vector<unsigned int> * w = &likelihoodData_->getWeights();
+  for (unsigned int i = 0; i < nbDistinctSites_; i++)
+  {
+    x = 0;
+    for (unsigned int j = 0; j < treeLikelihoodsContainer_.size(); j++)
+    {
+      x += (*_vdLikelihoods_branch[j])[i] * probas_[j];
+    }
+    d += (*w)[i] * x;
+  }
+
+  return -d;
+}
+
+
+/******************************************************************************
+*                           Second Order Derivatives                          *
+******************************************************************************/
+
+void DRHomogeneousMixedTreeLikelihood::computeTreeD2LikelihoodAtNode(const Node* node)
+{
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeTreeD2LikelihoodAtNode(node);
+  }
+}
+
+void DRHomogeneousMixedTreeLikelihood::computeTreeD2Likelihoods()
+{
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeTreeD2Likelihoods();
+  }
+}
+
+double DRHomogeneousMixedTreeLikelihood::getSecondOrderDerivative(const std::string& variable) const
+throw (Exception)
+{
+  if (!hasParameter(variable))
+    throw ParameterNotFoundException("DRHomogeneousTreeLikelihood::getFirstOrderDerivative().", variable);
+  if (getRateDistributionParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to rate distribution parameters are not implemented.");
+  }
+  if (getSubstitutionModelParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to substitution model parameters are not implemented.");
+  }
+
+  //
+  // Computation for branch lengths:
+  //
+
+  // Get the node with the branch whose length must be derivated:
+  unsigned int brI = TextTools::to<unsigned int>(variable.substr(5));
+  const Node* branch = nodes_[brI];
+  vector< Vdouble*> _vdLikelihoods_branch, _vd2Likelihoods_branch;
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    _vdLikelihoods_branch.push_back(&treeLikelihoodsContainer_[i]->likelihoodData_->getDLikelihoodArray(branch->getId()));
+    _vd2Likelihoods_branch.push_back(&treeLikelihoodsContainer_[i]->likelihoodData_->getD2LikelihoodArray(branch->getId()));
+  }
+
+  double d = 0;
+  double x, x2;
+  const vector<unsigned int> * w = &likelihoodData_->getWeights();
+  for (unsigned int i = 0; i < nbDistinctSites_; i++)
+  {
+    x = 0;
+    x2 = 0;
+    for (unsigned int j = 0; j < treeLikelihoodsContainer_.size(); j++)
+    {
+      x += (*_vdLikelihoods_branch[j])[i] * probas_[j];
+    }
+    for (unsigned int j = 0; j < treeLikelihoodsContainer_.size(); j++)
+    {
+      x2 += (*_vd2Likelihoods_branch[j])[i] * probas_[j];
+    }
+
+    d += (*w)[i] * (x2 - pow(x, 2));
+  }
+
+  return -d;
+}
+
+
+void DRHomogeneousMixedTreeLikelihood::displayLikelihood(const Node* node)
+{
+  for (unsigned int i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->displayLikelihood(node);
+  }
+}
+
diff --git a/src/Bpp/Phyl/Likelihood/DRHomogeneousMixedTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/DRHomogeneousMixedTreeLikelihood.h
new file mode 100644
index 0000000..7958486
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DRHomogeneousMixedTreeLikelihood.h
@@ -0,0 +1,218 @@
+//
+// File: DRHomogeneousMixedTreeLikelihood.h
+// Created by: Laurent Gueguen
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _DRHOMOGENEOUSMIXEDTREELIKELIHOOD_H_
+#define _DRHOMOGENEOUSMIXEDTREELIKELIHOOD_H_
+
+#include "DRHomogeneousTreeLikelihood.h"
+#include "../Model/SubstitutionModel.h"
+#include "../Model/MixedSubstitutionModel.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+
+namespace bpp
+{
+
+/**
+ * @brief A class to compute the average of several
+ * DRHomogeneousTreeLikelihood defined from a Mixed Substitution
+ * Model.
+ *
+ * In all computations, the average of the likelihoods, probabilities
+ * are computed.
+ **/
+class DRHomogeneousMixedTreeLikelihood :
+  public DRHomogeneousTreeLikelihood
+{
+private:
+  std::vector<DRHomogeneousTreeLikelihood*> treeLikelihoodsContainer_;
+  std::vector<double> probas_;
+
+  // true if the root Array should be computed (for ancestral
+  // reconstruction)
+  
+  bool rootArray_;
+  
+public:
+  /**
+   * @brief Build a new DRHomogeneousMixedTreeLikelihood object without
+   * data.
+   *
+   * This constructor only initialize the parameters. To compute a
+   * likelihood, you will need to call the setData() and the
+   * computeTreeLikelihood() methods.
+   *
+   * @param tree The tree to use.
+   * @param model The mixed substitution model to use.
+   * @param rDist The rate across sites distribution to use.
+   * @param checkRooted Tell if we have to check for the tree to be unrooted.
+   * If true, any rooted tree will be unrooted before likelihood computation.
+   * @param verbose Should I display some info?
+   * @param rootArray is true if the array of the likelihoods at the root
+   *    should be computed (useful for ancestral reconstruction).
+   * @throw Exception in an error occured.
+   */
+  DRHomogeneousMixedTreeLikelihood(
+    const Tree& tree,
+    SubstitutionModel* model,
+    DiscreteDistribution* rDist,
+    bool checkRooted = true,
+    bool verbose = true,
+    bool rootArray = false)
+  throw (Exception);
+
+  /**
+   * @brief Build a new DRHomogeneousMixedTreeLikelihood object with data.
+   *
+   * This constructor initializes all parameters, data, and likelihood arrays.
+   *
+   * @param tree The tree to use.
+   * @param data Sequences to use.
+   * @param model The mixed substitution model to use.
+   * @param rDist The rate across sites distribution to use.
+   * @param checkRooted Tell if we have to check for the tree to be unrooted.
+   * If true, any rooted tree will be unrooted before likelihood computation.
+   * @param verbose Should I display some info?
+   * @param rootArray is true if the array of the likelihoods at the root
+   *    should be computed (useful for ancestral reconstruction).
+   * @throw Exception in an error occured.
+   */
+  DRHomogeneousMixedTreeLikelihood(
+    const Tree& tree,
+    const SiteContainer& data,
+    SubstitutionModel* model,
+    DiscreteDistribution* rDist,
+    bool checkRooted = true,
+    bool verbose = true,
+    bool rootArray = false)
+  throw (Exception);
+
+  DRHomogeneousMixedTreeLikelihood(const DRHomogeneousMixedTreeLikelihood& lik);
+
+  DRHomogeneousMixedTreeLikelihood& operator=(const DRHomogeneousMixedTreeLikelihood& lik);
+
+  virtual ~DRHomogeneousMixedTreeLikelihood();
+
+  DRHomogeneousMixedTreeLikelihood* clone() const { return new DRHomogeneousMixedTreeLikelihood(*this); }
+
+public:
+  /**
+   * @name The TreeLikelihood interface.
+   *
+   * Other methods are implemented in the DRHomogeneousTreeLikelihood class.
+   *
+   * @{
+   */
+  double getLikelihood() const;
+  double getLogLikelihood() const;
+  
+  void setData(const SiteContainer& sites) throw (Exception);
+  double getLikelihoodForASite (unsigned int site) const;
+  double getLogLikelihoodForASite(unsigned int site) const;
+  /** @} */
+
+
+  /**
+   * @name The DiscreteRatesAcrossSites interface implementation:
+   *
+   * @{
+   */
+  double getLikelihoodForASiteForARateClass(unsigned int site, unsigned int rateClass) const;
+  double getLogLikelihoodForASiteForARateClass(unsigned int site, unsigned int rateClass) const;
+  double getLikelihoodForASiteForARateClassForAState(unsigned int site, unsigned int rateClass, int state) const;
+  double getLogLikelihoodForASiteForARateClassForAState(unsigned int site, unsigned int rateClass, int state) const;
+  /** @} */
+
+  /**
+   * @name DerivableFirstOrder interface.
+   *
+   * @{
+   */
+  double getFirstOrderDerivative(const std::string& variable) const throw (Exception);
+  /** @} */
+
+  /**
+   * @name DerivableSecondOrder interface.
+   *
+   * @{
+   */
+  double getSecondOrderDerivative(const std::string& variable) const throw (Exception);
+  double getSecondOrderDerivative(const std::string& variable1, const std::string& variable2) const throw (Exception) { return 0; } // Not implemented for now.
+  /** @} */
+
+public:
+  // Specific methods:
+  void initialize() throw (Exception);
+
+  void fireParameterChanged(const ParameterList& params);
+
+  void computeTreeLikelihood();
+
+  virtual void computeTreeDLikelihoods();
+
+protected:
+  virtual void computeLikelihoodAtNode_(const Node* node, VVVdouble& likelihoodArray) const;
+
+  /**
+   * @brief Compute the likelihood for a subtree defined by the Tree::Node <i>node</i>.
+   *
+   * @param node The root of the subtree.
+   */
+  virtual void computeSubtreeLikelihoodPostfix(const Node* node);
+
+  virtual void computeSubtreeLikelihoodPrefix(const Node* node);
+
+  virtual void computeRootLikelihood();
+
+  virtual void computeTreeD2LikelihoodAtNode(const Node*);
+  virtual void computeTreeD2Likelihoods();
+
+  void resetLikelihoodArrays(const Node* node);
+
+  /**
+   * @brief This method is mainly for debugging purpose.
+   *
+   * @param node The node at which likelihood values must be displayed.
+   */
+  virtual void displayLikelihood(const Node* node);
+};
+} // end of namespace bpp.
+
+#endif  // _DRHOMOGENEOUSMIXEDTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/DRHomogeneousTreeLikelihood.cpp b/src/Bpp/Phyl/Likelihood/DRHomogeneousTreeLikelihood.cpp
new file mode 100644
index 0000000..abfae54
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DRHomogeneousTreeLikelihood.cpp
@@ -0,0 +1,977 @@
+//
+// File: DRHomogeneousTreeLikelihood.cpp
+// Created by: Julien Dutheil
+// Created on: Fri Oct 17 18:14:51 2003
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "DRHomogeneousTreeLikelihood.h"
+#include "../PatternTools.h"
+
+// From SeqLib:
+#include <Bpp/Seq/SiteTools.h>
+#include <Bpp/Seq/Container/AlignedSequenceContainer.h>
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/App/ApplicationTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+
+using namespace std;
+
+/******************************************************************************/
+
+DRHomogeneousTreeLikelihood::DRHomogeneousTreeLikelihood(
+  const Tree& tree,
+  SubstitutionModel* model,
+  DiscreteDistribution* rDist,
+  bool checkRooted,
+  bool verbose)
+throw (Exception) :
+  AbstractHomogeneousTreeLikelihood(tree, model, rDist, checkRooted, verbose),
+  likelihoodData_(0),
+  minusLogLik_(-1.)
+{
+  init_();
+}
+
+/******************************************************************************/
+
+DRHomogeneousTreeLikelihood::DRHomogeneousTreeLikelihood(
+  const Tree& tree,
+  const SiteContainer& data,
+  SubstitutionModel* model,
+  DiscreteDistribution* rDist,
+  bool checkRooted,
+  bool verbose)
+throw (Exception) :
+  AbstractHomogeneousTreeLikelihood(tree, model, rDist, checkRooted, verbose),
+  likelihoodData_(0),
+  minusLogLik_(-1.)
+{
+  init_();
+  setData(data);
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::init_() throw (Exception)
+{
+  likelihoodData_ = new DRASDRTreeLikelihoodData(
+    tree_,
+    rateDistribution_->getNumberOfCategories());
+}
+
+/******************************************************************************/
+
+DRHomogeneousTreeLikelihood::DRHomogeneousTreeLikelihood(const DRHomogeneousTreeLikelihood& lik) :
+  AbstractHomogeneousTreeLikelihood(lik),
+  likelihoodData_(0),
+  minusLogLik_(-1.)
+{
+  likelihoodData_ = dynamic_cast<DRASDRTreeLikelihoodData*>(lik.likelihoodData_->clone());
+  likelihoodData_->setTree(tree_);
+  minusLogLik_ = lik.minusLogLik_;
+}
+
+/******************************************************************************/
+
+DRHomogeneousTreeLikelihood& DRHomogeneousTreeLikelihood::operator=(const DRHomogeneousTreeLikelihood& lik)
+{
+  AbstractHomogeneousTreeLikelihood::operator=(lik);
+  if (likelihoodData_)
+    delete likelihoodData_;
+  likelihoodData_ = dynamic_cast<DRASDRTreeLikelihoodData*>(lik.likelihoodData_->clone());
+  likelihoodData_->setTree(tree_);
+  minusLogLik_ = lik.minusLogLik_;
+  return *this;
+}
+
+/******************************************************************************/
+
+DRHomogeneousTreeLikelihood::~DRHomogeneousTreeLikelihood()
+{
+  delete likelihoodData_;
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::setData(const SiteContainer& sites) throw (Exception)
+{
+  if (data_)
+    delete data_;
+  data_ = PatternTools::getSequenceSubset(sites, *tree_->getRootNode());
+  if (verbose_)
+    ApplicationTools::displayTask("Initializing data structure");
+  likelihoodData_->initLikelihoods(*data_, *model_);
+  if (verbose_)
+    ApplicationTools::displayTaskDone();
+
+  nbSites_ = likelihoodData_->getNumberOfSites();
+  nbDistinctSites_ = likelihoodData_->getNumberOfDistinctSites();
+  nbStates_ = likelihoodData_->getNumberOfStates();
+
+  if (verbose_)
+    ApplicationTools::displayResult("Number of distinct sites",
+                                    TextTools::toString(nbDistinctSites_));
+  initialized_ = false;
+}
+
+/******************************************************************************/
+
+double DRHomogeneousTreeLikelihood::getLikelihood() const
+{
+  double l = 1.;
+  Vdouble* lik = &likelihoodData_->getRootRateSiteLikelihoodArray();
+  const vector<unsigned int>* w = &likelihoodData_->getWeights();
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    l *= std::pow((*lik)[i], (int)(*w)[i]);
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+double DRHomogeneousTreeLikelihood::getLogLikelihood() const
+{
+  double ll = 0;
+  Vdouble* lik = &likelihoodData_->getRootRateSiteLikelihoodArray();
+  const vector<unsigned int>* w = &likelihoodData_->getWeights();
+  vector<double> la(nbDistinctSites_);
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    la[i] = (*w)[i] * log((*lik)[i]);
+  }
+  sort(la.begin(), la.end());
+  for (size_t i = nbDistinctSites_; i > 0; i--)
+  {
+    ll += la[i - 1];
+  }
+  return ll;
+}
+
+/******************************************************************************/
+
+double DRHomogeneousTreeLikelihood::getLikelihoodForASite(size_t site) const
+{
+  return likelihoodData_->getRootRateSiteLikelihoodArray()[likelihoodData_->getRootArrayPosition(site)];
+}
+
+/******************************************************************************/
+
+double DRHomogeneousTreeLikelihood::getLogLikelihoodForASite(size_t site) const
+{
+  return log(likelihoodData_->getRootRateSiteLikelihoodArray()[likelihoodData_->getRootArrayPosition(site)]);
+}
+
+/******************************************************************************/
+double DRHomogeneousTreeLikelihood::getLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  return likelihoodData_->getRootSiteLikelihoodArray()[likelihoodData_->getRootArrayPosition(site)][rateClass];
+}
+
+/******************************************************************************/
+
+double DRHomogeneousTreeLikelihood::getLogLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  return log(likelihoodData_->getRootSiteLikelihoodArray()[likelihoodData_->getRootArrayPosition(site)][rateClass]);
+}
+
+/******************************************************************************/
+
+double DRHomogeneousTreeLikelihood::getLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const
+{
+  return likelihoodData_->getRootLikelihoodArray()[likelihoodData_->getRootArrayPosition(site)][rateClass][state];
+}
+
+/******************************************************************************/
+
+double DRHomogeneousTreeLikelihood::getLogLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const
+{
+  return log(likelihoodData_->getRootLikelihoodArray()[likelihoodData_->getRootArrayPosition(site)][rateClass][state]);
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::setParameters(const ParameterList& parameters)
+throw (ParameterNotFoundException, ConstraintException)
+{
+  setParametersValues(parameters);
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::fireParameterChanged(const ParameterList& params)
+{
+  applyParameters();
+
+  if (rateDistribution_->getParameters().getCommonParametersWith(params).size() > 0
+      || model_->getParameters().getCommonParametersWith(params).size() > 0)
+  {
+    // Rate parameter changed, need to recompute all probs:
+    computeAllTransitionProbabilities();
+  }
+  else if (params.size() > 0)
+  {
+    // We may save some computations:
+    for (size_t i = 0; i < params.size(); i++)
+    {
+      string s = params[i].getName();
+      if (s.substr(0, 5) == "BrLen")
+      {
+        // Branch length parameter:
+        computeTransitionProbabilitiesForNode(nodes_[TextTools::to < size_t > (s.substr(5))]);
+      }
+    }
+  }
+
+  computeTreeLikelihood();
+  if (computeFirstOrderDerivatives_)
+  {
+    computeTreeDLikelihoods();
+  }
+  if (computeSecondOrderDerivatives_)
+  {
+    computeTreeD2Likelihoods();
+  }
+
+  minusLogLik_ = -getLogLikelihood();
+}
+
+/******************************************************************************/
+
+double DRHomogeneousTreeLikelihood::getValue() const
+throw (Exception)
+{
+  if (!isInitialized())
+    throw Exception("DRHomogeneousTreeLikelihood::getValue(). Instance is not initialized.");
+  return minusLogLik_;
+}
+
+/******************************************************************************
+*                           First Order Derivatives                          *
+******************************************************************************/
+void DRHomogeneousTreeLikelihood::computeTreeDLikelihoodAtNode(const Node* node)
+{
+  const Node* father = node->getFather();
+  VVVdouble* _likelihoods_father_node = &likelihoodData_->getLikelihoodArray(father->getId(), node->getId());
+  Vdouble* _dLikelihoods_node = &likelihoodData_->getDLikelihoodArray(node->getId());
+  VVVdouble*  pxy__node = &pxy_[node->getId()];
+  VVVdouble* dpxy__node = &dpxy_[node->getId()];
+  VVVdouble larray;
+  computeLikelihoodAtNode_(father, larray);
+  Vdouble* rootLikelihoodsSR = &likelihoodData_->getRootRateSiteLikelihoodArray();
+
+  double dLi, dLic, dLicx, numerator, denominator;
+
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    VVdouble* _likelihoods_father_node_i = &(*_likelihoods_father_node)[i];
+    VVdouble* larray_i = &larray[i];
+    dLi = 0;
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _likelihoods_father_node_i_c = &(*_likelihoods_father_node_i)[c];
+      Vdouble* larray_i_c = &(*larray_i)[c];
+      VVdouble*  pxy__node_c = &(*pxy__node)[c];
+      VVdouble* dpxy__node_c = &(*dpxy__node)[c];
+      dLic = 0;
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        numerator = 0;
+        denominator = 0;
+        Vdouble*  pxy__node_c_x = &(*pxy__node_c)[x];
+        Vdouble* dpxy__node_c_x = &(*dpxy__node_c)[x];
+        dLicx = 0;
+        for (size_t y = 0; y < nbStates_; y++)
+        {
+          numerator   += (*dpxy__node_c_x)[y] * (*_likelihoods_father_node_i_c)[y];
+          denominator += (*pxy__node_c_x)[y] * (*_likelihoods_father_node_i_c)[y];
+        }
+        dLicx = denominator == 0. ? 0. : (*larray_i_c)[x] * numerator / denominator;
+        // cout << i << "\t" << c << "\t" << x << "\t" << (*larray_i_c)[x] << "\t" << numerator << "\t" << denominator << endl;
+        dLic += dLicx;
+      }
+      dLi += rateDistribution_->getProbability(c) * dLic;
+    }
+    (*_dLikelihoods_node)[i] = dLi / (*rootLikelihoodsSR)[i];
+    // cout << dLi << "\t" << (*rootLikelihoodsSR)[i] << endl;
+  }
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::computeTreeDLikelihoods()
+{
+  for (size_t k = 0; k < nbNodes_; k++)
+  {
+    computeTreeDLikelihoodAtNode(nodes_[k]);
+  }
+}
+
+/******************************************************************************/
+
+double DRHomogeneousTreeLikelihood::getFirstOrderDerivative(const std::string& variable) const
+throw (Exception)
+{
+  if (!hasParameter(variable))
+    throw ParameterNotFoundException("DRHomogeneousTreeLikelihood::getFirstOrderDerivative().", variable);
+  if (getRateDistributionParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to rate distribution parameters are not implemented.");
+  }
+  if (getSubstitutionModelParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to substitution model parameters are not implemented.");
+  }
+
+  //
+  // Computation for branch lengths:
+  //
+
+  // Get the node with the branch whose length must be derivated:
+  size_t brI = TextTools::to<size_t>(variable.substr(5));
+  const Node* branch = nodes_[brI];
+  Vdouble* _dLikelihoods_branch = &likelihoodData_->getDLikelihoodArray(branch->getId());
+  double d = 0;
+  const vector<unsigned int>* w = &likelihoodData_->getWeights();
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    d += (*w)[i] * (*_dLikelihoods_branch)[i];
+  }
+  return -d;
+}
+
+/******************************************************************************
+*                           Second Order Derivatives                         *
+******************************************************************************/
+void DRHomogeneousTreeLikelihood::computeTreeD2LikelihoodAtNode(const Node* node)
+{
+  const Node* father = node->getFather();
+  VVVdouble* _likelihoods_father_node = &likelihoodData_->getLikelihoodArray(father->getId(), node->getId());
+  Vdouble* _d2Likelihoods_node = &likelihoodData_->getD2LikelihoodArray(node->getId());
+  VVVdouble*   pxy__node = &pxy_[node->getId()];
+  VVVdouble* d2pxy__node = &d2pxy_[node->getId()];
+  VVVdouble larray;
+  computeLikelihoodAtNode_(father, larray);
+  Vdouble* rootLikelihoodsSR = &likelihoodData_->getRootRateSiteLikelihoodArray();
+
+  double d2Li, d2Lic, d2Licx, numerator, denominator;
+
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    VVdouble* _likelihoods_father_node_i = &(*_likelihoods_father_node)[i];
+    VVdouble* larray_i = &larray[i];
+    d2Li = 0;
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _likelihoods_father_node_i_c = &(*_likelihoods_father_node_i)[c];
+      Vdouble* larray_i_c = &(*larray_i)[c];
+      VVdouble*   pxy__node_c = &(*pxy__node)[c];
+      VVdouble* d2pxy__node_c = &(*d2pxy__node)[c];
+      d2Lic = 0;
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        numerator = 0;
+        denominator = 0;
+        Vdouble*   pxy__node_c_x = &(*pxy__node_c)[x];
+        Vdouble* d2pxy__node_c_x = &(*d2pxy__node_c)[x];
+        d2Licx = 0;
+        for (size_t y = 0; y < nbStates_; y++)
+        {
+          numerator   += (*d2pxy__node_c_x)[y] * (*_likelihoods_father_node_i_c)[y];
+          denominator += (*pxy__node_c_x)[y] * (*_likelihoods_father_node_i_c)[y];
+        }
+        d2Licx = denominator == 0. ? 0. : (*larray_i_c)[x] * numerator / denominator;
+        d2Lic += d2Licx;
+      }
+      d2Li += rateDistribution_->getProbability(c) * d2Lic;
+    }
+    (*_d2Likelihoods_node)[i] = d2Li / (*rootLikelihoodsSR)[i];
+  }
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::computeTreeD2Likelihoods()
+{
+  for (size_t k = 0; k < nbNodes_; k++)
+  {
+    computeTreeD2LikelihoodAtNode(nodes_[k]);
+  }
+}
+
+/******************************************************************************/
+
+double DRHomogeneousTreeLikelihood::getSecondOrderDerivative(const std::string& variable) const
+throw (Exception)
+{
+  if (!hasParameter(variable))
+    throw ParameterNotFoundException("DRHomogeneousTreeLikelihood::getSecondOrderDerivative().", variable);
+  if (getRateDistributionParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to rate distribution parameters are not implemented.");
+  }
+  if (getSubstitutionModelParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to substitution model parameters are not implemented.");
+  }
+
+  //
+  // Computation for branch lengths:
+  //
+
+  // Get the node with the branch whose length must be derivated:
+  size_t brI = TextTools::to<size_t>(variable.substr(5));
+  const Node* branch = nodes_[brI];
+  Vdouble* _dLikelihoods_branch = &likelihoodData_->getDLikelihoodArray(branch->getId());
+  Vdouble* _d2Likelihoods_branch = &likelihoodData_->getD2LikelihoodArray(branch->getId());
+  double d2 = 0;
+  const vector<unsigned int>* w = &likelihoodData_->getWeights();
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    d2 += (*w)[i] * ((*_d2Likelihoods_branch)[i] - pow((*_dLikelihoods_branch)[i], 2));
+  }
+  return -d2;
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::resetLikelihoodArrays(const Node* node)
+{
+  for (size_t n = 0; n < node->getNumberOfSons(); n++)
+  {
+    const Node* subNode = node->getSon(n);
+    resetLikelihoodArray(likelihoodData_->getLikelihoodArray(node->getId(), subNode->getId()));
+  }
+  if (node->hasFather())
+  {
+    const Node* father = node->getFather();
+    resetLikelihoodArray(likelihoodData_->getLikelihoodArray(node->getId(), father->getId()));
+  }
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::computeTreeLikelihood()
+{
+  computeSubtreeLikelihoodPostfix(tree_->getRootNode());
+  computeSubtreeLikelihoodPrefix(tree_->getRootNode());
+  computeRootLikelihood();
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::computeSubtreeLikelihoodPostfix(const Node* node)
+{
+//  if(node->isLeaf()) return;
+// cout << node->getId() << "\t" << (node->hasName()?node->getName():"") << endl;
+  if (node->getNumberOfSons() == 0)
+    return;
+
+  // Set all likelihood arrays to 1 for a start:
+  resetLikelihoodArrays(node);
+
+  map<int, VVVdouble>* _likelihoods_node = &likelihoodData_->getLikelihoodArrays(node->getId());
+  size_t nbNodes = node->getNumberOfSons();
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    // For each son node...
+
+    const Node* son = node->getSon(l);
+    VVVdouble* _likelihoods_node_son = &(*_likelihoods_node)[son->getId()];
+
+    if (son->isLeaf())
+    {
+      VVdouble* _likelihoods_leaf = &likelihoodData_->getLeafLikelihoods(son->getId());
+      for (size_t i = 0; i < nbDistinctSites_; i++)
+      {
+        // For each site in the sequence,
+        Vdouble* _likelihoods_leaf_i = &(*_likelihoods_leaf)[i];
+        VVdouble* _likelihoods_node_son_i = &(*_likelihoods_node_son)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          // For each rate classe,
+          Vdouble* _likelihoods_node_son_i_c = &(*_likelihoods_node_son_i)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            // For each initial state,
+            (*_likelihoods_node_son_i_c)[x] = (*_likelihoods_leaf_i)[x];
+          }
+        }
+      }
+    }
+    else
+    {
+      computeSubtreeLikelihoodPostfix(son); // Recursive method:
+      size_t nbSons = son->getNumberOfSons();
+      map<int, VVVdouble>* _likelihoods_son = &likelihoodData_->getLikelihoodArrays(son->getId());
+
+      vector<const VVVdouble*> iLik(nbSons);
+      vector<const VVVdouble*> tProb(nbSons);
+      for (size_t n = 0; n < nbSons; n++)
+      {
+        const Node* sonSon = son->getSon(n);
+        tProb[n] = &pxy_[sonSon->getId()];
+        iLik[n] = &(*_likelihoods_son)[sonSon->getId()];
+      }
+      computeLikelihoodFromArrays(iLik, tProb, *_likelihoods_node_son, nbSons, nbDistinctSites_, nbClasses_, nbStates_, false);
+    }
+  }
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::computeSubtreeLikelihoodPrefix(const Node* node)
+{
+  if (!node->hasFather())
+  {
+    // 'node' is the root of the tree.
+    // Just call the method on each son node:
+    size_t nbSons = node->getNumberOfSons();
+    for (size_t n = 0; n < nbSons; n++)
+    {
+      computeSubtreeLikelihoodPrefix(node->getSon(n));
+    }
+    return;
+  }
+  else
+  {
+    const Node* father = node->getFather();
+    map<int, VVVdouble>* _likelihoods_node = &likelihoodData_->getLikelihoodArrays(node->getId());
+    map<int, VVVdouble>* _likelihoods_father = &likelihoodData_->getLikelihoodArrays(father->getId());
+    VVVdouble* _likelihoods_node_father = &(*_likelihoods_node)[father->getId()];
+    if (node->isLeaf())
+    {
+      resetLikelihoodArray(*_likelihoods_node_father);
+    }
+
+    if (father->isLeaf())
+    {
+      // If the tree is rooted by a leaf
+      VVdouble* _likelihoods_leaf = &likelihoodData_->getLeafLikelihoods(father->getId());
+      for (size_t i = 0; i < nbDistinctSites_; i++)
+      {
+        // For each site in the sequence,
+        Vdouble* _likelihoods_leaf_i = &(*_likelihoods_leaf)[i];
+        VVdouble* _likelihoods_node_father_i = &(*_likelihoods_node_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          // For each rate classe,
+          Vdouble* _likelihoods_node_father_i_c = &(*_likelihoods_node_father_i)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            // For each initial state,
+            (*_likelihoods_node_father_i_c)[x] = (*_likelihoods_leaf_i)[x];
+          }
+        }
+      }
+    }
+    else
+    {
+      vector<const Node*> nodes;
+      // Add brothers:
+      size_t nbFatherSons = father->getNumberOfSons();
+      for (size_t n = 0; n < nbFatherSons; n++)
+      {
+        const Node* son = father->getSon(n);
+        if (son->getId() != node->getId())
+          nodes.push_back(son);  // This is a real brother, not current node!
+      }
+      // Now the real stuff... We've got to compute the likelihoods for the
+      // subtree defined by node 'father'.
+      // This is the same as postfix method, but with different subnodes.
+
+      size_t nbSons = nodes.size(); // In case of a bifurcating tree, this is equal to 1, excepted for the root.
+
+      vector<const VVVdouble*> iLik(nbSons);
+      vector<const VVVdouble*> tProb(nbSons);
+      for (size_t n = 0; n < nbSons; n++)
+      {
+        const Node* fatherSon = nodes[n];
+        tProb[n] = &pxy_[fatherSon->getId()];
+        iLik[n] = &(*_likelihoods_father)[fatherSon->getId()];
+      }
+
+      if (father->hasFather())
+      {
+        const Node* fatherFather = father->getFather();
+        computeLikelihoodFromArrays(iLik, tProb, &(*_likelihoods_father)[fatherFather->getId()], &pxy_[father->getId()], *_likelihoods_node_father, nbSons, nbDistinctSites_, nbClasses_, nbStates_, false);
+      }
+      else
+      {
+        computeLikelihoodFromArrays(iLik, tProb, *_likelihoods_node_father, nbSons, nbDistinctSites_, nbClasses_, nbStates_, false);
+      }
+    }
+
+    if (!father->hasFather())
+    {
+      // We have to account for the root frequencies:
+      for (size_t i = 0; i < nbDistinctSites_; i++)
+      {
+        VVdouble* _likelihoods_node_father_i = &(*_likelihoods_node_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_node_father_i_c = &(*_likelihoods_node_father_i)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            (*_likelihoods_node_father_i_c)[x] *= rootFreqs_[x];
+          }
+        }
+      }
+    }
+
+    // Call the method on each son node:
+    size_t nbNodeSons = node->getNumberOfSons();
+    for (size_t i = 0; i < nbNodeSons; i++)
+    {
+      computeSubtreeLikelihoodPrefix(node->getSon(i)); // Recursive method.
+    }
+  }
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::computeRootLikelihood()
+{
+  const Node* root = tree_->getRootNode();
+  VVVdouble* rootLikelihoods = &likelihoodData_->getRootLikelihoodArray();
+  // Set all likelihoods to 1 for a start:
+  if (root->isLeaf())
+  {
+    VVdouble* leavesLikelihoods_root = &likelihoodData_->getLeafLikelihoods(root->getId());
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* rootLikelihoods_i = &(*rootLikelihoods)[i];
+      Vdouble* leavesLikelihoods_root_i = &(*leavesLikelihoods_root)[i];
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* rootLikelihoods_i_c = &(*rootLikelihoods_i)[c];
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          (*rootLikelihoods_i_c)[x] = (*leavesLikelihoods_root_i)[x];
+        }
+      }
+    }
+  }
+  else
+  {
+    resetLikelihoodArray(*rootLikelihoods);
+  }
+
+  map<int, VVVdouble>* likelihoods_root = &likelihoodData_->getLikelihoodArrays(root->getId());
+  size_t nbNodes = root->getNumberOfSons();
+  vector<const VVVdouble*> iLik(nbNodes);
+  vector<const VVVdouble*> tProb(nbNodes);
+  for (size_t n = 0; n < nbNodes; n++)
+  {
+    const Node* son = root->getSon(n);
+    tProb[n] = &pxy_[son->getId()];
+    iLik[n] = &(*likelihoods_root)[son->getId()];
+  }
+  computeLikelihoodFromArrays(iLik, tProb, *rootLikelihoods, nbNodes, nbDistinctSites_, nbClasses_, nbStates_, false);
+
+  Vdouble p = rateDistribution_->getProbabilities();
+  VVdouble* rootLikelihoodsS  = &likelihoodData_->getRootSiteLikelihoodArray();
+  Vdouble* rootLikelihoodsSR = &likelihoodData_->getRootRateSiteLikelihoodArray();
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    // For each site in the sequence,
+    VVdouble* rootLikelihoods_i = &(*rootLikelihoods)[i];
+    Vdouble* rootLikelihoodsS_i = &(*rootLikelihoodsS)[i];
+    (*rootLikelihoodsSR)[i] = 0;
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      // For each rate classe,
+      Vdouble* rootLikelihoods_i_c = &(*rootLikelihoods_i)[c];
+      double* rootLikelihoodsS_i_c = &(*rootLikelihoodsS_i)[c];
+      (*rootLikelihoodsS_i_c) = 0;
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        // For each initial state,
+        (*rootLikelihoodsS_i_c) += rootFreqs_[x] * (*rootLikelihoods_i_c)[x];
+      }
+      (*rootLikelihoodsSR)[i] += p[c] * (*rootLikelihoodsS_i_c);
+    }
+
+    // Final checking (for numerical errors):
+    if ((*rootLikelihoodsSR)[i] < 0)
+      (*rootLikelihoodsSR)[i] = 0.;
+  }
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::computeLikelihoodAtNode_(const Node* node, VVVdouble& likelihoodArray) const
+{
+  // const Node * node = tree_->getNode(nodeId);
+  int nodeId = node->getId();
+  likelihoodArray.resize(nbDistinctSites_);
+  map<int, VVVdouble>* likelihoods_node = &likelihoodData_->getLikelihoodArrays(nodeId);
+
+  // Initialize likelihood array:
+  if (node->isLeaf())
+  {
+    VVdouble* leavesLikelihoods_node = &likelihoodData_->getLeafLikelihoods(nodeId);
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* likelihoodArray_i = &likelihoodArray[i];
+      Vdouble* leavesLikelihoods_node_i = &(*leavesLikelihoods_node)[i];
+      likelihoodArray_i->resize(nbClasses_);
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* likelihoodArray_i_c = &(*likelihoodArray_i)[c];
+        likelihoodArray_i_c->resize(nbStates_);
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          (*likelihoodArray_i_c)[x] = (*leavesLikelihoods_node_i)[x];
+        }
+      }
+    }
+  }
+  else
+  {
+    // Otherwise:
+    // Set all likelihoods to 1 for a start:
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* likelihoodArray_i = &likelihoodArray[i];
+      likelihoodArray_i->resize(nbClasses_);
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* likelihoodArray_i_c = &(*likelihoodArray_i)[c];
+        likelihoodArray_i_c->resize(nbStates_);
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          (*likelihoodArray_i_c)[x] = 1.;
+        }
+      }
+    }
+  }
+
+  size_t nbNodes = node->getNumberOfSons();
+
+  vector<const VVVdouble*> iLik(nbNodes);
+  vector<const VVVdouble*> tProb(nbNodes);
+  for (size_t n = 0; n < nbNodes; n++)
+  {
+    const Node* son = node->getSon(n);
+    tProb[n] = &pxy_[son->getId()];
+    iLik[n] = &(*likelihoods_node)[son->getId()];
+  }
+
+  if (node->hasFather())
+  {
+    const Node* father = node->getFather();
+    computeLikelihoodFromArrays(iLik, tProb, &(*likelihoods_node)[father->getId()], &pxy_[nodeId], likelihoodArray, nbNodes, nbDistinctSites_, nbClasses_, nbStates_, false);
+  }
+  else
+  {
+    computeLikelihoodFromArrays(iLik, tProb, likelihoodArray, nbNodes, nbDistinctSites_, nbClasses_, nbStates_, false);
+
+    // We have to account for the equilibrium frequencies:
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* likelihoodArray_i = &likelihoodArray[i];
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* likelihoodArray_i_c = &(*likelihoodArray_i)[c];
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          (*likelihoodArray_i_c)[x] *= rootFreqs_[x];
+        }
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::computeLikelihoodFromArrays(
+  const vector<const VVVdouble*>& iLik,
+  const vector<const VVVdouble*>& tProb,
+  VVVdouble& oLik,
+  size_t nbNodes,
+  size_t nbDistinctSites,
+  size_t nbClasses,
+  size_t nbStates,
+  bool reset)
+{
+  if (reset)
+    resetLikelihoodArray(oLik);
+
+  for (size_t n = 0; n < nbNodes; n++)
+  {
+    const VVVdouble* pxy_n = tProb[n];
+    const VVVdouble* iLik_n = iLik[n];
+
+    for (size_t i = 0; i < nbDistinctSites; i++)
+    {
+      // For each site in the sequence,
+      const VVdouble* iLik_n_i = &(*iLik_n)[i];
+      VVdouble* oLik_i = &(oLik)[i];
+
+      for (size_t c = 0; c < nbClasses; c++)
+      {
+        // For each rate classe,
+        const Vdouble* iLik_n_i_c = &(*iLik_n_i)[c];
+        Vdouble* oLik_i_c = &(*oLik_i)[c];
+        const VVdouble* pxy_n_c = &(*pxy_n)[c];
+        for (size_t x = 0; x < nbStates; x++)
+        {
+          // For each initial state,
+          const Vdouble* pxy_n_c_x = &(*pxy_n_c)[x];
+          double likelihood = 0;
+          for (size_t y = 0; y < nbStates; y++)
+          {
+            likelihood += (*pxy_n_c_x)[y] * (*iLik_n_i_c)[y];
+          }
+          // We store this conditionnal likelihood into the corresponding array:
+          (*oLik_i_c)[x] *= likelihood;
+        }
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::computeLikelihoodFromArrays(
+  const vector<const VVVdouble*>& iLik,
+  const vector<const VVVdouble*>& tProb,
+  const VVVdouble* iLikR,
+  const VVVdouble* tProbR,
+  VVVdouble& oLik,
+  size_t nbNodes,
+  size_t nbDistinctSites,
+  size_t nbClasses,
+  size_t nbStates,
+  bool reset)
+{
+  if (reset)
+    resetLikelihoodArray(oLik);
+
+  for (size_t n = 0; n < nbNodes; n++)
+  {
+    const VVVdouble* pxy_n = tProb[n];
+    const VVVdouble* iLik_n = iLik[n];
+
+    for (size_t i = 0; i < nbDistinctSites; i++)
+    {
+      // For each site in the sequence,
+      const VVdouble* iLik_n_i = &(*iLik_n)[i];
+      VVdouble* oLik_i = &(oLik)[i];
+
+      for (size_t c = 0; c < nbClasses; c++)
+      {
+        // For each rate classe,
+        const Vdouble* iLik_n_i_c = &(*iLik_n_i)[c];
+        Vdouble* oLik_i_c = &(*oLik_i)[c];
+        const VVdouble* pxy_n_c = &(*pxy_n)[c];
+        for (size_t x = 0; x < nbStates; x++)
+        {
+          // For each initial state,
+          const Vdouble* pxy_n_c_x = &(*pxy_n_c)[x];
+          double likelihood = 0;
+          for (size_t y = 0; y < nbStates; y++)
+          {
+            // cout << "1:" << (* pxy_n_c_x)[y]  << endl;
+            // cout << "2:" << (* iLik_n_i_c)[y] << endl;
+            likelihood += (*pxy_n_c_x)[y] * (*iLik_n_i_c)[y];
+            // cout << i << "\t" << c << "\t" << x << "\t" << y << "\t" <<  (* pxy__son_c_x)[y] << "\t" << (* likelihoods_root_son_i_c)[y] << endl;
+          }
+          // We store this conditionnal likelihood into the corresponding array:
+          (*oLik_i_c)[x] *= likelihood;
+        }
+      }
+    }
+  }
+
+  // Now deal with the subtree containing the root:
+  for (size_t i = 0; i < nbDistinctSites; i++)
+  {
+    // For each site in the sequence,
+    const VVdouble* iLikR_i = &(*iLikR)[i];
+    VVdouble* oLik_i = &(oLik)[i];
+
+    for (size_t c = 0; c < nbClasses; c++)
+    {
+      // For each rate classe,
+      const Vdouble* iLikR_i_c = &(*iLikR_i)[c];
+      Vdouble* oLik_i_c = &(*oLik_i)[c];
+      const VVdouble* pxyR_c = &(*tProbR)[c];
+      for (size_t x = 0; x < nbStates; x++)
+      {
+        double likelihood = 0;
+        for (size_t y = 0; y < nbStates; y++)
+        {
+          // For each final state,
+          const Vdouble* pxyR_c_y = &(*pxyR_c)[y];
+          likelihood += (*pxyR_c_y)[x] * (*iLikR_i_c)[y];
+        }
+        // We store this conditionnal likelihood into the corresponding array:
+        (*oLik_i_c)[x] *= likelihood;
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+void DRHomogeneousTreeLikelihood::displayLikelihood(const Node* node)
+{
+  cout << "Likelihoods at node " << node->getId() << ": " << endl;
+  for (size_t n = 0; n < node->getNumberOfSons(); n++)
+  {
+    const Node* subNode = node->getSon(n);
+    cout << "Array for sub-node " << subNode->getId() << endl;
+    displayLikelihoodArray(likelihoodData_->getLikelihoodArray(node->getId(), subNode->getId()));
+  }
+  if (node->hasFather())
+  {
+    const Node* father = node->getFather();
+    cout << "Array for father node " << father->getId() << endl;
+    displayLikelihoodArray(likelihoodData_->getLikelihoodArray(node->getId(), father->getId()));
+  }
+  cout << "                                         ***" << endl;
+}
+
+/*******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Likelihood/DRHomogeneousTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/DRHomogeneousTreeLikelihood.h
new file mode 100755
index 0000000..f62cf7b
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DRHomogeneousTreeLikelihood.h
@@ -0,0 +1,312 @@
+//
+// File: DRHomogeneousTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Fri Oct 17 18:14:51 2003
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _DRHOMOGENEOUSTREELIKELIHOOD_H_
+#define _DRHOMOGENEOUSTREELIKELIHOOD_H_
+
+#include "AbstractHomogeneousTreeLikelihood.h"
+#include "DRTreeLikelihood.h"
+#include "DRASDRTreeLikelihoodData.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+
+namespace bpp
+{
+
+/**
+ * @brief This class implements the likelihood computation for a tree using the double-recursive
+ * algorithm.
+ *
+ * The substitution model is the same over the tree (homogeneous model).
+ * A non-uniform distribution of rates among the sites is allowed (ASRV models).</p>
+ *
+ * This class uses an instance of the DRASDRTreeLikelihoodData for conditionnal likelihood storage.
+ *
+ * All nodes share the same site patterns.
+ */
+class DRHomogeneousTreeLikelihood:
+  public AbstractHomogeneousTreeLikelihood,
+  public DRTreeLikelihood
+{
+  private:
+    mutable DRASDRTreeLikelihoodData* likelihoodData_;
+
+  protected:
+    double minusLogLik_;
+    
+  public:
+    /**
+     * @brief Build a new DRHomogeneousTreeLikelihood object without data.
+     *
+     * This constructor only initialize the parameters.
+     * To compute a likelihood, you will need to call the setData() and the computeTreeLikelihood() methods.
+     *
+     * @param tree The tree to use.
+     * @param model The substitution model to use.
+     * @param rDist The rate across sites distribution to use.
+     * @param checkRooted Tell if we have to check for the tree to be unrooted.
+     * If true, any rooted tree will be unrooted before likelihood computation.
+     * @param verbose Should I display some info?
+     * @throw Exception in an error occured.
+     */
+    DRHomogeneousTreeLikelihood(
+      const Tree& tree,
+      SubstitutionModel* model,
+      DiscreteDistribution* rDist,
+      bool checkRooted = true,
+      bool verbose = true)
+      throw (Exception);
+  
+    /**
+     * @brief Build a new DRHomogeneousTreeLikelihood object and compute the corresponding likelihood.
+     *
+     * This constructor initializes all parameters, data, and likelihood arrays.
+     *
+     * @param tree The tree to use.
+     * @param data Sequences to use.
+     * @param model The substitution model to use.
+     * @param rDist The rate across sites distribution to use.
+     * @param checkRooted Tell if we have to check for the tree to be unrooted.
+     * If true, any rooted tree will be unrooted before likelihood computation.
+     * @param verbose Should I display some info?
+     * @throw Exception in an error occured.
+     */
+    DRHomogeneousTreeLikelihood(
+      const Tree& tree,
+      const SiteContainer& data,
+      SubstitutionModel* model,
+      DiscreteDistribution* rDist,
+      bool checkRooted = true,
+      bool verbose = true)
+      throw (Exception);
+
+    /**
+     * @brief Copy constructor.
+     */ 
+    DRHomogeneousTreeLikelihood(const DRHomogeneousTreeLikelihood& lik);
+    
+    DRHomogeneousTreeLikelihood & operator=(const DRHomogeneousTreeLikelihood& lik);
+
+    virtual ~DRHomogeneousTreeLikelihood();
+
+    DRHomogeneousTreeLikelihood* clone() const { return new DRHomogeneousTreeLikelihood(*this); }
+
+  private:
+
+    /**
+     * @brief Method called by constructors.
+     */
+    void init_() throw (Exception);
+
+  public:
+
+    /**
+     * @name The TreeLikelihood interface.
+     *
+     * Other methods are implemented in the AbstractTreeLikelihood class.
+     *
+     * @{
+     */
+    void setData(const SiteContainer & sites) throw (Exception);
+    double getLikelihood () const;
+    double getLogLikelihood() const;
+    double getLikelihoodForASite (size_t site) const;
+    double getLogLikelihoodForASite(size_t site) const;
+    size_t getSiteIndex(size_t site) const throw (IndexOutOfBoundsException) { return likelihoodData_->getRootArrayPosition(site); }
+    /** @} */
+
+    void computeTreeLikelihood();
+
+    
+    /**
+     * @name The DiscreteRatesAcrossSites interface implementation:
+     *
+     * @{
+     */
+    double getLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+    double getLogLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+    double getLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const;
+    double getLogLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const;
+    /** @} */
+  
+    /**
+     * @brief Implements the Function interface.
+     *
+     * Update the parameter list and call the fireParameterChanged() method.
+     *
+     * If a subset of the whole parameter list is passed to the function,
+     * only these parameters are updated and the other remain constant (i.e.
+     * equal to their last value).
+     *
+     * @param parameters The parameter list to pass to the function.
+     */
+    void setParameters(const ParameterList & parameters) throw (ParameterNotFoundException, ConstraintException);
+    
+    /**
+     * @brief Function and NNISearchable interface.
+     */
+    double getValue() const throw (Exception);
+    
+    /**
+     * @name DerivableFirstOrder interface.
+     *
+     * @{
+     */
+    double getFirstOrderDerivative(const std::string& variable) const throw (Exception);
+    /** @{ */
+
+    /**
+     * @name DerivableSecondOrder interface.
+     *
+     * @{
+     */
+    double getSecondOrderDerivative(const std::string& variable) const throw (Exception);
+    double getSecondOrderDerivative(const std::string& variable1, const std::string& variable2) const throw (Exception) { return 0; } // Not implemented for now.
+    /** @} */
+    
+  public:  // Specific methods:
+
+    DRASDRTreeLikelihoodData* getLikelihoodData() { return likelihoodData_; }
+    const DRASDRTreeLikelihoodData* getLikelihoodData() const { return likelihoodData_; }
+  
+    virtual void computeLikelihoodAtNode(int nodeId, VVVdouble& likelihoodArray) const
+    {
+      computeLikelihoodAtNode_(tree_->getNode(nodeId), likelihoodArray);
+    }
+      
+  protected:
+    virtual void computeLikelihoodAtNode_(const Node* node, VVVdouble& likelihoodArray) const;
+  
+    /**
+     * Initialize the arrays corresponding to each son node for the node passed as argument.
+     * The method is called for each son node and the result stored in the corresponding array.
+     */
+    virtual void computeSubtreeLikelihoodPostfix(const Node* node); //Recursive method.
+    /**
+     * This method initilize the remaining likelihood arrays, corresponding to father nodes.
+     * It must be called after the postfix method because it requires that the arrays for
+     * son nodes to be be computed.
+     */
+    virtual void computeSubtreeLikelihoodPrefix(const Node* node); //Recursive method.
+
+    virtual void computeRootLikelihood();
+
+    virtual void computeTreeDLikelihoodAtNode(const Node* node);
+    virtual void computeTreeDLikelihoods();
+    
+    virtual void computeTreeD2LikelihoodAtNode(const Node* node);
+    virtual void computeTreeD2Likelihoods();
+
+    virtual void fireParameterChanged(const ParameterList& params);
+
+    virtual void resetLikelihoodArrays(const Node* node);
+  
+    /**
+     * @brief This method is mainly for debugging purpose.
+     *
+     * @param node The node at which likelihood values must be displayed.
+     */
+    virtual void displayLikelihood(const Node* node);
+
+    /**
+     * @brief Compute conditional likelihoods.
+     *
+     * This method is the "core" likelihood computation function, performing all the product uppon all nodes, the summation for each ancestral state and each rate class.
+     * It is designed for inner usage, and a maximum efficiency, so no checking is performed on the input parameters.
+     * Use with care!
+     * 
+     * @param iLik A vector of likelihood arrays, one for each conditional node.
+     * @param tProb A vector of transition probabilities, one for each node.
+     * @param oLik The likelihood array to store the computed likelihoods.
+     * @param nbNodes The number of nodes = the size of the input vectors.
+     * @param nbDistinctSites The number of distinct sites (the first dimension of the likelihood array).
+     * @param nbClasses The number of rate classes (the second dimension of the likelihood array).
+     * @param nbStates The number of states (the third dimension of the likelihood array).
+     * @param reset Tell if the output likelihood array must be initalized prior to computation.
+     * If true, the resetLikelihoodArray method will be called.
+     */
+    static void computeLikelihoodFromArrays(
+        const std::vector<const VVVdouble*>& iLik,
+        const std::vector<const VVVdouble*>& tProb,
+        VVVdouble& oLik, size_t nbNodes,
+        size_t nbDistinctSites,
+        size_t nbClasses,
+        size_t nbStates,
+        bool reset = true);
+
+    /**
+     * @brief Compute conditional likelihoods.
+     *
+     * This method is the "core" likelihood computation function, performing all the product uppon all nodes, the summation for each ancestral state and each rate class.
+     * This function is specific to non-reversible models: the subtree containing the root is specified separately.
+     * It is designed for inner usage, and a maximum efficiency, so no checking is performed on the input parameters.
+     * Use with care!
+     * 
+     * @param iLik A vector of likelihood arrays, one for each conditional node.
+     * @param tProb A vector of transition probabilities, one for each node.
+     * @param iLikR The likelihood array for the subtree containing the root of the tree.
+     * @param tProbR The transition probabilities for thr subtree containing the root of the tree.
+     * @param oLik The likelihood array to store the computed likelihoods.
+     * @param nbNodes The number of nodes = the size of the input vectors.
+     * @param nbDistinctSites The number of distinct sites (the first dimension of the likelihood array).
+     * @param nbClasses The number of rate classes (the second dimension of the likelihood array).
+     * @param nbStates The number of states (the third dimension of the likelihood array).
+     * @param reset Tell if the output likelihood array must be initalized prior to computation.
+     * If true, the resetLikelihoodArray method will be called.
+     */
+    static void computeLikelihoodFromArrays(
+        const std::vector<const VVVdouble*>& iLik,
+        const std::vector<const VVVdouble*>& tProb,
+        const VVVdouble* iLikR,
+        const VVVdouble* tProbR,
+        VVVdouble& oLik,
+        size_t nbNodes,
+        size_t nbDistinctSites,
+        size_t nbClasses,
+        size_t nbStates,
+        bool reset = true);
+
+  friend class DRHomogeneousMixedTreeLikelihood;
+};
+
+} //end of namespace bpp.
+
+#endif  //_DRHOMOGENEOUSTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/DRNonHomogeneousTreeLikelihood.cpp b/src/Bpp/Phyl/Likelihood/DRNonHomogeneousTreeLikelihood.cpp
new file mode 100644
index 0000000..25b3ec1
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DRNonHomogeneousTreeLikelihood.cpp
@@ -0,0 +1,1336 @@
+//
+// File: DRNonHomogeneousTreeLikelihood.cpp
+// Created by: Julien Dutheil
+// Created on: Fri Oct 17 18:14:51 2003
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "DRNonHomogeneousTreeLikelihood.h"
+#include "../PatternTools.h"
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/App/ApplicationTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/SiteTools.h>
+#include <Bpp/Seq/Container/AlignedSequenceContainer.h>
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+
+using namespace std;
+
+/******************************************************************************/
+
+DRNonHomogeneousTreeLikelihood::DRNonHomogeneousTreeLikelihood(
+  const Tree& tree,
+  SubstitutionModelSet* modelSet,
+  DiscreteDistribution* rDist,
+  bool verbose,
+  bool reparametrizeRoot)
+throw (Exception) :
+  AbstractNonHomogeneousTreeLikelihood(tree, modelSet, rDist, verbose, reparametrizeRoot),
+  likelihoodData_(0),
+  minusLogLik_(-1.)
+{
+  if (!modelSet->isFullySetUpFor(tree))
+    throw Exception("DRNonHomogeneousTreeLikelihood(constructor). Model set is not fully specified.");
+  init_();
+}
+
+/******************************************************************************/
+
+DRNonHomogeneousTreeLikelihood::DRNonHomogeneousTreeLikelihood(
+  const Tree& tree,
+  const SiteContainer& data,
+  SubstitutionModelSet* modelSet,
+  DiscreteDistribution* rDist,
+  bool verbose,
+  bool reparametrizeRoot)
+throw (Exception) :
+  AbstractNonHomogeneousTreeLikelihood(tree, modelSet, rDist, verbose, reparametrizeRoot),
+  likelihoodData_(0),
+  minusLogLik_(-1.)
+{
+  if (!modelSet->isFullySetUpFor(tree))
+    throw Exception("DRNonHomogeneousTreeLikelihood(constructor). Model set is not fully specified.");
+  init_();
+  setData(data);
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::init_() throw (Exception)
+{
+  likelihoodData_ = new DRASDRTreeLikelihoodData(
+    tree_,
+    rateDistribution_->getNumberOfCategories());
+}
+
+/******************************************************************************/
+
+DRNonHomogeneousTreeLikelihood::DRNonHomogeneousTreeLikelihood(const DRNonHomogeneousTreeLikelihood& lik) :
+  AbstractNonHomogeneousTreeLikelihood(lik),
+  likelihoodData_(0),
+  minusLogLik_(lik.minusLogLik_)
+{
+  likelihoodData_ = dynamic_cast<DRASDRTreeLikelihoodData*>(lik.likelihoodData_->clone());
+  likelihoodData_->setTree(tree_);
+}
+
+/******************************************************************************/
+
+DRNonHomogeneousTreeLikelihood& DRNonHomogeneousTreeLikelihood::operator=(const DRNonHomogeneousTreeLikelihood& lik)
+{
+  AbstractNonHomogeneousTreeLikelihood::operator=(lik);
+  if (likelihoodData_)
+    delete likelihoodData_;
+  likelihoodData_ = dynamic_cast<DRASDRTreeLikelihoodData*>(lik.likelihoodData_->clone());
+  likelihoodData_->setTree(tree_);
+  minusLogLik_ = lik.minusLogLik_;
+  return *this;
+}
+
+/******************************************************************************/
+
+DRNonHomogeneousTreeLikelihood::~DRNonHomogeneousTreeLikelihood()
+{
+  delete likelihoodData_;
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::setData(const SiteContainer& sites) throw (Exception)
+{
+  if (data_)
+    delete data_;
+  data_ = PatternTools::getSequenceSubset(sites, *tree_->getRootNode());
+  if (verbose_)
+    ApplicationTools::displayTask("Initializing data structure");
+  likelihoodData_->initLikelihoods(*data_, *modelSet_->getModel(0)); // We assume here that all models have the same number of states, and that they have the same 'init' method,
+                                                                     // Which is a reasonable assumption as long as they share the same alphabet.
+  if (verbose_)
+    ApplicationTools::displayTaskDone();
+
+  nbSites_         = likelihoodData_->getNumberOfSites();
+  nbDistinctSites_ = likelihoodData_->getNumberOfDistinctSites();
+  nbStates_        = likelihoodData_->getNumberOfStates();
+
+  if (verbose_)
+    ApplicationTools::displayResult("Number of distinct sites",
+                                    TextTools::toString(nbDistinctSites_));
+  initialized_ = false;
+}
+
+/******************************************************************************/
+
+double DRNonHomogeneousTreeLikelihood::getLikelihood() const
+{
+  double l = 1.;
+  Vdouble* lik = &likelihoodData_->getRootRateSiteLikelihoodArray();
+  const vector<unsigned int>* w = &likelihoodData_->getWeights();
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    l *= std::pow((*lik)[i], (int)(*w)[i]);
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+double DRNonHomogeneousTreeLikelihood::getLogLikelihood() const
+{
+  double ll = 0;
+  Vdouble* lik = &likelihoodData_->getRootRateSiteLikelihoodArray();
+  const vector<unsigned int>* w = &likelihoodData_->getWeights();
+  vector<double> la(nbDistinctSites_);
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    la[i] = (*w)[i] * log((*lik)[i]);
+  }
+  sort(la.begin(), la.end());
+  for (size_t i = nbDistinctSites_; i > 0; i--)
+  {
+    ll += la[i - 1];
+  }
+  return ll;
+}
+
+/******************************************************************************/
+
+double DRNonHomogeneousTreeLikelihood::getLikelihoodForASite(size_t site) const
+{
+  return likelihoodData_->getRootRateSiteLikelihoodArray()[likelihoodData_->getRootArrayPosition(site)];
+}
+
+/******************************************************************************/
+
+double DRNonHomogeneousTreeLikelihood::getLogLikelihoodForASite(size_t site) const
+{
+  return log(likelihoodData_->getRootRateSiteLikelihoodArray()[likelihoodData_->getRootArrayPosition(site)]);
+}
+
+/******************************************************************************/
+double DRNonHomogeneousTreeLikelihood::getLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  return likelihoodData_->getRootSiteLikelihoodArray()[likelihoodData_->getRootArrayPosition(site)][rateClass];
+}
+
+/******************************************************************************/
+
+double DRNonHomogeneousTreeLikelihood::getLogLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  return log(likelihoodData_->getRootSiteLikelihoodArray()[likelihoodData_->getRootArrayPosition(site)][rateClass]);
+}
+
+/******************************************************************************/
+
+double DRNonHomogeneousTreeLikelihood::getLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const
+{
+  return likelihoodData_->getRootLikelihoodArray()[likelihoodData_->getRootArrayPosition(site)][rateClass][state];
+}
+
+/******************************************************************************/
+
+double DRNonHomogeneousTreeLikelihood::getLogLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const
+{
+  return log(likelihoodData_->getRootLikelihoodArray()[likelihoodData_->getRootArrayPosition(site)][rateClass][state]);
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::setParameters(const ParameterList& parameters)
+throw (ParameterNotFoundException, ConstraintException)
+{
+  setParametersValues(parameters);
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::fireParameterChanged(const ParameterList& params)
+{
+  applyParameters();
+
+  if (params.getCommonParametersWith(rateDistribution_->getIndependentParameters()).size() > 0)
+  {
+    computeAllTransitionProbabilities();
+  }
+  else
+  {
+    vector<int> ids;
+    vector<string> tmp = params.getCommonParametersWith(modelSet_->getNodeParameters()).getParameterNames();
+    for (size_t i = 0; i < tmp.size(); i++)
+    {
+      vector<int> tmpv = modelSet_->getNodesWithParameter(tmp[i]);
+      ids = VectorTools::vectorUnion(ids, tmpv);
+    }
+    tmp = params.getCommonParametersWith(brLenParameters_).getParameterNames();
+    vector<const Node*> nodes;
+    for (size_t i = 0; i < ids.size(); i++)
+    {
+      nodes.push_back(idToNode_[ids[i]]);
+    }
+    vector<const Node*> tmpv;
+    bool test = false;
+    for (size_t i = 0; i < tmp.size(); i++)
+    {
+      if (tmp[i] == "BrLenRoot" || tmp[i] == "RootPosition")
+      {
+        if (!test)
+        {
+          tmpv.push_back(tree_->getRootNode()->getSon(0));
+          tmpv.push_back(tree_->getRootNode()->getSon(1));
+          test = true; // Add only once.
+        }
+      }
+      else
+        tmpv.push_back(nodes_[TextTools::to < size_t > (tmp[i].substr(5))]);
+    }
+    nodes = VectorTools::vectorUnion(nodes, tmpv);
+
+    for (size_t i = 0; i < nodes.size(); i++)
+    {
+      computeTransitionProbabilitiesForNode(nodes[i]);
+    }
+    rootFreqs_ = modelSet_->getRootFrequencies();
+  }
+  computeTreeLikelihood();
+  if (computeFirstOrderDerivatives_)
+  {
+    computeTreeDLikelihoods();
+  }
+  if (computeSecondOrderDerivatives_)
+  {
+    computeTreeD2Likelihoods();
+  }
+}
+
+/******************************************************************************/
+
+double DRNonHomogeneousTreeLikelihood::getValue() const
+throw (Exception)
+{
+  if (!isInitialized())
+    throw Exception("DRNonHomogeneousTreeLikelihood::getValue(). Instance is not initialized.");
+  return -getLogLikelihood();
+}
+
+/******************************************************************************
+*                           First Order Derivatives                          *
+******************************************************************************/
+void DRNonHomogeneousTreeLikelihood::computeTreeDLikelihoodAtNode(const Node* node)
+{
+  const Node* father = node->getFather();
+  VVVdouble* _likelihoods_father_node = &likelihoodData_->getLikelihoodArray(father->getId(), node->getId());
+  Vdouble* _dLikelihoods_node = &likelihoodData_->getDLikelihoodArray(node->getId());
+  VVVdouble*  pxy__node = &pxy_[node->getId()];
+  VVVdouble* dpxy__node = &dpxy_[node->getId()];
+  VVVdouble larray;
+  computeLikelihoodAtNode_(father, larray);
+  Vdouble* rootLikelihoodsSR = &likelihoodData_->getRootRateSiteLikelihoodArray();
+
+  double dLi, dLic, dLicx, numerator, denominator;
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    VVdouble* _likelihoods_father_node_i = &(*_likelihoods_father_node)[i];
+    VVdouble* larray_i = &larray[i];
+    dLi = 0;
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _likelihoods_father_node_i_c = &(*_likelihoods_father_node_i)[c];
+      Vdouble* larray_i_c = &(*larray_i)[c];
+      VVdouble*  pxy__node_c = &(*pxy__node)[c];
+      VVdouble* dpxy__node_c = &(*dpxy__node)[c];
+      dLic = 0;
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        numerator = 0;
+        denominator = 0;
+        Vdouble*  pxy__node_c_x = &(*pxy__node_c)[x];
+        Vdouble* dpxy__node_c_x = &(*dpxy__node_c)[x];
+        dLicx = 0;
+        for (size_t y = 0; y < nbStates_; y++)
+        {
+          numerator   += (*dpxy__node_c_x)[y] * (*_likelihoods_father_node_i_c)[y];
+          denominator += (*pxy__node_c_x)[y] * (*_likelihoods_father_node_i_c)[y];
+        }
+        dLicx = denominator == 0. ? 0. : (*larray_i_c)[x] * numerator / denominator;
+        dLic += dLicx;
+      }
+      dLi += rateDistribution_->getProbability(c) * dLic;
+    }
+    (*_dLikelihoods_node)[i] = dLi / (*rootLikelihoodsSR)[i];
+  }
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::computeTreeDLikelihoods()
+{
+  for (size_t k = 0; k < nbNodes_; k++)
+  {
+    computeTreeDLikelihoodAtNode(nodes_[k]);
+  }
+}
+
+/******************************************************************************/
+
+double DRNonHomogeneousTreeLikelihood::getFirstOrderDerivative(const string& variable) const
+throw (Exception)
+{
+  if (!hasParameter(variable))
+    throw ParameterNotFoundException("DRNonHomogeneousTreeLikelihood::getFirstOrderDerivative().", variable);
+  if (getRateDistributionParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to rate distribution parameters are not implemented.");
+  }
+  if (getSubstitutionModelParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to substitution model parameters are not implemented.");
+  }
+
+  //
+  // Computation for branch lengths:
+  //
+  const vector<unsigned int>* w = &likelihoodData_->getWeights();
+  Vdouble* _dLikelihoods_branch;
+  if (variable == "BrLenRoot")
+  {
+    _dLikelihoods_branch = &likelihoodData_->getDLikelihoodArray(root1_);
+    double d1 = 0;
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      d1 -= (*w)[i] * (*_dLikelihoods_branch)[i];
+    }
+    _dLikelihoods_branch = &likelihoodData_->getDLikelihoodArray(root2_);
+    double d2 = 0;
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      d2 -= (*w)[i] * (*_dLikelihoods_branch)[i];
+    }
+    double pos = getParameterValue("RootPosition");
+    return pos * d1 + (1. - pos) * d2;
+  }
+  else if (variable == "RootPosition")
+  {
+    _dLikelihoods_branch = &likelihoodData_->getDLikelihoodArray(root1_);
+    double d1 = 0;
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      d1 -= (*w)[i] * (*_dLikelihoods_branch)[i];
+    }
+    _dLikelihoods_branch = &likelihoodData_->getDLikelihoodArray(root2_);
+    double d2 = 0;
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      d2 -= (*w)[i] * (*_dLikelihoods_branch)[i];
+    }
+    double len = getParameterValue("BrLenRoot");
+    return len * (d1 - d2);
+  }
+  else
+  {
+    // Get the node with the branch whose length must be derivated:
+    size_t brI = TextTools::to<size_t>(variable.substr(5));
+    const Node* branch = nodes_[brI];
+    _dLikelihoods_branch = &likelihoodData_->getDLikelihoodArray(branch->getId());
+    double d = 0;
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      d += (*w)[i] * (*_dLikelihoods_branch)[i];
+    }
+    return -d;
+  }
+}
+
+/******************************************************************************
+*                           Second Order Derivatives                         *
+******************************************************************************/
+void DRNonHomogeneousTreeLikelihood::computeTreeD2LikelihoodAtNode(const Node* node)
+{
+  const Node* father = node->getFather();
+  VVVdouble* _likelihoods_father_node = &likelihoodData_->getLikelihoodArray(father->getId(), node->getId());
+  Vdouble* _d2Likelihoods_node = &likelihoodData_->getD2LikelihoodArray(node->getId());
+  VVVdouble*   pxy__node = &pxy_[node->getId()];
+  VVVdouble* d2pxy__node = &d2pxy_[node->getId()];
+  VVVdouble larray;
+  computeLikelihoodAtNode_(father, larray);
+  Vdouble* rootLikelihoodsSR = &likelihoodData_->getRootRateSiteLikelihoodArray();
+
+  double d2Li, d2Lic, d2Licx, numerator, denominator;
+
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    VVdouble* _likelihoods_father_node_i = &(*_likelihoods_father_node)[i];
+    VVdouble* larray_i = &larray[i];
+    d2Li = 0;
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _likelihoods_father_node_i_c = &(*_likelihoods_father_node_i)[c];
+      Vdouble* larray_i_c = &(*larray_i)[c];
+      VVdouble*   pxy__node_c = &(*pxy__node)[c];
+      VVdouble* d2pxy__node_c = &(*d2pxy__node)[c];
+      d2Lic = 0;
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        numerator = 0;
+        denominator = 0;
+        Vdouble*   pxy__node_c_x = &(*pxy__node_c)[x];
+        Vdouble* d2pxy__node_c_x = &(*d2pxy__node_c)[x];
+        d2Licx = 0;
+        for (size_t y = 0; y < nbStates_; y++)
+        {
+          numerator   += (*d2pxy__node_c_x)[y] * (*_likelihoods_father_node_i_c)[y];
+          denominator += (*pxy__node_c_x)[y] * (*_likelihoods_father_node_i_c)[y];
+        }
+        d2Licx = denominator == 0. ? 0. : (*larray_i_c)[x] * numerator / denominator;
+        d2Lic += d2Licx;
+      }
+      d2Li += rateDistribution_->getProbability(c) * d2Lic;
+    }
+    (*_d2Likelihoods_node)[i] = d2Li / (*rootLikelihoodsSR)[i];
+  }
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::computeTreeD2Likelihoods()
+{
+  for (size_t k = 0; k < nbNodes_; k++)
+  {
+    computeTreeD2LikelihoodAtNode(nodes_[k]);
+  }
+}
+
+/******************************************************************************/
+
+double DRNonHomogeneousTreeLikelihood::getSecondOrderDerivative(const string& variable) const
+throw (Exception)
+{
+  if (!hasParameter(variable))
+    throw ParameterNotFoundException("DRNonHomogeneousTreeLikelihood::getSecondOrderDerivative().", variable);
+  if (getRateDistributionParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to rate distribution parameters are not implemented.");
+  }
+  if (getSubstitutionModelParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to substitution model parameters are not implemented.");
+  }
+
+  //
+  // Computation for branch lengths:
+  //
+
+  const vector<unsigned int>* w = &likelihoodData_->getWeights();
+  // We can't deduce second order derivatives regarding BrLenRoot and RootPosition from the
+  // branch length derivatives. We need a bit more calculations...
+  // NB: we could save a few calculations here...
+  if (variable == "BrLenRoot")
+  {
+    const Node* father = tree_->getRootNode();
+
+    // Compute dLikelihoods array for the father node.
+    // Fist initialize to 1:
+    VVVdouble dLikelihoods_father(nbDistinctSites_);
+    VVVdouble d2Likelihoods_father(nbDistinctSites_);
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* dLikelihoods_father_i = &dLikelihoods_father[i];
+      VVdouble* d2Likelihoods_father_i = &d2Likelihoods_father[i];
+      dLikelihoods_father_i->resize(nbClasses_);
+      d2Likelihoods_father_i->resize(nbClasses_);
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* dLikelihoods_father_i_c = &(*dLikelihoods_father_i)[c];
+        Vdouble* d2Likelihoods_father_i_c = &(*d2Likelihoods_father_i)[c];
+        dLikelihoods_father_i_c->resize(nbStates_);
+        d2Likelihoods_father_i_c->resize(nbStates_);
+        for (size_t s = 0; s < nbStates_; s++)
+        {
+          (*dLikelihoods_father_i_c)[s] = 1.;
+          (*d2Likelihoods_father_i_c)[s] = 1.;
+        }
+      }
+    }
+
+    size_t nbNodes = father->getNumberOfSons();
+    for (size_t l = 0; l < nbNodes; l++)
+    {
+      const Node* son = father->getSon(l);
+
+      if (son->getId() == root1_)
+      {
+        VVVdouble* _likelihoodsroot1_ = &likelihoodData_->getLikelihoodArray(father->getId(), root1_);
+        VVVdouble* _likelihoodsroot2_ = &likelihoodData_->getLikelihoodArray(father->getId(), root2_);
+        double pos = getParameterValue("RootPosition");
+
+        VVVdouble* d2pxy_root1_ = &d2pxy_[root1_];
+        VVVdouble* d2pxy_root2_ = &d2pxy_[root2_];
+        VVVdouble* dpxy_root1_  = &dpxy_[root1_];
+        VVVdouble* dpxy_root2_  = &dpxy_[root2_];
+        VVVdouble* pxy_root1_   = &pxy_[root1_];
+        VVVdouble* pxy_root2_   = &pxy_[root2_];
+        for (size_t i = 0; i < nbDistinctSites_; i++)
+        {
+          VVdouble* _likelihoodsroot1__i = &(*_likelihoodsroot1_)[i];
+          VVdouble* _likelihoodsroot2__i = &(*_likelihoodsroot2_)[i];
+          VVdouble* dLikelihoods_father_i = &dLikelihoods_father[i];
+          VVdouble* d2Likelihoods_father_i = &d2Likelihoods_father[i];
+          for (size_t c = 0; c < nbClasses_; c++)
+          {
+            Vdouble* _likelihoodsroot1__i_c = &(*_likelihoodsroot1__i)[c];
+            Vdouble* _likelihoodsroot2__i_c = &(*_likelihoodsroot2__i)[c];
+            Vdouble* dLikelihoods_father_i_c = &(*dLikelihoods_father_i)[c];
+            Vdouble* d2Likelihoods_father_i_c = &(*d2Likelihoods_father_i)[c];
+            VVdouble* d2pxy_root1__c = &(*d2pxy_root1_)[c];
+            VVdouble* d2pxy_root2__c = &(*d2pxy_root2_)[c];
+            VVdouble* dpxy_root1__c  = &(*dpxy_root1_)[c];
+            VVdouble* dpxy_root2__c  = &(*dpxy_root2_)[c];
+            VVdouble* pxy_root1__c   = &(*pxy_root1_)[c];
+            VVdouble* pxy_root2__c   = &(*pxy_root2_)[c];
+            for (size_t x = 0; x < nbStates_; x++)
+            {
+              Vdouble* d2pxy_root1__c_x = &(*d2pxy_root1__c)[x];
+              Vdouble* d2pxy_root2__c_x = &(*d2pxy_root2__c)[x];
+              Vdouble* dpxy_root1__c_x  = &(*dpxy_root1__c)[x];
+              Vdouble* dpxy_root2__c_x  = &(*dpxy_root2__c)[x];
+              Vdouble* pxy_root1__c_x   = &(*pxy_root1__c)[x];
+              Vdouble* pxy_root2__c_x   = &(*pxy_root2__c)[x];
+              double d2l1 = 0, d2l2 = 0, dl1 = 0, dl2 = 0, l1 = 0, l2 = 0;
+              for (size_t y = 0; y < nbStates_; y++)
+              {
+                d2l1 += (*d2pxy_root1__c_x)[y] * (*_likelihoodsroot1__i_c)[y];
+                d2l2 += (*d2pxy_root2__c_x)[y] * (*_likelihoodsroot2__i_c)[y];
+                dl1  += (*dpxy_root1__c_x)[y]  * (*_likelihoodsroot1__i_c)[y];
+                dl2  += (*dpxy_root2__c_x)[y]  * (*_likelihoodsroot2__i_c)[y];
+                l1   += (*pxy_root1__c_x)[y]   * (*_likelihoodsroot1__i_c)[y];
+                l2   += (*pxy_root2__c_x)[y]   * (*_likelihoodsroot2__i_c)[y];
+              }
+              double dl = pos * dl1 * l2 + (1. - pos) * dl2 * l1;
+              double d2l = pos * pos * d2l1 * l2 + (1. - pos) * (1. - pos) * d2l2 * l1 + 2 * pos * (1. - pos) * dl1 * dl2;
+              (*dLikelihoods_father_i_c)[x] *= dl;
+              (*d2Likelihoods_father_i_c)[x] *= d2l;
+            }
+          }
+        }
+      }
+      else if (son->getId() == root2_)
+      {
+        // Do nothing, this was accounted when dealing with root1_
+      }
+      else
+      {
+        // Account for a putative multifurcation:
+        VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(father->getId(), son->getId());
+
+        VVVdouble* pxy__son = &pxy_[son->getId()];
+        for (size_t i = 0; i < nbDistinctSites_; i++)
+        {
+          VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[i];
+          VVdouble* dLikelihoods_father_i = &dLikelihoods_father[i];
+          VVdouble* d2Likelihoods_father_i = &d2Likelihoods_father[i];
+          for (size_t c = 0; c < nbClasses_; c++)
+          {
+            Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+            Vdouble* dLikelihoods_father_i_c = &(*dLikelihoods_father_i)[c];
+            Vdouble* d2Likelihoods_father_i_c = &(*d2Likelihoods_father_i)[c];
+            VVdouble* pxy__son_c = &(*pxy__son)[c];
+            for (size_t x = 0; x < nbStates_; x++)
+            {
+              double dl = 0;
+              Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+              for (size_t y = 0; y < nbStates_; y++)
+              {
+                dl += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+              }
+              (*dLikelihoods_father_i_c)[x] *= dl;
+              (*d2Likelihoods_father_i_c)[x] *= dl;
+            }
+          }
+        }
+      }
+    }
+    Vdouble* rootLikelihoodsSR = &likelihoodData_->getRootRateSiteLikelihoodArray();
+    double d2l = 0, dlx, d2lx;
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* dLikelihoods_father_i = &dLikelihoods_father[i];
+      VVdouble* d2Likelihoods_father_i = &d2Likelihoods_father[i];
+      dlx = 0, d2lx = 0;
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* dLikelihoods_father_i_c = &(*dLikelihoods_father_i)[c];
+        Vdouble* d2Likelihoods_father_i_c = &(*d2Likelihoods_father_i)[c];
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          dlx += rateDistribution_->getProbability(c) * rootFreqs_[x] * (*dLikelihoods_father_i_c)[x];
+          d2lx += rateDistribution_->getProbability(c) * rootFreqs_[x] * (*d2Likelihoods_father_i_c)[x];
+        }
+      }
+      d2l += (*w)[i] * (d2lx / (*rootLikelihoodsSR)[i] - pow(dlx / (*rootLikelihoodsSR)[i], 2));
+    }
+    return -d2l;
+  }
+  else if (variable == "RootPosition")
+  {
+    const Node* father = tree_->getRootNode();
+
+    // Compute dLikelihoods array for the father node.
+    // Fist initialize to 1:
+    VVVdouble dLikelihoods_father(nbDistinctSites_);
+    VVVdouble d2Likelihoods_father(nbDistinctSites_);
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* dLikelihoods_father_i = &dLikelihoods_father[i];
+      VVdouble* d2Likelihoods_father_i = &d2Likelihoods_father[i];
+      dLikelihoods_father_i->resize(nbClasses_);
+      d2Likelihoods_father_i->resize(nbClasses_);
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* dLikelihoods_father_i_c = &(*dLikelihoods_father_i)[c];
+        Vdouble* d2Likelihoods_father_i_c = &(*d2Likelihoods_father_i)[c];
+        dLikelihoods_father_i_c->resize(nbStates_);
+        d2Likelihoods_father_i_c->resize(nbStates_);
+        for (size_t s = 0; s < nbStates_; s++)
+        {
+          (*dLikelihoods_father_i_c)[s] = 1.;
+          (*d2Likelihoods_father_i_c)[s] = 1.;
+        }
+      }
+    }
+
+    size_t nbNodes = father->getNumberOfSons();
+    for (size_t l = 0; l < nbNodes; l++)
+    {
+      const Node* son = father->getSon(l);
+
+      if (son->getId() == root1_)
+      {
+        VVVdouble* _likelihoodsroot1_ = &likelihoodData_->getLikelihoodArray(father->getId(), root1_);
+        VVVdouble* _likelihoodsroot2_ = &likelihoodData_->getLikelihoodArray(father->getId(), root2_);
+        double len = getParameterValue("BrLenRoot");
+
+        VVVdouble* d2pxy_root1_ = &d2pxy_[root1_];
+        VVVdouble* d2pxy_root2_ = &d2pxy_[root2_];
+        VVVdouble* dpxy_root1_  = &dpxy_[root1_];
+        VVVdouble* dpxy_root2_  = &dpxy_[root2_];
+        VVVdouble* pxy_root1_   = &pxy_[root1_];
+        VVVdouble* pxy_root2_   = &pxy_[root2_];
+        for (size_t i = 0; i < nbDistinctSites_; i++)
+        {
+          VVdouble* _likelihoodsroot1__i = &(*_likelihoodsroot1_)[i];
+          VVdouble* _likelihoodsroot2__i = &(*_likelihoodsroot2_)[i];
+          VVdouble* dLikelihoods_father_i = &dLikelihoods_father[i];
+          VVdouble* d2Likelihoods_father_i = &d2Likelihoods_father[i];
+          for (size_t c = 0; c < nbClasses_; c++)
+          {
+            Vdouble* _likelihoodsroot1__i_c = &(*_likelihoodsroot1__i)[c];
+            Vdouble* _likelihoodsroot2__i_c = &(*_likelihoodsroot2__i)[c];
+            Vdouble* dLikelihoods_father_i_c = &(*dLikelihoods_father_i)[c];
+            Vdouble* d2Likelihoods_father_i_c = &(*d2Likelihoods_father_i)[c];
+            VVdouble* d2pxy_root1__c = &(*d2pxy_root1_)[c];
+            VVdouble* d2pxy_root2__c = &(*d2pxy_root2_)[c];
+            VVdouble* dpxy_root1__c  = &(*dpxy_root1_)[c];
+            VVdouble* dpxy_root2__c  = &(*dpxy_root2_)[c];
+            VVdouble* pxy_root1__c   = &(*pxy_root1_)[c];
+            VVdouble* pxy_root2__c   = &(*pxy_root2_)[c];
+            for (size_t x = 0; x < nbStates_; x++)
+            {
+              Vdouble* d2pxy_root1__c_x = &(*d2pxy_root1__c)[x];
+              Vdouble* d2pxy_root2__c_x = &(*d2pxy_root2__c)[x];
+              Vdouble* dpxy_root1__c_x  = &(*dpxy_root1__c)[x];
+              Vdouble* dpxy_root2__c_x  = &(*dpxy_root2__c)[x];
+              Vdouble* pxy_root1__c_x   = &(*pxy_root1__c)[x];
+              Vdouble* pxy_root2__c_x   = &(*pxy_root2__c)[x];
+              double d2l1 = 0, d2l2 = 0, dl1 = 0, dl2 = 0, l1 = 0, l2 = 0;
+              for (size_t y = 0; y < nbStates_; y++)
+              {
+                d2l1 += (*d2pxy_root1__c_x)[y] * (*_likelihoodsroot1__i_c)[y];
+                d2l2 += (*d2pxy_root2__c_x)[y] * (*_likelihoodsroot2__i_c)[y];
+                dl1  += (*dpxy_root1__c_x)[y]  * (*_likelihoodsroot1__i_c)[y];
+                dl2  += (*dpxy_root2__c_x)[y]  * (*_likelihoodsroot2__i_c)[y];
+                l1   += (*pxy_root1__c_x)[y]   * (*_likelihoodsroot1__i_c)[y];
+                l2   += (*pxy_root2__c_x)[y]   * (*_likelihoodsroot2__i_c)[y];
+              }
+              double dl = len * (dl1 * l2 - dl2 * l1);
+              double d2l = len * len * (d2l1 * l2 + d2l2 * l1 - 2 * dl1 * dl2);
+              (*dLikelihoods_father_i_c)[x] *= dl;
+              (*d2Likelihoods_father_i_c)[x] *= d2l;
+            }
+          }
+        }
+      }
+      else if (son->getId() == root2_)
+      {
+        // Do nothing, this was accounted when dealing with root1_
+      }
+      else
+      {
+        // Account for a putative multifurcation:
+        VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(father->getId(), son->getId());
+
+        VVVdouble* pxy__son = &pxy_[son->getId()];
+        for (size_t i = 0; i < nbDistinctSites_; i++)
+        {
+          VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[i];
+          VVdouble* dLikelihoods_father_i = &dLikelihoods_father[i];
+          VVdouble* d2Likelihoods_father_i = &d2Likelihoods_father[i];
+          for (size_t c = 0; c < nbClasses_; c++)
+          {
+            Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+            Vdouble* dLikelihoods_father_i_c = &(*dLikelihoods_father_i)[c];
+            Vdouble* d2Likelihoods_father_i_c = &(*d2Likelihoods_father_i)[c];
+            VVdouble* pxy__son_c = &(*pxy__son)[c];
+            for (size_t x = 0; x < nbStates_; x++)
+            {
+              double dl = 0;
+              Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+              for (size_t y = 0; y < nbStates_; y++)
+              {
+                dl += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+              }
+              (*dLikelihoods_father_i_c)[x] *= dl;
+              (*d2Likelihoods_father_i_c)[x] *= dl;
+            }
+          }
+        }
+      }
+    }
+    Vdouble* rootLikelihoodsSR = &likelihoodData_->getRootRateSiteLikelihoodArray();
+    double d2l = 0, dlx, d2lx;
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* dLikelihoods_father_i = &dLikelihoods_father[i];
+      VVdouble* d2Likelihoods_father_i = &d2Likelihoods_father[i];
+      dlx = 0, d2lx = 0;
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* dLikelihoods_father_i_c = &(*dLikelihoods_father_i)[c];
+        Vdouble* d2Likelihoods_father_i_c = &(*d2Likelihoods_father_i)[c];
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          dlx += rateDistribution_->getProbability(c) * rootFreqs_[x] * (*dLikelihoods_father_i_c)[x];
+          d2lx += rateDistribution_->getProbability(c) * rootFreqs_[x] * (*d2Likelihoods_father_i_c)[x];
+        }
+      }
+      d2l += (*w)[i] * (d2lx / (*rootLikelihoodsSR)[i] - pow(dlx / (*rootLikelihoodsSR)[i], 2));
+    }
+    return -d2l;
+  }
+  else
+  {
+    Vdouble* _dLikelihoods_branch;
+    Vdouble* _d2Likelihoods_branch;
+    // Get the node with the branch whose length must be derivated:
+    size_t brI = TextTools::to<size_t>(variable.substr(5));
+    const Node* branch = nodes_[brI];
+    _dLikelihoods_branch = &likelihoodData_->getDLikelihoodArray(branch->getId());
+    _d2Likelihoods_branch = &likelihoodData_->getD2LikelihoodArray(branch->getId());
+    double d2l = 0;
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      d2l += (*w)[i] * ((*_d2Likelihoods_branch)[i] - pow((*_dLikelihoods_branch)[i], 2));
+    }
+    return -d2l;
+  }
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::resetLikelihoodArrays(const Node* node)
+{
+  for (size_t n = 0; n < node->getNumberOfSons(); n++)
+  {
+    const Node* subNode = node->getSon(n);
+    resetLikelihoodArray(likelihoodData_->getLikelihoodArray(node->getId(), subNode->getId()));
+  }
+  if (node->hasFather())
+  {
+    const Node* father = node->getFather();
+    resetLikelihoodArray(likelihoodData_->getLikelihoodArray(node->getId(), father->getId()));
+  }
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::computeTreeLikelihood()
+{
+  computeSubtreeLikelihoodPostfix(tree_->getRootNode());
+  computeSubtreeLikelihoodPrefix(tree_->getRootNode());
+  computeRootLikelihood();
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::computeSubtreeLikelihoodPostfix(const Node* node)
+{
+//  if(node->isLeaf()) return;
+// cout << node->getId() << "\t" << (node->hasName()?node->getName():"") << endl;
+  if (node->getNumberOfSons() == 0)
+    return;
+
+  // Set all likelihood arrays to 1 for a start:
+  resetLikelihoodArrays(node);
+
+  map<int, VVVdouble>* _likelihoods_node = &likelihoodData_->getLikelihoodArrays(node->getId());
+  size_t nbNodes = node->getNumberOfSons();
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    // For each son node...
+
+    const Node* son = node->getSon(l);
+    VVVdouble* _likelihoods_node_son = &(*_likelihoods_node)[son->getId()];
+
+    if (son->isLeaf())
+    {
+      VVdouble* _likelihoods_leaf = &likelihoodData_->getLeafLikelihoods(son->getId());
+      for (size_t i = 0; i < nbDistinctSites_; i++)
+      {
+        // For each site in the sequence,
+        Vdouble* _likelihoods_leaf_i = &(*_likelihoods_leaf)[i];
+        VVdouble* _likelihoods_node_son_i = &(*_likelihoods_node_son)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          // For each rate classe,
+          Vdouble* _likelihoods_node_son_i_c = &(*_likelihoods_node_son_i)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            // For each initial state,
+            (*_likelihoods_node_son_i_c)[x] = (*_likelihoods_leaf_i)[x];
+          }
+        }
+      }
+    }
+    else
+    {
+      computeSubtreeLikelihoodPostfix(son); // Recursive method:
+      size_t nbSons = son->getNumberOfSons();
+      map<int, VVVdouble>* _likelihoods_son = &likelihoodData_->getLikelihoodArrays(son->getId());
+
+      vector<const VVVdouble*> iLik(nbSons);
+      vector<const VVVdouble*> tProb(nbSons);
+      for (size_t n = 0; n < nbSons; n++)
+      {
+        const Node* sonSon = son->getSon(n);
+        tProb[n] = &pxy_[sonSon->getId()];
+        iLik[n] = &(*_likelihoods_son)[sonSon->getId()];
+      }
+      computeLikelihoodFromArrays(iLik, tProb, *_likelihoods_node_son, nbSons, nbDistinctSites_, nbClasses_, nbStates_, false);
+    }
+  }
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::computeSubtreeLikelihoodPrefix(const Node* node)
+{
+  if (!node->hasFather())
+  {
+    // 'node' is the root of the tree.
+    // Just call the method on each son node:
+    size_t nbSons = node->getNumberOfSons();
+    for (size_t n = 0; n < nbSons; n++)
+    {
+      computeSubtreeLikelihoodPrefix(node->getSon(n));
+    }
+    return;
+  }
+  else
+  {
+    const Node* father = node->getFather();
+    map<int, VVVdouble>* _likelihoods_node = &likelihoodData_->getLikelihoodArrays(node->getId());
+    map<int, VVVdouble>* _likelihoods_father = &likelihoodData_->getLikelihoodArrays(father->getId());
+    VVVdouble* _likelihoods_node_father = &(*_likelihoods_node)[father->getId()];
+    if (node->isLeaf())
+    {
+      resetLikelihoodArray(*_likelihoods_node_father);
+    }
+
+    if (father->isLeaf())
+    {
+      // If the tree is rooted by a leaf
+      VVdouble* _likelihoods_leaf = &likelihoodData_->getLeafLikelihoods(father->getId());
+      for (size_t i = 0; i < nbDistinctSites_; i++)
+      {
+        // For each site in the sequence,
+        Vdouble* _likelihoods_leaf_i = &(*_likelihoods_leaf)[i];
+        VVdouble* _likelihoods_node_father_i = &(*_likelihoods_node_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          // For each rate classe,
+          Vdouble* _likelihoods_node_father_i_c = &(*_likelihoods_node_father_i)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            // For each initial state,
+            (*_likelihoods_node_father_i_c)[x] = (*_likelihoods_leaf_i)[x];
+          }
+        }
+      }
+    }
+    else
+    {
+      vector<const Node*> nodes;
+      // Add brothers:
+      size_t nbFatherSons = father->getNumberOfSons();
+      for (size_t n = 0; n < nbFatherSons; n++)
+      {
+        const Node* son = father->getSon(n);
+        if (son->getId() != node->getId())
+          nodes.push_back(son);  // This is a real brother, not current node!
+      }
+      // Now the real stuff... We've got to compute the likelihoods for the
+      // subtree defined by node 'father'.
+      // This is the same as postfix method, but with different subnodes.
+
+      size_t nbSons = nodes.size(); // In case of a bifurcating tree this is equal to 1.
+
+      vector<const VVVdouble*> iLik(nbSons);
+      vector<const VVVdouble*> tProb(nbSons);
+      for (size_t n = 0; n < nbSons; n++)
+      {
+        const Node* fatherSon = nodes[n];
+        tProb[n] = &pxy_[fatherSon->getId()];
+        iLik[n] = &(*_likelihoods_father)[fatherSon->getId()];
+      }
+
+      if (father->hasFather())
+      {
+        const Node* fatherFather = father->getFather();
+        computeLikelihoodFromArrays(iLik, tProb, &(*_likelihoods_father)[fatherFather->getId()], &pxy_[father->getId()], *_likelihoods_node_father, nbSons, nbDistinctSites_, nbClasses_, nbStates_, false);
+      }
+      else
+      {
+        computeLikelihoodFromArrays(iLik, tProb, *_likelihoods_node_father, nbSons, nbDistinctSites_, nbClasses_, nbStates_, false);
+      }
+    }
+
+    if (!father->hasFather())
+    {
+      // We have to account for the root frequencies:
+      for (size_t i = 0; i < nbDistinctSites_; i++)
+      {
+        VVdouble* _likelihoods_node_father_i = &(*_likelihoods_node_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_node_father_i_c = &(*_likelihoods_node_father_i)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            (*_likelihoods_node_father_i_c)[x] *= rootFreqs_[x];
+          }
+        }
+      }
+    }
+
+    // Call the method on each son node:
+    size_t nbNodeSons = node->getNumberOfSons();
+    for (size_t i = 0; i < nbNodeSons; i++)
+    {
+      computeSubtreeLikelihoodPrefix(node->getSon(i)); // Recursive method.
+    }
+  }
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::computeRootLikelihood()
+{
+  const Node* root = tree_->getRootNode();
+  VVVdouble* rootLikelihoods = &likelihoodData_->getRootLikelihoodArray();
+  // Set all likelihoods to 1 for a start:
+  if (root->isLeaf())
+  {
+    VVdouble* leavesLikelihoods_root = &likelihoodData_->getLeafLikelihoods(root->getId());
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* rootLikelihoods_i = &(*rootLikelihoods)[i];
+      Vdouble* leavesLikelihoods_root_i = &(*leavesLikelihoods_root)[i];
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* rootLikelihoods_i_c = &(*rootLikelihoods_i)[c];
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          (*rootLikelihoods_i_c)[x] = (*leavesLikelihoods_root_i)[x];
+        }
+      }
+    }
+  }
+  else
+  {
+    resetLikelihoodArray(*rootLikelihoods);
+  }
+
+  map<int, VVVdouble>* likelihoods_root = &likelihoodData_->getLikelihoodArrays(root->getId());
+  size_t nbNodes = root->getNumberOfSons();
+  vector<const VVVdouble*> iLik(nbNodes);
+  vector<const VVVdouble*> tProb(nbNodes);
+  for (size_t n = 0; n < nbNodes; n++)
+  {
+    const Node* son = root->getSon(n);
+    tProb[n] = &pxy_[son->getId()];
+    iLik[n] = &(*likelihoods_root)[son->getId()];
+  }
+  computeLikelihoodFromArrays(iLik, tProb, *rootLikelihoods, nbNodes, nbDistinctSites_, nbClasses_, nbStates_, false);
+
+  Vdouble p = rateDistribution_->getProbabilities();
+  VVdouble* rootLikelihoodsS  = &likelihoodData_->getRootSiteLikelihoodArray();
+  Vdouble* rootLikelihoodsSR = &likelihoodData_->getRootRateSiteLikelihoodArray();
+  for (size_t i = 0; i < nbDistinctSites_; i++)
+  {
+    // For each site in the sequence,
+    VVdouble* rootLikelihoods_i = &(*rootLikelihoods)[i];
+    Vdouble* rootLikelihoodsS_i = &(*rootLikelihoodsS)[i];
+    (*rootLikelihoodsSR)[i] = 0;
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      // For each rate classe,
+      Vdouble* rootLikelihoods_i_c = &(*rootLikelihoods_i)[c];
+      double* rootLikelihoodsS_i_c = &(*rootLikelihoodsS_i)[c];
+      (*rootLikelihoodsS_i_c) = 0;
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        // For each initial state,
+        (*rootLikelihoodsS_i_c) += rootFreqs_[x] * (*rootLikelihoods_i_c)[x];
+      }
+      (*rootLikelihoodsSR)[i] += p[c] * (*rootLikelihoodsS_i_c);
+    }
+
+    // Final checking (for numerical errors):
+    if ((*rootLikelihoodsSR)[i] < 0)
+      (*rootLikelihoodsSR)[i] = 0.;
+  }
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::computeLikelihoodAtNode_(const Node* node, VVVdouble& likelihoodArray) const
+{
+//  const Node * node = tree_->getNode(nodeId);
+  int nodeId = node->getId();
+  likelihoodArray.resize(nbDistinctSites_);
+  map<int, VVVdouble>* likelihoods_node = &likelihoodData_->getLikelihoodArrays(node->getId());
+
+  // Initialize likelihood array:
+  if (node->isLeaf())
+  {
+    VVdouble* leavesLikelihoods_node = &likelihoodData_->getLeafLikelihoods(nodeId);
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* likelihoodArray_i = &likelihoodArray[i];
+      Vdouble* leavesLikelihoods_node_i = &(*leavesLikelihoods_node)[i];
+      likelihoodArray_i->resize(nbClasses_);
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* likelihoodArray_i_c = &(*likelihoodArray_i)[c];
+        likelihoodArray_i_c->resize(nbStates_);
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          (*likelihoodArray_i_c)[x] = (*leavesLikelihoods_node_i)[x];
+        }
+      }
+    }
+  }
+  else
+  {
+    // Otherwise:
+    // Set all likelihoods to 1 for a start:
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* likelihoodArray_i = &likelihoodArray[i];
+      likelihoodArray_i->resize(nbClasses_);
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* likelihoodArray_i_c = &(*likelihoodArray_i)[c];
+        likelihoodArray_i_c->resize(nbStates_);
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          (*likelihoodArray_i_c)[x] = 1.;
+        }
+      }
+    }
+  }
+
+  size_t nbNodes = node->getNumberOfSons();
+
+  vector<const VVVdouble*> iLik(nbNodes);
+  vector<const VVVdouble*> tProb(nbNodes);
+  for (size_t n = 0; n < nbNodes; n++)
+  {
+    const Node* son = node->getSon(n);
+    tProb[n] = &pxy_[son->getId()];
+    iLik[n] = &(*likelihoods_node)[son->getId()];
+  }
+
+  if (node->hasFather())
+  {
+    const Node* father = node->getFather();
+    computeLikelihoodFromArrays(iLik, tProb, &(*likelihoods_node)[father->getId()], &pxy_[nodeId], likelihoodArray, nbNodes, nbDistinctSites_, nbClasses_, nbStates_, false);
+  }
+  else
+  {
+    computeLikelihoodFromArrays(iLik, tProb, likelihoodArray, nbNodes, nbDistinctSites_, nbClasses_, nbStates_, false);
+
+    // We have to account for the root frequencies:
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* likelihoodArray_i = &likelihoodArray[i];
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* likelihoodArray_i_c = &(*likelihoodArray_i)[c];
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          (*likelihoodArray_i_c)[x] *= rootFreqs_[x];
+        }
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::computeLikelihoodFromArrays(
+  const vector<const VVVdouble*>& iLik,
+  const vector<const VVVdouble*>& tProb,
+  VVVdouble& oLik,
+  size_t nbNodes,
+  size_t nbDistinctSites,
+  size_t nbClasses,
+  size_t nbStates,
+  bool reset)
+{
+  if (reset)
+    resetLikelihoodArray(oLik);
+
+  for (size_t n = 0; n < nbNodes; n++)
+  {
+    const VVVdouble* pxy_n = tProb[n];
+    const VVVdouble* iLik_n = iLik[n];
+
+    for (size_t i = 0; i < nbDistinctSites; i++)
+    {
+      // For each site in the sequence,
+      const VVdouble* iLik_n_i = &(*iLik_n)[i];
+      VVdouble* oLik_i = &(oLik)[i];
+
+      for (size_t c = 0; c < nbClasses; c++)
+      {
+        // For each rate classe,
+        const Vdouble* iLik_n_i_c = &(*iLik_n_i)[c];
+        Vdouble* oLik_i_c = &(*oLik_i)[c];
+        const VVdouble* pxy_n_c = &(*pxy_n)[c];
+        for (size_t x = 0; x < nbStates; x++)
+        {
+          // For each initial state,
+          const Vdouble* pxy_n_c_x = &(*pxy_n_c)[x];
+          double likelihood = 0;
+          for (size_t y = 0; y < nbStates; y++)
+          {
+            likelihood += (*pxy_n_c_x)[y] * (*iLik_n_i_c)[y];
+          }
+          // We store this conditionnal likelihood into the corresponding array:
+          (*oLik_i_c)[x] *= likelihood;
+        }
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::computeLikelihoodFromArrays(
+  const vector<const VVVdouble*>& iLik,
+  const vector<const VVVdouble*>& tProb,
+  const VVVdouble* iLikR,
+  const VVVdouble* tProbR,
+  VVVdouble& oLik,
+  size_t nbNodes,
+  size_t nbDistinctSites,
+  size_t nbClasses,
+  size_t nbStates,
+  bool reset)
+{
+  if (reset)
+    resetLikelihoodArray(oLik);
+
+  for (size_t n = 0; n < nbNodes; n++)
+  {
+    const VVVdouble* pxy_n = tProb[n];
+    const VVVdouble* iLik_n = iLik[n];
+
+    for (size_t i = 0; i < nbDistinctSites; i++)
+    {
+      // For each site in the sequence,
+      const VVdouble* iLik_n_i = &(*iLik_n)[i];
+      VVdouble* oLik_i = &(oLik)[i];
+
+      for (size_t c = 0; c < nbClasses; c++)
+      {
+        // For each rate classe,
+        const Vdouble* iLik_n_i_c = &(*iLik_n_i)[c];
+        Vdouble* oLik_i_c = &(*oLik_i)[c];
+        const VVdouble* pxy_n_c = &(*pxy_n)[c];
+        for (size_t x = 0; x < nbStates; x++)
+        {
+          // For each initial state,
+          const Vdouble* pxy_n_c_x = &(*pxy_n_c)[x];
+          double likelihood = 0;
+          for (size_t y = 0; y < nbStates; y++)
+          {
+            // cout << "1:" << (* pxy_n_c_x)[y]  << endl;
+            // cout << "2:" << (* iLik_n_i_c)[y] << endl;
+            likelihood += (*pxy_n_c_x)[y] * (*iLik_n_i_c)[y];
+            // cout << i << "\t" << c << "\t" << x << "\t" << y << "\t" <<  (* pxy__son_c_x)[y] << "\t" << (* likelihoods_root_son_i_c)[y] << endl;
+          }
+          // We store this conditionnal likelihood into the corresponding array:
+          (*oLik_i_c)[x] *= likelihood;
+        }
+      }
+    }
+  }
+
+  // Now deal with the subtree containing the root:
+  for (size_t i = 0; i < nbDistinctSites; i++)
+  {
+    // For each site in the sequence,
+    const VVdouble* iLikR_i = &(*iLikR)[i];
+    VVdouble* oLik_i = &(oLik)[i];
+
+    for (size_t c = 0; c < nbClasses; c++)
+    {
+      // For each rate classe,
+      const Vdouble* iLikR_i_c = &(*iLikR_i)[c];
+      Vdouble* oLik_i_c = &(*oLik_i)[c];
+      const VVdouble* pxyR_c = &(*tProbR)[c];
+      for (size_t x = 0; x < nbStates; x++)
+      {
+        double likelihood = 0;
+        for (size_t y = 0; y < nbStates; y++)
+        {
+          // For each final state,
+          const Vdouble* pxyR_c_y = &(*pxyR_c)[y];
+          likelihood += (*pxyR_c_y)[x] * (*iLikR_i_c)[y];
+        }
+        // We store this conditionnal likelihood into the corresponding array:
+        (*oLik_i_c)[x] *= likelihood;
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+void DRNonHomogeneousTreeLikelihood::displayLikelihood(const Node* node)
+{
+  cout << "Likelihoods at node " << node->getId() << ": " << endl;
+  for (size_t n = 0; n < node->getNumberOfSons(); n++)
+  {
+    const Node* subNode = node->getSon(n);
+    cout << "Array for sub-node " << subNode->getId() << endl;
+    displayLikelihoodArray(likelihoodData_->getLikelihoodArray(node->getId(), subNode->getId()));
+  }
+  if (node->hasFather())
+  {
+    const Node* father = node->getFather();
+    cout << "Array for father node " << father->getId() << endl;
+    displayLikelihoodArray(likelihoodData_->getLikelihoodArray(node->getId(), father->getId()));
+  }
+  cout << "                                         ***" << endl;
+}
+
+/*******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Likelihood/DRNonHomogeneousTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/DRNonHomogeneousTreeLikelihood.h
new file mode 100644
index 0000000..db7c7e4
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DRNonHomogeneousTreeLikelihood.h
@@ -0,0 +1,315 @@
+//
+// File: DRNonHomogeneousTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Fri Dec 28 19:14 2007
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _DRNONHOMOGENEOUSTREELIKELIHOOD_H_
+#define _DRNONHOMOGENEOUSTREELIKELIHOOD_H_
+
+#include "AbstractNonHomogeneousTreeLikelihood.h"
+#include "DRTreeLikelihood.h"
+#include "DRASDRTreeLikelihoodData.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+
+namespace bpp
+{
+
+/**
+ * @brief This class implements the likelihood computation for a tree using the double-recursive
+ * algorithm, allowing for non-homogeneous models of substitutions.
+ *
+ * The substitution model is the same over the tree (homogeneous model).
+ * A non-uniform distribution of rates among the sites is allowed (ASRV models).</p>
+ *
+ * This class uses an instance of the DRASDRTreeLikelihoodData for conditionnal likelihood storage.
+ *
+ * All nodes share the same site patterns.
+ *
+ * Important note: The input tree will be considered as rooted, since the likelihood of non-stationary models
+ * depends on the position of the root. If the input tree is not rooted, it will be considered as a rotted tree
+ * with a root multifurcation.
+ */
+class DRNonHomogeneousTreeLikelihood:
+  public AbstractNonHomogeneousTreeLikelihood,
+  public DRTreeLikelihood
+{
+  protected:
+    mutable DRASDRTreeLikelihoodData *likelihoodData_;
+    double minusLogLik_;
+   
+  public:
+    /**
+     * @brief Build a new DRNonHomogeneousTreeLikelihood object without data.
+     *
+     * This constructor only initialize the parameters.
+     * To compute a likelihood, you will need to call the setData() and the computeTreeLikelihood() methods.
+     *
+     * @param tree The tree to use.
+     * @param modelSet The set of substitution models to use.
+     * @param rDist The rate across sites distribution to use.
+     * If true, any rooted tree will be unrooted before likelihood computation.
+     * @param verbose Should I display some info?
+     * @param reparametrizeRoot Should we reparametrize the branch lengths at root?
+     * @throw Exception in an error occured.
+     */
+    DRNonHomogeneousTreeLikelihood(
+      const Tree& tree,
+      SubstitutionModelSet* modelSet,
+      DiscreteDistribution* rDist,
+      bool verbose = true,
+      bool reparametrizeRoot = false)
+      throw (Exception);
+  
+    /**
+     * @brief Build a new DRNonHomogeneousTreeLikelihood object and compute the corresponding likelihood.
+     *
+     * This constructor initializes all parameters, data, and likelihood arrays.
+     *
+     * @param tree The tree to use.
+     * @param data Sequences to use.
+     * @param modelSet The set of substitution models to use.
+     * @param rDist The rate across sites distribution to use.
+     * If true, any rooted tree will be unrooted before likelihood computation.
+     * @param verbose Should I display some info?
+     * @param reparametrizeRoot Should we reparametrize the branch lengths at root?
+     * @throw Exception in an error occured.
+     */
+    DRNonHomogeneousTreeLikelihood(
+      const Tree& tree,
+      const SiteContainer& data,
+      SubstitutionModelSet* modelSet,
+      DiscreteDistribution* rDist,
+      bool verbose = true,
+      bool reparametrizeRoot = false)
+      throw (Exception);
+
+    /**
+     * @brief Copy constructor.
+     */ 
+    DRNonHomogeneousTreeLikelihood(const DRNonHomogeneousTreeLikelihood& lik);
+    
+    DRNonHomogeneousTreeLikelihood& operator=(const DRNonHomogeneousTreeLikelihood& lik);
+
+    virtual ~DRNonHomogeneousTreeLikelihood();
+
+    DRNonHomogeneousTreeLikelihood* clone() const { return new DRNonHomogeneousTreeLikelihood(*this); }
+
+  private:
+
+    /**
+     * @brief Method called by constructors.
+     */
+    void init_() throw (Exception);
+
+  public:
+
+    /**
+     * @name The TreeLikelihood interface.
+     *
+     * Other methods are implemented in the AbstractTreeLikelihood class.
+     *
+     * @{
+     */
+    void setData(const SiteContainer& sites) throw (Exception);
+    double getLikelihood () const;
+    double getLogLikelihood() const;
+    double getLikelihoodForASite (size_t site) const;
+    double getLogLikelihoodForASite(size_t site) const;      
+    size_t getSiteIndex(size_t site) const throw (IndexOutOfBoundsException) { return likelihoodData_->getRootArrayPosition(site); }
+    /** @} */
+
+    void computeTreeLikelihood();
+
+    
+    /**
+     * @name The DiscreteRatesAcrossSites interface implementation:
+     *
+     * @{
+     */
+    double getLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+    double getLogLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+    double getLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const;
+    double getLogLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const;
+    /** @} */
+  
+    /**
+     * @brief Implements the Function interface.
+     *
+     * Update the parameter list and call the fireParameterChanged() method.
+     *
+     * If a subset of the whole parameter list is passed to the function,
+     * only these parameters are updated and the other remain constant (i.e.
+     * equal to their last value).
+     *
+     * @param parameters The parameter list to pass to the function.
+     */
+    void setParameters(const ParameterList& parameters) throw (ParameterNotFoundException, ConstraintException);
+    
+    /**
+     * @brief Function and NNISearchable interface.
+     */
+    double getValue() const throw (Exception);
+    
+    /**
+     * @name DerivableFirstOrder interface.
+     *
+     * @{
+     */
+    double getFirstOrderDerivative(const std::string& variable) const throw (Exception);
+    /** @{ */
+
+    /**
+     * @name DerivableSecondOrder interface.
+     *
+     * @{
+     */
+    double getSecondOrderDerivative(const std::string& variable) const throw (Exception);
+    double getSecondOrderDerivative(const std::string& variable1, const std::string& variable2) const throw (Exception) { return 0; } // Not implemented for now.
+    /** @} */
+    
+  public:  // Specific methods:
+
+    DRASDRTreeLikelihoodData* getLikelihoodData() { return likelihoodData_; }
+    const DRASDRTreeLikelihoodData* getLikelihoodData() const { return likelihoodData_; }
+  
+    virtual void computeLikelihoodAtNode(int nodeId, VVVdouble& likelihoodArray) const
+    {
+      computeLikelihoodAtNode_(tree_->getNode(nodeId), likelihoodArray);
+    }
+      
+  protected:
+    virtual void computeLikelihoodAtNode_(const Node* node, VVVdouble& likelihoodArray) const;
+
+  
+    /**
+     * Initialize the arrays corresponding to each son node for the node passed as argument.
+     * The method is called for each son node and the result stored in the corresponding array.
+     */
+    virtual void computeSubtreeLikelihoodPostfix(const Node* node); //Recursive method.
+    /**
+     * This method initilize the remaining likelihood arrays, corresponding to father nodes.
+     * It must be called after the postfix method because it requires that the arrays for
+     * son nodes to be be computed.
+     */
+    virtual void computeSubtreeLikelihoodPrefix(const Node* node); //Recursive method.
+
+    virtual void computeRootLikelihood();
+
+    virtual void computeTreeDLikelihoodAtNode(const Node* node);
+    virtual void computeTreeDLikelihoods();
+    
+    virtual void computeTreeD2LikelihoodAtNode(const Node* node);
+    virtual void computeTreeD2Likelihoods();
+
+    void fireParameterChanged(const ParameterList& params);
+
+    void resetLikelihoodArrays(const Node* node);
+  
+    /**
+     * @brief This method is mainly for debugging purpose.
+     *
+     * @param node The node at which likelihood values must be displayed.
+     */
+    virtual void displayLikelihood(const Node* node);
+
+    /**
+     * @brief Compute conditional likelihoods.
+     *
+     * This method is the "core" likelihood computation function, performing all the product uppon all nodes, the summation for each ancestral state and each rate class.
+     * It is designed for inner usage, and a maximum efficiency, so no checking is performed on the input parameters.
+     * Use with care!
+     * 
+     * @param iLik A vector of likelihood arrays, one for each conditional node.
+     * @param tProb A vector of transition probabilities, one for each node.
+     * @param oLik The likelihood array to store the computed likelihoods.
+     * @param nbNodes The number of nodes = the size of the input vectors.
+     * @param nbDistinctSites The number of distinct sites (the first dimension of the likelihood array).
+     * @param nbClasses The number of rate classes (the second dimension of the likelihood array).
+     * @param nbStates The number of states (the third dimension of the likelihood array).
+     * @param reset Tell if the output likelihood array must be initalized prior to computation.
+     * If true, the resetLikelihoodArray method will be called.
+     */
+    static void computeLikelihoodFromArrays(
+        const std::vector<const VVVdouble*>& iLik,
+        const std::vector<const VVVdouble*>& tProb,
+        VVVdouble& oLik, size_t nbNodes,
+        size_t nbDistinctSites,
+        size_t nbClasses,
+        size_t nbStates,
+        bool reset = true);
+
+    /**
+     * @brief Compute conditional likelihoods.
+     *
+     * This method is the "core" likelihood computation function, performing all the product uppon all nodes, the summation for each ancestral state and each rate class.
+     * This function is specific to non-reversible models: the subtree containing the root is specified separately.
+     * It is designed for inner usage, and a maximum efficiency, so no checking is performed on the input parameters.
+     * Use with care!
+     * 
+     * @param iLik A vector of likelihood arrays, one for each conditional node.
+     * @param tProb A vector of transition probabilities, one for each node.
+     * @param iLikR The likelihood array for the subtree containing the root of the tree.
+     * @param tProbR The transition probabilities for thr subtree containing the root of the tree.
+     * @param oLik The likelihood array to store the computed likelihoods.
+     * @param nbNodes The number of nodes = the size of the input vectors.
+     * @param nbDistinctSites The number of distinct sites (the first dimension of the likelihood array).
+     * @param nbClasses The number of rate classes (the second dimension of the likelihood array).
+     * @param nbStates The number of states (the third dimension of the likelihood array).
+     * @param reset Tell if the output likelihood array must be initalized prior to computation.
+     * If true, the resetLikelihoodArray method will be called.
+     */
+    static void computeLikelihoodFromArrays(
+        const std::vector<const VVVdouble*>& iLik,
+        const std::vector<const VVVdouble*>& tProb,
+        const VVVdouble* iLikR,
+        const VVVdouble* tProbR,
+        VVVdouble& oLik,
+        size_t nbNodes,
+        size_t nbDistinctSites,
+        size_t nbClasses,
+        size_t nbStates,
+        bool reset = true);
+
+  friend class DRNonHomogeneousMixedTreeLikelihood;
+};
+
+} //end of namespace bpp.
+
+#endif  //_DRNONHOMOGENEOUSTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/DRTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/DRTreeLikelihood.h
new file mode 100644
index 0000000..0b9eac8
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DRTreeLikelihood.h
@@ -0,0 +1,111 @@
+//
+// File: DRTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Sat Dec 29 19:04 2007
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _DRTREELIKELIHOOD_H_
+#define _DRTREELIKELIHOOD_H_
+
+#include "AbstractNonHomogeneousTreeLikelihood.h"
+#include "DRASDRTreeLikelihoodData.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+
+namespace bpp
+{
+
+/**
+ * @brief Interface for double-recursive (DR) implementation of the likelihood computation.
+ *
+ * In the DR implementation, three conditional likelihoods are stored at each node, corresponding to the three connected substrees
+ * (in case of multifurcations, there may have even more).
+ * The DR implementation hence uses 3x more memory than the simple recursive (R) implementation.
+ * However, the likelihood of the tree can be computed independently at each node of the tree,
+ * which is very convenient for topology estimation (the likelihood change of each NNI movement can be computed directly),
+ * ancestral state reconstruction (all marginal ancestral states can be computed in one pass over the tree), or for
+ * substitution mapping.
+ *
+ * This interface provides
+ * - a method to access the DR likelihood data structure,
+ * - a method to compute the likelihood array at each node.
+ *
+ * For now, this interface inherits from DiscreteRatesAcrossSitesTreeLikelihood and not TreeLikelihood,
+ * since the data structure available accounts for rate across site variation.
+ * This may change in the future.
+ *
+ * @see DRTreeLikelihoodTools
+ */
+class DRTreeLikelihood:
+  public virtual DiscreteRatesAcrossSitesTreeLikelihood
+{
+  public:
+    DRTreeLikelihood() {}
+    virtual ~DRTreeLikelihood() {}
+
+#ifndef NO_VIRTUAL_COV
+    DRTreeLikelihood* clone() const = 0;
+#endif
+
+  public:
+  
+    
+  public:
+
+    /**
+     * @name Get the likelihood data structure associated to this class.
+     *
+     * @{
+     */
+    virtual DRASDRTreeLikelihoodData* getLikelihoodData() = 0;
+    virtual const DRASDRTreeLikelihoodData* getLikelihoodData() const = 0;
+    /** @} */
+  
+    /**
+     * @brief Compute the likelihood array at a given node.
+     *
+     * @param nodeId The id of the node to consider.
+     * @param likelihoodArray The array where to store the results.
+     */
+    virtual void computeLikelihoodAtNode(int nodeId, VVVdouble& likelihoodArray) const = 0;
+
+};
+
+} //end of namespace bpp.
+
+#endif  //_DRTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/DRTreeLikelihoodTools.cpp b/src/Bpp/Phyl/Likelihood/DRTreeLikelihoodTools.cpp
new file mode 100755
index 0000000..db7a910
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DRTreeLikelihoodTools.cpp
@@ -0,0 +1,147 @@
+//
+// File: DRTreeLikelihoodTools.cpp
+// Created by: Julien Dutheil
+// Created on: Mon Janv 17 09:56 2005
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "DRTreeLikelihoodTools.h"
+#include <Bpp/Numeric/VectorTools.h>
+
+using namespace bpp;
+
+//-----------------------------------------------------------------------------------------
+
+VVVdouble DRTreeLikelihoodTools::getPosteriorProbabilitiesForEachStateForEachRate(
+  const DRTreeLikelihood & drl,
+  int nodeId)
+{
+  size_t nSites   = drl.getLikelihoodData()->getNumberOfDistinctSites();
+  size_t nClasses = drl.getNumberOfClasses();
+  size_t nStates  = drl.getNumberOfStates();
+  VVVdouble postProb(nSites);
+  
+  const DiscreteDistribution* rDist = drl.getRateDistribution();
+  Vdouble rcProbs = rDist->getProbabilities();
+  if(drl.getTree().isLeaf(nodeId))
+  {
+    VVdouble larray = drl.getLikelihoodData()->getLeafLikelihoods(nodeId);
+    for(size_t i = 0; i < nSites; i++)
+    {
+      VVdouble * postProb_i = & postProb[i];
+      postProb_i->resize(nClasses);
+      Vdouble * larray_i = & larray[i];
+      for(size_t c = 0; c < nClasses; c++)
+      {
+        Vdouble * postProb_i_c = & (* postProb_i)[c];
+        postProb_i_c->resize(nStates);
+        double * rcProb = & rcProbs[c];
+        for(size_t x = 0; x < nStates; x++)
+        {
+          (* postProb_i_c)[x] = (* larray_i)[x] * (* rcProb);
+        }
+      }
+    }
+  }
+  else
+  {
+    VVVdouble larray;
+    drl.computeLikelihoodAtNode(nodeId, larray);
+    
+    Vdouble likelihoods(nSites, 0);
+    for(size_t i = 0; i < nSites; i++)
+    {
+      VVdouble * larray_i = & larray[i];
+      for(size_t c = 0; c < nClasses; c++)
+      {
+        Vdouble * larray_i_c = & (* larray_i)[c];
+        for(size_t s = 0; s < nStates; s++)
+        {
+          likelihoods[i] += (* larray_i_c)[s];
+        }
+      }
+    }
+    
+    for(size_t i = 0; i < nSites; i++)
+    {
+      VVdouble * postProb_i = & postProb[i];
+      postProb_i->resize(nClasses);
+      VVdouble * larray_i = & larray[i];
+      double likelihood = likelihoods[i];
+      for(size_t c = 0; c < nClasses; c++)
+      {
+        Vdouble * postProb_i_c = & (* postProb_i)[c];
+        postProb_i_c->resize(nStates);
+        Vdouble * larray_i_c = & (* larray_i)[c];
+        for(size_t x = 0; x < nStates; x++)
+        {
+          (* postProb_i_c)[x] = (* larray_i_c)[x] / likelihood;
+        }
+      }
+    }
+  }
+  return postProb;
+}
+
+//-----------------------------------------------------------------------------------------
+
+Vdouble DRTreeLikelihoodTools::getPosteriorStateFrequencies(
+  const DRTreeLikelihood& drl,
+  int nodeId)
+{
+  VVVdouble probs = getPosteriorProbabilitiesForEachStateForEachRate(drl, nodeId);
+  Vdouble freqs(drl.getNumberOfStates());
+  double sumw = 0, w;
+  for (size_t i = 0; i < probs.size(); i++)
+  {
+    w = drl.getLikelihoodData()->getWeight(i);
+    sumw += w;
+    for (size_t j = 0; j < drl.getNumberOfClasses(); j++)
+    {
+      for (size_t k = 0; k < drl.getNumberOfStates(); k++)
+      {
+        freqs[k] += probs[i][j][k] * w;
+      }
+    }
+  }
+  for (size_t k = 0; k < drl.getNumberOfStates(); k++)
+  {
+    freqs[k] /= sumw;
+  }
+  return freqs;
+}
+
+//-----------------------------------------------------------------------------------------
+
diff --git a/src/Bpp/Phyl/Likelihood/DRTreeLikelihoodTools.h b/src/Bpp/Phyl/Likelihood/DRTreeLikelihoodTools.h
new file mode 100755
index 0000000..970c827
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DRTreeLikelihoodTools.h
@@ -0,0 +1,89 @@
+//
+// File: DRTreeLikelihoodTools.h
+// Created by: Julien Dutheil
+// Created on: Mon Janv 17 09:56 2005
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _DRTREELIKELIHOODTOOLS_H_
+#define _DRTREELIKELIHOODTOOLS_H_
+
+#include "TreeLikelihoodTools.h"
+#include "DRTreeLikelihood.h"
+#include <Bpp/Seq/Container/AlignedSequenceContainer.h>
+
+namespace bpp
+{
+
+/**
+ * @brief Utilitary methods dealing with objects implementing the DRTreeLikelihood interface.
+ */
+class DRTreeLikelihoodTools:
+  public TreeLikelihoodTools
+{
+
+  public:
+    /**
+     * @brief Compute the posterior probabilities for each state and each rate of each distinct site.
+     *
+     * @param drl A DR tree likelihood object.
+     * @param nodeId The id of the node at which probabilities must be computed.
+     * @return A 3-dimensional array, with probabilities for each site, each rate and each state.
+     */
+    static VVVdouble getPosteriorProbabilitiesForEachStateForEachRate(
+        const DRTreeLikelihood& drl,
+        int nodeId);
+
+    /**
+     * @brief Compute the posterior probabilities for each state for a given node.
+     *
+     * This method calls the getPosteriorProbabilitiesForEachStateForEachRate function
+     * and average the probabilities over all sites and rate classes, resulting in a
+     * one-dimensionnal frequency array, with one frequency per model state.
+     *
+     * @param drl A DR tree likelihood object.
+     * @param nodeId The id of the node at which probabilities must be computed.
+     * @return vector of double with state frequencies for the given node.
+     */
+    static Vdouble getPosteriorStateFrequencies(
+        const DRTreeLikelihood& drl,
+        int nodeId);
+
+};
+
+} //end of namespace bpp.
+
+#endif //_DRTREELIKELIHOODTOOLS_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/DiscreteRatesAcrossSitesTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/DiscreteRatesAcrossSitesTreeLikelihood.h
new file mode 100755
index 0000000..a1e5c2f
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/DiscreteRatesAcrossSitesTreeLikelihood.h
@@ -0,0 +1,210 @@
+//
+// File: DiscreteRateAcrossSitesTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _DISCRETERATESACROSSSITESTREELIKELIHOOD_H_
+#define _DISCRETERATESACROSSSITESTREELIKELIHOOD_H_
+
+#include "TreeLikelihood.h"
+
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+#include <Bpp/Numeric/ParameterList.h>
+
+namespace bpp
+{
+
+/**
+ * @brief Interface for rate across sites (RAS) implementation.
+ *
+ * This interface provides methods for dealing with RAS models.
+ */
+class DiscreteRatesAcrossSitesTreeLikelihood:
+  public virtual TreeLikelihood
+{
+	public:
+		DiscreteRatesAcrossSitesTreeLikelihood() {}
+		virtual ~DiscreteRatesAcrossSitesTreeLikelihood() {}
+
+	public:
+
+		/**
+		 * @brief Get the rate distribution used for the computation.
+		 *
+		 * @return A const pointer toward the rate distribution of this instance.
+		 */
+		virtual const DiscreteDistribution* getRateDistribution() const = 0;
+
+		/**
+		 * @brief Get the rate distribution used for the computation.
+		 *
+		 * @return A pointer toward the rate distribution of this instance.
+		 */
+		virtual DiscreteDistribution* getRateDistribution() = 0;
+
+		/**
+		 * @brief Get the likelihood for a site knowing its rate class.
+		 *
+		 * @param site      The site index.
+		 * @param rateClass The rate class index.
+		 * @return The likelihood for the specified site and rate class.
+		 */
+		virtual double getLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const = 0;
+		
+		/**
+		 * @brief Get the logarithm of the likelihood for a site knowing its rate class.
+		 *
+		 * @param site      The site index.
+		 * @param rateClass The rate class index.
+		 * @return The logarithm of the likelihood for the specified site and rate class.
+		 */
+		virtual double getLogLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const = 0;
+	
+		/**
+		 * @brief Get the likelihood for a site knowing its rate class and its ancestral state.
+		 *
+		 * @param site      The site index.
+		 * @param rateClass The rate class index.
+		 * @param state     The ancestral state.
+		 * @return The likelihood for the specified site and rate class and ancestral state.
+		 */
+		virtual double getLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const = 0;
+		
+		/**
+		 * @brief Get the logarithm of the likelihood for a site knowing its rate class and its ancestral state.
+		 *
+		 * @param site      The site index.
+		 * @param rateClass The rate class index.
+		 * @param state     The ancestral state.
+		 * @return The logarithm of the likelihood for the specified site and rate class and ancestral state..
+		 */
+		virtual double getLogLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const = 0;
+
+		/**
+		 * @brief Get the likelihood for each site and each rate class.
+		 *
+		 * @return A two-dimension vector with all likelihoods.
+		 */
+		virtual VVdouble getLikelihoodForEachSiteForEachRateClass() const = 0;
+		
+		/**
+		 * @brief Get the logarithm of the likelihood for each site and each rate class.
+		 *
+		 * @return A two-dimension vector with all log likelihoods:
+		 * <code>V[i][j] =</code> likelihood of site i and rate class j.
+		 */
+		virtual VVdouble getLogLikelihoodForEachSiteForEachRateClass() const = 0;
+		
+		/**
+		 * @brief Get the likelihood for each site and each rate class and each state.
+		 *
+		 * @return A three-dimension vector with all likelihoods.
+		 */
+		virtual VVVdouble getLikelihoodForEachSiteForEachRateClassForEachState() const = 0;
+		
+		/**
+		 * @brief Get the logarithm of the likelihood for each site and each rate class and each state.
+		 *
+		 * @return A three-dimension vector with all log likelihoods:
+		 * <code>V[i][j][k} =</code> likelihood of site i and rate class j and state k.
+		 */
+		virtual VVVdouble getLogLikelihoodForEachSiteForEachRateClassForEachState() const = 0;
+
+		/**
+		 * @brief Get the posterior probability for each site of belonging to a
+		 * particular rate class.
+		 *
+		 * @return A two-dimension vector with all posterior probabilities:
+		 * <code>V[i][j] =</code> probablity for site i of belonging to rate class j.
+		 */
+		virtual VVdouble getPosteriorProbabilitiesOfEachRate() const = 0;
+		
+		/**
+		 * @brief Get the posterior rate class (the one with maximum posterior
+		 * probability) for each site.
+		 *
+		 * @return A vector with all rate classes indexes.
+		 */
+		virtual std::vector<size_t> getRateClassWithMaxPostProbOfEachSite() const = 0;
+
+		/**
+		 * @brief Get the posterior rate (the one with maximum posterior
+		 * probability) for each site.
+		 *
+		 * @return A vector with all rate classes indexes.
+		 */
+		virtual Vdouble getRateWithMaxPostProbOfEachSite() const = 0;
+	
+		/**
+		 * @brief Get the posterior rate, i.e. averaged over all classes
+		 * and weighted with posterior probabilities, for each site.
+		 *
+		 * @return A vector with all rates.
+		 */
+		virtual Vdouble getPosteriorRateOfEachSite() const = 0;
+
+		/**
+		 * @brief Get the parameters associated to the rate distirbution.
+		 *
+		 * @return A ParameterList object with all rate distribution parameters.
+		 */
+		virtual ParameterList getRateDistributionParameters() const = 0;
+
+		/**
+		 * @brief Get the number of classes.
+		 *
+		 * @return The Number of classes.
+		 */
+		virtual size_t getNumberOfClasses() const = 0;
+
+    /**
+     * @brief Retrieves all Pij(t) for a particular branch, defined by the upper node.
+     *
+     * These intermediate results may be used by other methods.
+     *
+     * @param nodeId The node defining the branch of interest.
+     * @param siteIndex The position in the alignment.
+     * @return An array of dimension 3, where a[c][x][y] is the probability of substituting from x to y while being in rate class c.
+     */
+    virtual VVVdouble getTransitionProbabilitiesPerRateClass(int nodeId, size_t siteIndex) const = 0;
+		
+};
+
+} //end of namespace bpp.
+
+#endif //_DISCRETERATESACROSSSITESTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/GlobalClockTreeLikelihoodFunctionWrapper.cpp b/src/Bpp/Phyl/Likelihood/GlobalClockTreeLikelihoodFunctionWrapper.cpp
new file mode 100644
index 0000000..8362b72
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/GlobalClockTreeLikelihoodFunctionWrapper.cpp
@@ -0,0 +1,124 @@
+//
+// File: GlobalClockTreeLikelihoodFunctionWrapper.cpp
+// Created by: Julien Dutheil
+// Created on: Thu Jul 14 10:53 2011
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "GlobalClockTreeLikelihoodFunctionWrapper.h"
+
+using namespace bpp;
+
+void GlobalClockTreeLikelihoodFunctionWrapper::fireParameterChanged(const bpp::ParameterList& pl)
+{
+  // filter parameters:
+  ParameterList pl2;
+  bool recomputeHeights = false;
+  for (unsigned int i = 0; i < pl.size(); ++i)
+  {
+    if (pl[i].getName().substr(0, 7) == "HeightP" || pl[i].getName() == "TotalHeight")
+      recomputeHeights = true;
+    else
+      pl2.addParameter(pl[i]);
+  }
+  if (recomputeHeights)
+  {
+    TreeTemplate<Node> tree(tl_->getTree());
+    computeBranchLengthsFromHeights_(tree.getRootNode(), getParameter("TotalHeight").getValue(), pl2);
+  }
+  tl_->setParameters(pl2);
+}
+
+ParameterList GlobalClockTreeLikelihoodFunctionWrapper::getHeightParameters() const
+{
+  ParameterList pl;
+
+  for (unsigned int i = 0; i < getNumberOfParameters(); ++i)
+  {
+    Parameter p = getParameter_(i);
+    if (p.getName().substr(0, 7) == "HeightP" || p.getName() == "TotalHeight")
+      pl.addParameter(p);
+  }
+  return pl;
+}
+
+void GlobalClockTreeLikelihoodFunctionWrapper::initParameters_()
+{
+  // Check if the tree is rooted:
+  TreeTemplate<Node> tree(tl_->getTree());
+  if (!tree.isRooted()) throw Exception("GlobalClockTreeLikelihoodFunctionWrapper::initParameters_(). Tree is unrooted!");
+  if (TreeTemplateTools::isMultifurcating(*(tree.getRootNode()))) throw Exception("GlobalClockTreeLikelihoodFunctionWrapper::initParameters_(). Tree is multifurcating.");
+  std::map<const Node*, double> heights;
+  TreeTemplateTools::getHeights(*(tree.getRootNode()), heights);
+  double totalHeight = heights[tree.getRootNode()];
+  addParameter_(new Parameter("TotalHeight", totalHeight, &Parameter::R_PLUS_STAR));
+  for (std::map<const Node*, double>::iterator it = heights.begin(); it != heights.end(); it++)
+  {
+    if (!it->first->isLeaf() && it->first->hasFather())
+    {
+      double fatherHeight = heights[it->first->getFather()];
+      addParameter_(new Parameter("HeightP" + TextTools::toString(it->first->getId()), it->second / fatherHeight, &Parameter::PROP_CONSTRAINT_IN));
+    }
+  }
+  // We add other parameters:
+  ParameterList pl = tl_->getParameters();
+  for (unsigned int i = 0; i < pl.size(); ++i)
+  {
+    if (pl[i].getName().substr(0, 5) != "BrLen")
+      addParameter_(pl[i].clone());
+  }
+  // Compute everything:
+  fireParameterChanged(getParameters());
+}
+
+void GlobalClockTreeLikelihoodFunctionWrapper::computeBranchLengthsFromHeights_(const Node* node, double height, ParameterList& brlenPl) throw (Exception)
+{
+  for (unsigned int i = 0; i < node->getNumberOfSons(); i++)
+  {
+    const Node* son = node->getSon(i);
+    if (son->isLeaf())
+    {
+      brlenPl.addParameter(Parameter("BrLen" + TextTools::toString(son->getId()), std::max(0.0000011, height), new IntervalConstraint(1, 0.000001, false), true));
+    }
+    else
+    {
+      double sonHeightP = getParameter("HeightP" + TextTools::toString(son->getId())).getValue();
+      double sonHeight = sonHeightP * height;
+      brlenPl.addParameter(Parameter("BrLen" + TextTools::toString(son->getId()), std::max(0.0000011, height - sonHeight), new IntervalConstraint(1, 0.000001, false), true));
+      computeBranchLengthsFromHeights_(son, sonHeight, brlenPl);
+    }
+  }
+}
+
diff --git a/src/Bpp/Phyl/Likelihood/GlobalClockTreeLikelihoodFunctionWrapper.h b/src/Bpp/Phyl/Likelihood/GlobalClockTreeLikelihoodFunctionWrapper.h
new file mode 100644
index 0000000..306442a
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/GlobalClockTreeLikelihoodFunctionWrapper.h
@@ -0,0 +1,104 @@
+//
+// File: GlobalClockTreeLikelihoodFunctionWrapper.h
+// Created by: Julien Dutheil
+// Created on: Thu Jul 14 10:53 2011
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _GLOBALCLOCKTREELIKELIHOODFUNCTIONWRAPPER_H_
+#define _GLOBALCLOCKTREELIKELIHOODFUNCTIONWRAPPER_H_
+
+#include "TreeLikelihood.h"
+
+namespace bpp
+{
+
+class GlobalClockTreeLikelihoodFunctionWrapper:
+  public virtual DerivableSecondOrder,
+  public AbstractParametrizable
+{
+  private:
+    TreeLikelihood* tl_;
+
+  public:
+    GlobalClockTreeLikelihoodFunctionWrapper(TreeLikelihood* tl):
+      AbstractParametrizable(""),
+      tl_(tl)
+    {
+      initParameters_();
+    }
+
+    GlobalClockTreeLikelihoodFunctionWrapper(const GlobalClockTreeLikelihoodFunctionWrapper& gctlfw):
+      AbstractParametrizable(gctlfw), tl_(gctlfw.tl_)
+    {}
+    
+    GlobalClockTreeLikelihoodFunctionWrapper& operator=(const GlobalClockTreeLikelihoodFunctionWrapper& gctlfw) {
+      AbstractParametrizable::operator=(gctlfw);
+      tl_ = gctlfw.tl_;
+      return *this;
+    }
+
+    GlobalClockTreeLikelihoodFunctionWrapper* clone() const { return new GlobalClockTreeLikelihoodFunctionWrapper(*this); }
+
+  public:
+    void setParameters(const ParameterList& pl) throw (Exception) {
+      //For now we go the hard way and recompute everything:
+      matchParametersValues(pl);
+    }
+
+    double getValue() const throw (Exception) { return tl_->getValue(); }
+
+    void fireParameterChanged(const bpp::ParameterList& pl);
+
+    void enableSecondOrderDerivatives(bool yn) { tl_->enableSecondOrderDerivatives(yn); }
+    bool enableSecondOrderDerivatives() const { return tl_->enableSecondOrderDerivatives(); }
+    void enableFirstOrderDerivatives(bool yn) { tl_->enableFirstOrderDerivatives(yn); }
+    bool enableFirstOrderDerivatives() const { return tl_->enableFirstOrderDerivatives(); }
+    double getSecondOrderDerivative(const std::string& variable1, const std::string& variable2) const throw (Exception) { return tl_->getSecondOrderDerivative(variable1, variable2); }
+    double getSecondOrderDerivative(const std::string& variable) const throw (Exception) { return tl_->getSecondOrderDerivative(variable); }
+    double getFirstOrderDerivative(const std::string& variable) const throw (Exception) { return tl_->getFirstOrderDerivative(variable); } 
+
+    ParameterList getHeightParameters() const;
+
+  private:
+    void initParameters_();
+    void computeBranchLengthsFromHeights_(const Node* node, double height, ParameterList& brlenPl) throw (Exception);
+
+};
+
+} // end of namespace bpp.
+
+#endif //_GLOBALCLOCKTREELIKELIHOODFUNCTIONWRAPPER_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/HomogeneousTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/HomogeneousTreeLikelihood.h
new file mode 100755
index 0000000..8dab14b
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/HomogeneousTreeLikelihood.h
@@ -0,0 +1,98 @@
+//
+// File: HomogeneousTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Tue Oct 9 16:03 2007
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _HOMOGENEOUSTREELIKELIHOOD_H_
+#define _HOMOGENEOUSTREELIKELIHOOD_H_
+
+#include "TreeLikelihood.h"
+#include "../Model/SubstitutionModel.h"
+
+namespace bpp
+{
+
+/**
+ * @brief Specialization of the TreeLikelihood interface for the Homogeneous case.
+ *
+ * Homogeneous models assume a unique substitution model along the tree.
+ * This interface further assumes that  the substitution model is the same for all sites.
+ * For likelihood functions with different model per sites, see SitePartitionHomogeneousTreeLikelihood.
+ *
+ * @see SubstitutionModel, SitePartitionHomogeneousTreeLikelihood.
+ */
+class HomogeneousTreeLikelihood :
+	public virtual TreeLikelihood
+{
+	public:
+#ifndef NO_VIRTUAL_COV
+    HomogeneousTreeLikelihood* clone() const = 0;
+#endif
+
+  public:
+    const SubstitutionModel* getSubstitutionModel(int nodeId, size_t siteIndex) const throw (NodeNotFoundException)
+    {
+      return getSubstitutionModel();
+    }
+
+    SubstitutionModel* getSubstitutionModel(int nodeId, size_t siteIndex) throw (NodeNotFoundException)
+    {
+      return getSubstitutionModel();
+    }
+
+    /**
+     * @return The substitution model attached to this instance.
+     */
+    virtual const SubstitutionModel* getSubstitutionModel() const = 0;
+    
+    /**
+     * @return The substitution model attached to this instance.
+     */
+    virtual SubstitutionModel* getSubstitutionModel() = 0;
+
+    /**
+     * @return Set the substitution model for this instance.
+     * @throw Exception If the model could not be set (for instance, because of a wrong alphabet type).
+     */
+    virtual void setSubstitutionModel(SubstitutionModel* model) throw (Exception) = 0;
+    
+};
+
+} //end of namespace bpp.
+
+#endif	//_HOMOGENEOUSTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/MarginalAncestralStateReconstruction.cpp b/src/Bpp/Phyl/Likelihood/MarginalAncestralStateReconstruction.cpp
new file mode 100644
index 0000000..fe4a673
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/MarginalAncestralStateReconstruction.cpp
@@ -0,0 +1,184 @@
+//
+// File: MarginalAncestralStateReconstruction.cpp
+// Created by: Julien Dutheil
+// Created on: Fri Jul 08 13:32 2005
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "MarginalAncestralStateReconstruction.h"
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Random/RandomTools.h>
+
+using namespace bpp;
+using namespace std;
+
+vector<size_t> MarginalAncestralStateReconstruction::getAncestralStatesForNode(int nodeId, VVdouble& probs, bool sample) const
+{
+  vector<size_t> ancestors(nbDistinctSites_);
+  probs.resize(nbDistinctSites_);
+  double cumProb = 0;
+  double r;
+  if (likelihood_->getTree().isLeaf(nodeId))
+  {
+    VVdouble larray = likelihood_->getLikelihoodData()->getLeafLikelihoods(nodeId);
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      Vdouble* probs_i = &probs[i];
+      probs_i->resize(nbStates_);
+      size_t j = VectorTools::whichMax(larray[i]);
+      ancestors[i] = (int)j;
+      (*probs_i)[j] = 1.;
+    }
+  }
+  else
+  {
+    VVVdouble larray;
+
+    likelihood_->computeLikelihoodAtNode(nodeId, larray);
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      VVdouble* larray_i = &larray[i];
+      Vdouble* probs_i = &probs[i];
+      probs_i->resize(nbStates_);
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* larray_i_c = &(*larray_i)[c];
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          (*probs_i)[x] += (*larray_i_c)[x] * r_[c] / l_[i];
+        }
+      }
+      if (sample)
+      {
+        cumProb = 0;
+        r = RandomTools::giveRandomNumberBetweenZeroAndEntry(1.);
+        for (size_t j = 0; j < nbStates_; j++)
+        {
+          cumProb += (*probs_i)[j];
+          if (r <= cumProb)
+          {
+            ancestors[i] = (int)j;
+            break;
+          }
+        }
+      }
+      else
+        ancestors[i] = VectorTools::whichMax(*probs_i);
+    }
+  }
+  return ancestors;
+}
+
+map<int, vector<size_t> > MarginalAncestralStateReconstruction::getAllAncestralStates() const
+{
+  map<int, vector<size_t> > ancestors;
+  // Clone the data into a AlignedSequenceContainer for more efficiency:
+  AlignedSequenceContainer* data = new AlignedSequenceContainer(*likelihood_->getLikelihoodData()->getShrunkData());
+  recursiveMarginalAncestralStates(tree_.getRootNode(), ancestors, *data);
+  delete data;
+  return ancestors;
+}
+
+Sequence* MarginalAncestralStateReconstruction::getAncestralSequenceForNode(int nodeId, VVdouble* probs, bool sample) const
+{
+  string name = tree_.hasNodeName(nodeId) ? tree_.getNodeName(nodeId) : ("" + TextTools::toString(nodeId));
+  const vector<size_t>* rootPatternLinks = &likelihood_->getLikelihoodData()->getRootArrayPositions();
+  const SubstitutionModel* model = likelihood_->getSubstitutionModel(tree_.getNodesId()[0], 0); // We assume all nodes have a model with the same number of states.
+  vector<size_t> states;
+  vector<int> allStates(nbSites_);
+  VVdouble patternedProbs;
+  if (probs)
+  {
+    states = getAncestralStatesForNode(nodeId, patternedProbs, sample);
+    probs->resize(nbSites_);
+    for (size_t i = 0; i < nbSites_; i++)
+    {
+      allStates[i] = model->getAlphabetChar(states[(*rootPatternLinks)[i]]);
+      (*probs)[i] = patternedProbs[(*rootPatternLinks)[i]];
+    }
+  }
+  else
+  {
+    states = getAncestralStatesForNode(nodeId, patternedProbs, sample);
+    for (size_t i = 0; i < nbSites_; i++)
+    {
+      allStates[i] = model->getAlphabetChar(states[(*rootPatternLinks)[i]]);
+    }
+  }
+  return new BasicSequence(name, allStates, alphabet_);
+}
+
+void MarginalAncestralStateReconstruction::recursiveMarginalAncestralStates(
+  const Node* node,
+  map<int, vector<size_t> >& ancestors,
+  AlignedSequenceContainer& data) const
+{
+  if (node->isLeaf())
+  {
+    vector<int> content = data.getContent(node->getName());
+    vector<size_t>* v = &ancestors[node->getId()];
+    v->resize(content.size());
+    // This is a tricky way to store the real sequence as an ancestral one...
+    // In case of Markov Modulated models, we consider that the real sequences
+    // Are all in the first category.
+    const SubstitutionModel* model = likelihood_->getSubstitutionModel(tree_.getNodesId()[0], 0); // We assume all nodes have a model with the same number of states.
+    for (size_t i = 0; i < content.size(); i++)
+    {
+      (*v)[i] = model->getModelStates(content[i])[0];
+    }
+  }
+  else
+  {
+    ancestors[node->getId()] = getAncestralStatesForNode(node->getId());
+    for (size_t i = 0; i < node->getNumberOfSons(); i++)
+    {
+      recursiveMarginalAncestralStates(node->getSon(i), ancestors, data);
+    }
+  }
+}
+
+AlignedSequenceContainer* MarginalAncestralStateReconstruction::getAncestralSequences(bool sample) const
+{
+  AlignedSequenceContainer* asc = new AlignedSequenceContainer(alphabet_);
+  vector<int> ids = tree_.getInnerNodesId();
+  for (size_t i = 0; i < ids.size(); i++)
+  {
+    Sequence* seq = getAncestralSequenceForNode(ids[i], NULL, sample);
+    asc->addSequence(*seq);
+    delete seq;
+  }
+  return asc;
+}
+
diff --git a/src/Bpp/Phyl/Likelihood/MarginalAncestralStateReconstruction.h b/src/Bpp/Phyl/Likelihood/MarginalAncestralStateReconstruction.h
new file mode 100755
index 0000000..0316956
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/MarginalAncestralStateReconstruction.h
@@ -0,0 +1,199 @@
+//
+// File: MarginalAncestralStateReconstruction.h
+// Created by: Julien Dutheil
+// Created on: Fri Jul 08 13:32 2005
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _MARGINALANCESTRALSTATESRECONSTRUCTION_H_
+#define _MARGINALANCESTRALSTATESRECONSTRUCTION_H_
+
+#include "../AncestralStateReconstruction.h"
+#include "DRTreeLikelihood.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/Alphabet.h>
+#include <Bpp/Seq/Container/AlignedSequenceContainer.h>
+#include <Bpp/Seq/Sequence.h>
+
+// From the STL:
+#include <vector>
+
+namespace bpp
+{
+
+/**
+ * @brief Likelihood ancestral states reconstruction: marginal method.
+ *
+ * Reference:
+ * Z Yang, S Kumar and M Nei (1995), _Genetics_ 141(4) 1641-50.
+ */
+class MarginalAncestralStateReconstruction:
+  public virtual AncestralStateReconstruction
+{
+	private:
+		const DRTreeLikelihood* likelihood_;
+    TreeTemplate<Node> tree_;
+		const Alphabet* alphabet_;
+		size_t nbSites_;
+		size_t nbDistinctSites_;
+		size_t nbClasses_;
+		size_t nbStates_;
+    std::vector<size_t> rootPatternLinks_;
+    std::vector<double> r_;
+    std::vector<double> l_;
+		
+	public:
+		MarginalAncestralStateReconstruction(const DRTreeLikelihood* drl) :
+      likelihood_      (drl),
+      tree_            (drl->getTree()),
+			alphabet_        (drl->getAlphabet()),
+			nbSites_         (drl->getLikelihoodData()->getNumberOfSites()),
+			nbDistinctSites_ (drl->getLikelihoodData()->getNumberOfDistinctSites()),
+			nbClasses_       (drl->getLikelihoodData()->getNumberOfClasses()),
+			nbStates_        (drl->getLikelihoodData()->getNumberOfStates()),
+			rootPatternLinks_(drl->getLikelihoodData()->getRootArrayPositions()),
+      r_               (drl->getRateDistribution()->getProbabilities()),
+      l_               (drl->getLikelihoodData()->getRootRateSiteLikelihoodArray())
+    {}
+
+    MarginalAncestralStateReconstruction(const MarginalAncestralStateReconstruction& masr) :
+      likelihood_      (masr.likelihood_),
+      tree_            (masr.tree_),
+      alphabet_        (masr.alphabet_),
+      nbSites_         (masr.nbSites_),
+      nbDistinctSites_ (masr.nbDistinctSites_),
+      nbClasses_       (masr.nbClasses_),
+      nbStates_        (masr.nbStates_),
+      rootPatternLinks_(masr.rootPatternLinks_),
+      r_               (masr.r_),
+      l_               (masr.l_)
+    {}
+
+    MarginalAncestralStateReconstruction& operator=(const MarginalAncestralStateReconstruction& masr)
+    {
+      likelihood_       = masr.likelihood_;
+      tree_             = masr.tree_;
+      alphabet_         = masr.alphabet_;
+      nbSites_          = masr.nbSites_;
+      nbDistinctSites_  = masr.nbDistinctSites_;
+      nbClasses_        = masr.nbClasses_;
+      nbStates_         = masr.nbStates_;
+      rootPatternLinks_ = masr.rootPatternLinks_;
+      r_                = masr.r_;
+      l_                = masr.l_;
+      return *this;
+    }
+
+
+#ifndef NO_VIRTUAL_COV
+    MarginalAncestralStateReconstruction*
+#else
+    Clonable*
+#endif
+    clone() const { return new MarginalAncestralStateReconstruction(*this); }
+
+		virtual ~MarginalAncestralStateReconstruction() {}
+
+	public:
+
+		/**
+		 * @brief Get ancestral states for a given node as a vector of int.
+		 *
+		 * The size of the vector is the number of distinct sites in the container
+		 * associated to the likelihood object.
+		 * This method is mainly for efficient internal use in other classes.
+		 * Consider using the getAncestralSequenceForNode() method for a more
+		 * general output.
+		 *
+		 * @param nodeId The id of the node at which the states must be reconstructed.
+     * @param probs  A vector to be filled with the probability for each state at each position (will be the same size as the returned vector for states).
+     * @param sample Tell if the sequence should be sample from the posterior distribution instead of taking the one with maximum probability.
+		 * @return A vector of states indices.
+		 * @see getAncestralSequenceForNode
+		 */ 
+    std::vector<size_t> getAncestralStatesForNode(int nodeId, VVdouble& probs, bool sample) const;
+		
+    std::vector<size_t> getAncestralStatesForNode(int nodeId) const
+    {
+      VVdouble probs(nbSites_);
+      return getAncestralStatesForNode(nodeId, probs, false);
+    }
+		
+    std::map<int, std::vector<size_t> > getAllAncestralStates() const;
+
+		/**
+		 * @brief Get the ancestral sequence for a given node.
+		 *
+		 * The name of the sequence will be the name of the node if there is one, its id otherwise.
+		 * A new sequence object is created, whose destruction is up to the user.
+		 *
+		 * @param nodeId The id of the node at which the sequence must be reconstructed.
+     * @param probs  A pointer toward a vector to be filled with the probability for each state at each site (set to NULL if you don't want these probabilities).
+     * @param sample Tell if the sequence should be sample from the posterior distribution instead of taking the one with maximum probability.
+		 * @return A sequence object.
+		 */ 
+		Sequence* getAncestralSequenceForNode(int nodeId, VVdouble* probs, bool sample) const;
+		
+    Sequence* getAncestralSequenceForNode(int nodeId) const
+    {
+      return getAncestralSequenceForNode(nodeId, 0, false);
+    }
+
+    AlignedSequenceContainer* getAncestralSequences() const
+    {
+      return getAncestralSequences(false);
+    }
+
+#ifndef NO_VIRTUAL_COV
+    AlignedSequenceContainer *
+#else
+    SequenceContainer *
+#endif
+    getAncestralSequences(bool sample) const;
+	
+  private:
+		void recursiveMarginalAncestralStates(
+			const Node* node,
+			std::map<int, std::vector<size_t> >& ancestors,
+			AlignedSequenceContainer& data) const;
+
+		
+};
+
+} //end of namespace bpp.
+
+#endif // _MARGINALANCESTRALSTATESRECONSTRUCTION_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/NNIHomogeneousTreeLikelihood.cpp b/src/Bpp/Phyl/Likelihood/NNIHomogeneousTreeLikelihood.cpp
new file mode 100644
index 0000000..3908903
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/NNIHomogeneousTreeLikelihood.cpp
@@ -0,0 +1,363 @@
+//
+// File: DRHomogeneousTreeLikelihood.cpp
+// Created by: Julien Dutheil
+// Created on: Fri Oct 17 18:14:51 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "NNIHomogeneousTreeLikelihood.h"
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Numeric/AutoParameter.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+
+using namespace std;
+
+/*******************************************************************************/
+void BranchLikelihood::initModel(const SubstitutionModel* model, const DiscreteDistribution* rDist)
+{
+  model_ = model;
+  rDist_ = rDist;
+  nbStates_ = model->getNumberOfStates();
+  nbClasses_  = rDist->getNumberOfCategories();
+  pxy_.resize(nbClasses_);
+  for (size_t i = 0; i < nbClasses_; i++)
+  {
+    pxy_[i].resize(nbStates_);
+    for (size_t j = 0; j < nbStates_; j++)
+    {
+      pxy_[i][j].resize(nbStates_);
+    }
+  }
+}
+
+/*******************************************************************************/
+void BranchLikelihood::computeAllTransitionProbabilities()
+{
+  double l = getParameterValue("BrLen");
+
+  // Computes all pxy once for all:
+  for (size_t c = 0; c < nbClasses_; c++)
+  {
+    VVdouble* pxy__c = &pxy_[c];
+    RowMatrix<double> Q = model_->getPij_t(l * rDist_->getCategory(c));
+    for (size_t x = 0; x < nbStates_; x++)
+    {
+      Vdouble* pxy__c_x = &(*pxy__c)[x];
+      for (size_t y = 0; y < nbStates_; y++)
+      {
+        (*pxy__c_x)[y] = Q(x, y);
+      }
+    }
+  }
+}
+
+/*******************************************************************************/
+void BranchLikelihood::computeLogLikelihood()
+{
+  lnL_ = 0;
+
+  vector<double> la(array1_->size());
+  for (size_t i = 0; i < array1_->size(); i++)
+  {
+    double Li = 0;
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      double rc = rDist_->getProbability(c);
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        for (size_t y = 0; y < nbStates_; y++)
+        {
+          Li += rc * (*array1_)[i][c][x] * pxy_[c][x][y] * (*array2_)[i][c][y];
+        }
+      }
+    }
+    la[i] = weights_[i] * log(Li);
+  }
+
+  sort(la.begin(), la.end());
+  for (size_t i = array1_->size(); i > 0; i--)
+  {
+    lnL_ -= la[i - 1];
+  }
+}
+
+/******************************************************************************/
+
+NNIHomogeneousTreeLikelihood::NNIHomogeneousTreeLikelihood(
+  const Tree& tree,
+  SubstitutionModel* model,
+  DiscreteDistribution* rDist,
+  bool checkRooted,
+  bool verbose)
+throw (Exception) :
+  DRHomogeneousTreeLikelihood(tree, model, rDist, checkRooted, verbose),
+  brLikFunction_(0),
+  brentOptimizer_(0),
+  brLenNNIValues_(),
+  brLenNNIParams_()
+{
+  brentOptimizer_ = new BrentOneDimension();
+  brentOptimizer_->setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO);
+  brentOptimizer_->setProfiler(0);
+  brentOptimizer_->setMessageHandler(0);
+  brentOptimizer_->setVerbose(0);
+}
+
+/******************************************************************************/
+
+NNIHomogeneousTreeLikelihood::NNIHomogeneousTreeLikelihood(
+  const Tree& tree,
+  const SiteContainer& data,
+  SubstitutionModel* model,
+  DiscreteDistribution* rDist,
+  bool checkRooted,
+  bool verbose)
+throw (Exception) :
+  DRHomogeneousTreeLikelihood(tree, data, model, rDist, checkRooted, verbose),
+  brLikFunction_(0),
+  brentOptimizer_(0),
+  brLenNNIValues_(),
+  brLenNNIParams_()
+{
+  brentOptimizer_ = new BrentOneDimension();
+  brentOptimizer_->setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO);
+  brentOptimizer_->setProfiler(0);
+  brentOptimizer_->setMessageHandler(0);
+  brentOptimizer_->setVerbose(0);
+  // We have to do this since the DRHomogeneousTreeLikelihood constructor will not call the overloaded setData method:
+  brLikFunction_ = new BranchLikelihood(getLikelihoodData()->getWeights());
+}
+
+/******************************************************************************/
+
+NNIHomogeneousTreeLikelihood::NNIHomogeneousTreeLikelihood(const NNIHomogeneousTreeLikelihood& lik) :
+  DRHomogeneousTreeLikelihood(lik),
+  brLikFunction_(0),
+  brentOptimizer_(0),
+  brLenNNIValues_(),
+  brLenNNIParams_()
+{
+  brLikFunction_  = dynamic_cast<BranchLikelihood*>(lik.brLikFunction_->clone());
+  brentOptimizer_ = dynamic_cast<BrentOneDimension*>(lik.brentOptimizer_->clone());
+  brLenNNIValues_ = lik.brLenNNIValues_;
+  brLenNNIParams_ = lik.brLenNNIParams_;
+}
+
+/******************************************************************************/
+
+NNIHomogeneousTreeLikelihood& NNIHomogeneousTreeLikelihood::operator=(const NNIHomogeneousTreeLikelihood& lik)
+{
+  DRHomogeneousTreeLikelihood::operator=(lik);
+  if (brLikFunction_) delete brLikFunction_;
+  brLikFunction_  = dynamic_cast<BranchLikelihood*>(lik.brLikFunction_->clone());
+  if (brentOptimizer_) delete brentOptimizer_;
+  brentOptimizer_ = dynamic_cast<BrentOneDimension*>(lik.brentOptimizer_->clone());
+  brLenNNIValues_ = lik.brLenNNIValues_;
+  brLenNNIParams_ = lik.brLenNNIParams_;
+  return *this;
+}
+
+/******************************************************************************/
+
+NNIHomogeneousTreeLikelihood::~NNIHomogeneousTreeLikelihood()
+{
+  if (brLikFunction_) delete brLikFunction_;
+  delete brentOptimizer_;
+}
+
+/******************************************************************************/
+double NNIHomogeneousTreeLikelihood::testNNI(int nodeId) const throw (NodeException)
+{
+  const Node* son    = tree_->getNode(nodeId);
+  if (!son->hasFather()) throw NodePException("DRHomogeneousTreeLikelihood::testNNI(). Node 'son' must not be the root node.", son);
+  const Node* parent = son->getFather();
+  if (!parent->hasFather()) throw NodePException("DRHomogeneousTreeLikelihood::testNNI(). Node 'parent' must not be the root node.", parent);
+  const Node* grandFather = parent->getFather();
+  // From here: Bifurcation assumed.
+  // In case of multifurcation, an arbitrary uncle is chosen.
+  // If we are at root node with a trifurcation, this does not matter, since 2 NNI are possible (see doc of the NNISearchable interface).
+  size_t parentPosition = grandFather->getSonPosition(parent);
+  // const Node * uncle = grandFather->getSon(parentPosition > 1 ? parentPosition - 1 : 1 - parentPosition);
+  const Node* uncle = grandFather->getSon(parentPosition > 1 ? 0 : 1 - parentPosition);
+
+  // Retrieving arrays of interest:
+  const DRASDRTreeLikelihoodNodeData* parentData = &getLikelihoodData()->getNodeData(parent->getId());
+  const VVVdouble* sonArray   = &parentData->getLikelihoodArrayForNeighbor(son->getId());
+  vector<const Node*> parentNeighbors = TreeTemplateTools::getRemainingNeighbors(parent, grandFather, son);
+  size_t nbParentNeighbors = parentNeighbors.size();
+  vector<const VVVdouble*> parentArrays(nbParentNeighbors);
+  vector<const VVVdouble*> parentTProbs(nbParentNeighbors);
+  for (size_t k = 0; k < nbParentNeighbors; k++)
+  {
+    const Node* n = parentNeighbors[k]; // This neighbor
+    parentArrays[k] = &parentData->getLikelihoodArrayForNeighbor(n->getId());
+    // if(n != grandFather) parentTProbs[k] = & pxy_[n->getId()];
+    // else                 parentTProbs[k] = & pxy_[parent->getId()];
+    parentTProbs[k] = &pxy_[n->getId()];
+  }
+
+  const DRASDRTreeLikelihoodNodeData* grandFatherData = &getLikelihoodData()->getNodeData(grandFather->getId());
+  const VVVdouble* uncleArray      = &grandFatherData->getLikelihoodArrayForNeighbor(uncle->getId());
+  vector<const Node*> grandFatherNeighbors = TreeTemplateTools::getRemainingNeighbors(grandFather, parent, uncle);
+  size_t nbGrandFatherNeighbors = grandFatherNeighbors.size();
+  vector<const VVVdouble*> grandFatherArrays;
+  vector<const VVVdouble*> grandFatherTProbs;
+  for (size_t k = 0; k < nbGrandFatherNeighbors; k++)
+  {
+    const Node* n = grandFatherNeighbors[k]; // This neighbor
+    if (grandFather->getFather() == NULL || n != grandFather->getFather())
+    {
+      grandFatherArrays.push_back(&grandFatherData->getLikelihoodArrayForNeighbor(n->getId()));
+      grandFatherTProbs.push_back(&pxy_[n->getId()]);
+    }
+  }
+
+  // Compute array 1: grand father array
+  VVVdouble array1 = *sonArray;
+  resetLikelihoodArray(array1);
+  grandFatherArrays.push_back(sonArray);
+  grandFatherTProbs.push_back(&pxy_[son->getId()]);
+  if (grandFather->hasFather())
+  {
+    computeLikelihoodFromArrays(grandFatherArrays, grandFatherTProbs, &grandFatherData->getLikelihoodArrayForNeighbor(grandFather->getFather()->getId()), &pxy_[grandFather->getId()], array1, nbGrandFatherNeighbors, nbDistinctSites_, nbClasses_, nbStates_, false);
+  }
+  else
+  {
+    computeLikelihoodFromArrays(grandFatherArrays, grandFatherTProbs, array1, nbGrandFatherNeighbors + 1, nbDistinctSites_, nbClasses_, nbStates_, false);
+
+    // This is the root node, we have to account for the ancestral frequencies:
+    for (size_t i = 0; i < nbDistinctSites_; i++)
+    {
+      for (size_t j = 0; j < nbClasses_; j++)
+      {
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          array1[i][j][x] *= rootFreqs_[x];
+        }
+      }
+    }
+  }
+
+  // Compute array 2: parent array
+  VVVdouble array2 = *uncleArray;
+  resetLikelihoodArray(array2);
+  parentArrays.push_back(uncleArray);
+  parentTProbs.push_back(&pxy_[uncle->getId()]);
+  computeLikelihoodFromArrays(parentArrays, parentTProbs, array2, nbParentNeighbors + 1, nbDistinctSites_, nbClasses_, nbStates_, false);
+
+  // Initialize BranchLikelihood:
+  brLikFunction_->initModel(model_, rateDistribution_);
+  brLikFunction_->initLikelihoods(&array1, &array2);
+  ParameterList parameters;
+  size_t pos = 0;
+  while (pos < nodes_.size() && nodes_[pos]->getId() != parent->getId()) pos++;
+  if (pos == nodes_.size()) throw Exception("NNIHomogeneousTreeLikelihood::testNNI. Unvalid node id.");
+  Parameter brLen = getParameter("BrLen" + TextTools::toString(pos));
+  brLen.setName("BrLen");
+  parameters.addParameter(brLen);
+  brLikFunction_->setParameters(parameters);
+
+  // Re-estimate branch length:
+  brentOptimizer_->setFunction(brLikFunction_);
+  brentOptimizer_->getStopCondition()->setTolerance(0.1);
+  brentOptimizer_->setInitialInterval(brLen.getValue(), brLen.getValue() + 0.01);
+  brentOptimizer_->init(parameters);
+  brentOptimizer_->optimize();
+  // brLenNNIValues_[nodeId] = brLikFunction_->getParameterValue("BrLen");
+  brLenNNIValues_[nodeId] = brentOptimizer_->getParameters().getParameter("BrLen").getValue();
+  brLikFunction_->resetLikelihoods(); // Array1 and Array2 will be destroyed after this function call.
+                                      // We should not keep pointers towards them...
+
+  // Return the resulting likelihood:
+  return brLikFunction_->getValue() - getValue();
+}
+
+/*******************************************************************************/
+void NNIHomogeneousTreeLikelihood::doNNI(int nodeId) throw (NodeException)
+{
+  // Perform the topological move, the likelihood array will have to be recomputed...
+  Node* son    = tree_->getNode(nodeId);
+  if (!son->hasFather()) throw NodePException("DRHomogeneousTreeLikelihood::testNNI(). Node 'son' must not be the root node.", son);
+  Node* parent = son->getFather();
+  if (!parent->hasFather()) throw NodePException("DRHomogeneousTreeLikelihood::testNNI(). Node 'parent' must not be the root node.", parent);
+  Node* grandFather = parent->getFather();
+  // From here: Bifurcation assumed.
+  // In case of multifurcation, an arbitrary uncle is chosen.
+  // If we are at root node with a trifurcation, this does not matter, since 2 NNI are possible (see doc of the NNISearchable interface).
+  size_t parentPosition = grandFather->getSonPosition(parent);
+  Node* uncle = grandFather->getSon(parentPosition > 1 ? 0 : 1 - parentPosition);
+  // Swap nodes:
+  parent->removeSon(son);
+  grandFather->removeSon(uncle);
+  parent->addSon(uncle);
+  grandFather->addSon(son);
+  size_t pos = 0;
+  while (pos < nodes_.size() && nodes_[pos]->getId() != parent->getId()) pos++;
+  if (pos == nodes_.size()) throw Exception("NNIHomogeneousTreeLikelihood::doNNI. Unvalid node id.");
+
+  string name = "BrLen" + TextTools::toString(pos);
+  if (brLenNNIValues_.find(nodeId) != brLenNNIValues_.end())
+  {
+    double length = brLenNNIValues_[nodeId];
+    brLenParameters_.setParameterValue(name, length);
+    getParameter_(name).setValue(length);
+    parent->setDistanceToFather(length);
+  }
+  else cerr << "ERROR, branch not found: " << nodeId << endl;
+  try
+  {
+    brLenNNIParams_.addParameter(brLenParameters_.getParameter(name));
+  }
+  catch (ParameterException& ex)
+  {
+    StdErr errout;
+    cerr << "DEBUG:" << endl;
+    brLenNNIParams_.printParameters(errout);
+    cerr << "DEBUG:" << name << endl;
+  }
+  // In case of copy of this object, we must remove the constraint associated to this stored parameter:
+  // (It should be also possible to update the pointer in the copy constructor,
+  // but we do not need the constraint info here...).
+  brLenNNIParams_[brLenNNIParams_.size() - 1].removeConstraint();
+}
+
+/*******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Likelihood/NNIHomogeneousTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/NNIHomogeneousTreeLikelihood.h
new file mode 100644
index 0000000..8696147
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/NNIHomogeneousTreeLikelihood.h
@@ -0,0 +1,284 @@
+//
+// File: NNIHomogeneousTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Fri Apr 06 14:16 2007
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _NNIHOMOGENEOUSTREELIKELIHOOD_H_
+#define _NNIHOMOGENEOUSTREELIKELIHOOD_H_
+
+#include "DRHomogeneousTreeLikelihood.h"
+#include "../NNISearchable.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Parametrizable.h>
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+#include <Bpp/Numeric/Function/BrentOneDimension.h>
+
+namespace bpp
+{
+/**
+ * @brief Compute likelihood for a 4-tree.
+ *
+ * This class is used internally by DRHomogeneousTreeLikelihood to test NNI movements.
+ * This function needs:
+ * - two likelihood arrays corresponding to the conditional likelihoods at top and bottom nodes,
+ * - a substitution model and a rate distribution, whose parameters will not be estimated but taken "as is",
+ * It takes only one parameter, the branch length.
+ */
+class BranchLikelihood :
+  public Function,
+  public AbstractParametrizable
+{
+protected:
+  const VVVdouble* array1_, * array2_;
+  const SubstitutionModel* model_;
+  const DiscreteDistribution* rDist_;
+  size_t nbStates_, nbClasses_;
+  VVVdouble pxy_;
+  double lnL_;
+  std::vector<unsigned int> weights_;
+
+public:
+  BranchLikelihood(const std::vector<unsigned int>& weights) :
+    AbstractParametrizable(""),
+    array1_(0),
+    array2_(0),
+    model_(0),
+    rDist_(0),
+    nbStates_(0),
+    nbClasses_(0),
+    pxy_(),
+    lnL_(log(0.)),
+    weights_(weights)
+  {
+    addParameter_(new Parameter("BrLen", 1, 0));
+  }
+
+  BranchLikelihood(const BranchLikelihood& bl) :
+    AbstractParametrizable(bl),
+    array1_(bl.array1_),
+    array2_(bl.array2_),
+    model_(bl.model_),
+    rDist_(bl.rDist_),
+    nbStates_(bl.nbStates_),
+    nbClasses_(bl.nbClasses_),
+    pxy_(bl.pxy_),
+    lnL_(bl.lnL_),
+    weights_(bl.weights_)
+  {}
+
+  BranchLikelihood& operator=(const BranchLikelihood& bl)
+  {
+    AbstractParametrizable::operator=(bl);
+    array1_ = bl.array1_;
+    array2_ = bl.array2_;
+    model_ = bl.model_;
+    rDist_ = bl.rDist_;
+    nbStates_ = bl.nbStates_;
+    nbClasses_ = bl.nbClasses_;
+    pxy_ = bl.pxy_;
+    lnL_ = bl.lnL_;
+    weights_ = bl.weights_;
+    return *this;
+  }
+
+  virtual ~BranchLikelihood() {}
+
+  BranchLikelihood* clone() const { return new BranchLikelihood(*this); }
+
+public:
+  void initModel(const SubstitutionModel* model, const DiscreteDistribution* rDist);
+
+  /**
+   * @warning No checking on alphabet size or number of rate classes is performed,
+   * use with care!
+   */
+  void initLikelihoods(const VVVdouble* array1, const VVVdouble* array2)
+  {
+    array1_ = array1;
+    array2_ = array2;
+  }
+
+  void resetLikelihoods()
+  {
+    array1_ = 0;
+    array2_ = 0;
+  }
+
+  void setParameters(const ParameterList& parameters)
+  throw (ParameterNotFoundException, ConstraintException)
+  {
+    setParametersValues(parameters);
+  }
+
+  double getValue() const throw (Exception) { return lnL_; }
+
+  void fireParameterChanged(const ParameterList& parameters)
+  {
+    computeAllTransitionProbabilities();
+    computeLogLikelihood();
+  }
+
+protected:
+  void computeAllTransitionProbabilities();
+  void computeLogLikelihood();
+};
+
+
+/**
+ * @brief This class adds support for NNI topology estimation to the DRHomogeneousTreeLikelihood class.
+ */
+class NNIHomogeneousTreeLikelihood :
+  public DRHomogeneousTreeLikelihood,
+  public virtual NNISearchable
+{
+protected:
+  BranchLikelihood* brLikFunction_;
+  /**
+   * @brief Optimizer used for testing NNI.
+   */
+  BrentOneDimension* brentOptimizer_;
+
+  /**
+   * @brief Hash used for backing up branch lengths when testing NNIs.
+   */
+  mutable std::map<int, double> brLenNNIValues_;
+
+  ParameterList brLenNNIParams_;
+
+public:
+  /**
+   * @brief Build a new NNIHomogeneousTreeLikelihood object.
+   *
+   * @param tree The tree to use.
+   * @param model The substitution model to use.
+   * @param rDist The rate across sites distribution to use.
+   * @param checkRooted Tell if we have to check for the tree to be unrooted.
+   * If true, any rooted tree will be unrooted before likelihood computation.
+   * @param verbose Should I display some info?
+   * @throw Exception in an error occured.
+   */
+  NNIHomogeneousTreeLikelihood(
+    const Tree& tree,
+    SubstitutionModel* model,
+    DiscreteDistribution* rDist,
+    bool checkRooted = true,
+    bool verbose = true)
+  throw (Exception);
+
+  /**
+   * @brief Build a new NNIHomogeneousTreeLikelihood object.
+   *
+   * @param tree The tree to use.
+   * @param data Sequences to use.
+   * @param model The substitution model to use.
+   * @param rDist The rate across sites distribution to use.
+   * @param checkRooted Tell if we have to check for the tree to be unrooted.
+   * If true, any rooted tree will be unrooted before likelihood computation.
+   * @param verbose Should I display some info?
+   * @throw Exception in an error occured.
+   */
+  NNIHomogeneousTreeLikelihood(
+    const Tree& tree,
+    const SiteContainer& data,
+    SubstitutionModel* model,
+    DiscreteDistribution* rDist,
+    bool checkRooted = true,
+    bool verbose = true)
+  throw (Exception);
+
+  /**
+   * @brief Copy constructor.
+   */
+  NNIHomogeneousTreeLikelihood(const NNIHomogeneousTreeLikelihood& lik);
+
+  NNIHomogeneousTreeLikelihood& operator=(const NNIHomogeneousTreeLikelihood& lik);
+
+  virtual ~NNIHomogeneousTreeLikelihood();
+
+#ifndef NO_VIRTUAL_COV
+  NNIHomogeneousTreeLikelihood*
+#else
+  Clonable*
+#endif
+  clone() const { return new NNIHomogeneousTreeLikelihood(*this); }
+
+public:
+  void setData(const SiteContainer& sites) throw (Exception)
+  {
+    DRHomogeneousTreeLikelihood::setData(sites);
+    if (brLikFunction_) delete brLikFunction_;
+    brLikFunction_ = new BranchLikelihood(getLikelihoodData()->getWeights());
+  }
+
+  /**
+   * @name The NNISearchable interface.
+   *
+   * Current implementation:
+   * When testing a particular NNI, only the branch length of the parent node is optimized (and roughly).
+   * All other parameters (substitution model, rate distribution and other branch length are kept at there current value.
+   * When performing a NNI, only the topology change is performed.
+   * This is up to the user to re-initialize the underlying likelihood data to match the new topology.
+   * Usually, this is achieved by calling the topologyChangePerformed() method, which call the reInit() method of the LikelihoodData object.
+   * @{
+   */
+  const Tree& getTopology() const { return getTree(); }
+
+  double getTopologyValue() const throw (Exception) { return getValue(); }
+
+  double testNNI(int nodeId) const throw (NodeException);
+
+  void doNNI(int nodeId) throw (NodeException);
+
+  void topologyChangeTested(const TopologyChangeEvent& event)
+  {
+    getLikelihoodData()->reInit();
+    // if(brLenNNIParams_.size() > 0)
+    fireParameterChanged(brLenNNIParams_);
+    brLenNNIParams_.reset();
+  }
+
+  void topologyChangeSuccessful(const TopologyChangeEvent& event)
+  {
+    brLenNNIValues_.clear();
+  }
+  /** @} */
+};
+} // end of namespace bpp.
+
+#endif  // _NNIHOMOGENEOUSTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/NonHomogeneousTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/NonHomogeneousTreeLikelihood.h
new file mode 100755
index 0000000..8afc6de
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/NonHomogeneousTreeLikelihood.h
@@ -0,0 +1,123 @@
+//
+// File: NonHomogeneousTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Tue Oct 9 16:03 2007
+// From file: HomogeneousTreeLikelihood.h
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _NONHOMOGENEOUSTREELIKELIHOOD_H_
+#define _NONHOMOGENEOUSTREELIKELIHOOD_H_
+
+#include "TreeLikelihood.h"
+#include "../Model/SubstitutionModelSet.h"
+
+namespace bpp
+{
+
+/**
+ * @brief Specialization of the TreeLikelihood interface for the branch non-homogeneous and non-stationary models.
+ *
+ * The main difference is that the likelihood depends on the position of the root.
+ * The frequencies at the root of the tree are new parameters, which are not necessarily equal to the equilibrium frequencies of the substitution model.
+ *
+ * This interface further assumes that the substitution model is the same for all sites, for a given branch.
+ *
+ * @see SubstitutionModelSet.
+ */
+class NonHomogeneousTreeLikelihood :
+	public virtual TreeLikelihood
+{
+	public:
+#ifndef NO_VIRTUAL_COV
+    NonHomogeneousTreeLikelihood* clone() const = 0;
+#endif
+
+  public:
+    const SubstitutionModel* getSubstitutionModel(int nodeId, size_t siteIndex) const throw (NodeNotFoundException)
+    {
+      return getSubstitutionModelForNode(nodeId);
+    }
+
+    SubstitutionModel* getSubstitutionModel(int nodeId, size_t siteIndex) throw (NodeNotFoundException)
+    {
+      return getSubstitutionModelForNode(nodeId);
+    }
+
+    /**
+     * @brief Get the substitution model associated to a given node.
+     *
+     * @param nodeId The id of the request node.
+     * @return A pointer toward the corresponding model.
+     * @throw NodeNotFoundException This exception may be thrown if the node is not found (depending on the implementation).
+     */
+    virtual const SubstitutionModel* getSubstitutionModelForNode(int nodeId) const throw (NodeNotFoundException) = 0;
+
+    /**
+     * @brief Get the substitution model associated to a given node.
+     *
+     * @param nodeId The id of the request node.
+     * @return A pointer toward the corresponding model.
+     * @throw NodeNotFoundException This exception may be thrown if the node is not found (depending on the implementation).
+     */
+    virtual SubstitutionModel* getSubstitutionModelForNode(int nodeId) throw (NodeNotFoundException) = 0;
+
+    /**
+     * @return The set of substitution models associated to this instance.
+     */
+    virtual const SubstitutionModelSet* getSubstitutionModelSet() const = 0;
+
+    /**
+     * @return The set of substitution models associated to this instance.
+     */
+    virtual SubstitutionModelSet* getSubstitutionModelSet() = 0;
+    
+    /**
+     * @return Set the substitution models for this instance.
+     * @throw Exception If the model could not be set (for instance, because of a wrong alphabet type).
+     */
+    virtual void setSubstitutionModelSet(SubstitutionModelSet* model) throw (Exception) = 0;
+
+    /**
+     * @return The parameters on which the root frequencies depend.
+     */
+    virtual ParameterList getRootFrequenciesParameters() const = 0;
+
+};
+
+} //end of namespace bpp.
+
+#endif	//_NONHOMOGENEOUSTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/PairedSiteLikelihoods.cpp b/src/Bpp/Phyl/Likelihood/PairedSiteLikelihoods.cpp
new file mode 100644
index 0000000..231e4b5
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/PairedSiteLikelihoods.cpp
@@ -0,0 +1,189 @@
+//
+// File: PairedSiteLikelihoods.cpp
+// Created by: Nicolas Rochette
+// Created on: January 6, 2011
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+// From the STL
+#include <vector>
+#include <string>
+#include <numeric>
+#include <cmath>
+
+#include "PairedSiteLikelihoods.h"
+#include "TreeLikelihood.h"
+
+using namespace std;
+using namespace bpp;
+
+/***
+ * Constructors:
+ ***/
+
+PairedSiteLikelihoods::PairedSiteLikelihoods() :
+  logLikelihoods_(),
+  modelNames_()
+{}
+
+PairedSiteLikelihoods::PairedSiteLikelihoods(
+  const vector<vector<double> >& siteLogLikelihoods,
+  const vector<string>& modelNames) throw (Exception) :
+  logLikelihoods_(siteLogLikelihoods),
+  modelNames_(modelNames)
+{
+  if (modelNames_.size() != getNumberOfModels())
+  {
+    if (modelNames_.size() == 0)
+      modelNames_.assign(getNumberOfModels(), string());
+    else
+      throw Exception("PairedSiteLikelihoods: There should be as many model names as model site-loglikelihoods records.");
+  }
+
+  if (this->getNumberOfModels() > 0)
+  {
+    for (vector<vector<double> >::const_iterator siteLLiks = siteLogLikelihoods.begin();
+         siteLLiks != siteLogLikelihoods.end();
+         ++siteLLiks)
+    {
+      if (siteLLiks->size() != getNumberOfSites())
+        throw Exception("PairedSiteLikelihoods: Models site-loglikelihoods records do not have the same number of elements.");
+    }
+  }
+}
+
+void PairedSiteLikelihoods::appendModel(
+  const vector<double>& siteLogLikelihoods,
+  const string& modelName
+  ) throw (Exception)
+{
+  if (getNumberOfModels() > 0 && siteLogLikelihoods.size() != getNumberOfSites())
+    throw Exception("PairedSiteLikelihoods::appendModel: Model site-loglikelihoods record does not have the correct number of elements");
+
+  logLikelihoods_.push_back(siteLogLikelihoods);
+  modelNames_.push_back(modelName);
+}
+
+void PairedSiteLikelihoods::appendModel(const bpp::TreeLikelihood& treeLikelihood) throw (Exception)
+{
+  const vector<double>& siteLogLikelihoods = treeLikelihood.getLogLikelihoodForEachSite();
+  const string& modelName = treeLikelihood.getTree().getName();
+
+  PairedSiteLikelihoods::appendModel(siteLogLikelihoods, modelName);
+}
+
+void PairedSiteLikelihoods::appendModels(const PairedSiteLikelihoods& psl)  throw (Exception)
+{
+  if (getNumberOfModels() > 0 && psl.getNumberOfModels() > 0 && psl.getNumberOfSites() != getNumberOfSites())
+    throw Exception("PairedSiteLikelihoods::appendModels: The two PairedSiteLikelihood objects have different number of sites.");
+
+  logLikelihoods_.insert(logLikelihoods_.end(),
+                        psl.logLikelihoods_.begin(),
+                        psl.logLikelihoods_.end()
+                        );
+
+  modelNames_.insert(modelNames_.end(),
+                    psl.modelNames_.begin(),
+                    psl.modelNames_.end()
+                    );
+}
+
+
+pair<vector<string>, vector<double> > PairedSiteLikelihoods::computeExpectedLikelihoodWeights (int replicates) const
+{
+  // Initialize the weights
+  vector<double> weights(getNumberOfModels(), 0);
+
+  // Sum the model weights over replicates
+  for (int r = 0; r < replicates; ++r)
+  {
+    // Draw the pseudoreplicate
+    vector<int> siteCounts = bootstrap(getNumberOfSites());
+
+    // Compute the loglikelihood of each model for this replicate
+    vector<double> models_logliks (getNumberOfModels(), 0);
+    for (size_t m = 0; m < getNumberOfModels(); ++m)
+    {
+      const vector<double>& modelSiteLLiks = logLikelihoods_.at(m);
+      double Y = 0;
+      for (size_t s = 0; s < getNumberOfSites(); ++s)
+      {
+        Y += modelSiteLLiks.at(s) * siteCounts.at(s);
+      }
+      models_logliks.at(m) = Y;
+    }
+
+    // Get the best loglikelihood
+    double Ymax = *max_element(models_logliks.begin(), models_logliks.end());
+
+    // Get the exponentials of the loglikelihood differences
+    // and the sum of these values
+    vector<double> exp_logliks_diffs (getNumberOfModels(), 0);
+    for (size_t m = 0; m < getNumberOfModels(); ++m)
+    {
+      exp_logliks_diffs.at(m) = exp(models_logliks.at(m) - Ymax);
+    }
+
+    double sumELLD = accumulate(exp_logliks_diffs.begin(), exp_logliks_diffs.end(), 0.0);
+
+    // Get the models weights for this replicate
+    for (size_t m = 0; m < getNumberOfModels(); ++m)
+    {
+      double w = exp_logliks_diffs.at(m) / sumELLD;
+      weights.at(m) += w;
+    }
+  } //for replicates
+
+  // Divide all weights by the number of replicates.
+  for (vector<double>::iterator w = weights.begin(); w != weights.end(); ++w)
+  {
+    *w /= replicates;
+  }
+
+  return make_pair(modelNames_, weights);
+}
+
+std::vector<int> PairedSiteLikelihoods::bootstrap(std::size_t length, double scaling)
+{
+  vector<int> v(length, 0);
+
+  for (size_t i = 0; i < static_cast<size_t>(static_cast<double>(length) * scaling + 0.5); ++i)
+  {
+    ++v.at(RandomTools::giveIntRandomNumberBetweenZeroAndEntry(static_cast<int>(length)));
+  }
+
+  return v;
+}
+
diff --git a/src/Bpp/Phyl/Likelihood/PairedSiteLikelihoods.h b/src/Bpp/Phyl/Likelihood/PairedSiteLikelihoods.h
new file mode 100644
index 0000000..705ccdf
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/PairedSiteLikelihoods.h
@@ -0,0 +1,195 @@
+//
+// File: PairedSiteLikelihoods.h
+// Created by: Nicolas Rochette
+// Created on: January 6, 2011
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _PAIREDSITELLIKELIHOODS_H_
+#define _PAIREDSITELLIKELIHOODS_H_
+
+// From the STL:
+#include <vector>
+#include <string>
+
+// From Bio++
+#include "TreeLikelihood.h"
+#include <Bpp/Exceptions.h>
+
+namespace bpp
+{
+/**
+ * @brief A container for paired-site likelihoods (likelihoods over
+ * the same sites for different models, especially topologies).
+ * An instance of this class is, roughly, a list of models, each of
+ * them having a name (stored in the <i>modelNames</i> attribute) and
+ * a set of site likelihoods (stored in the <i>logLikelihoods</i> attribute).
+ */
+class PairedSiteLikelihoods
+{
+private:
+  std::vector<std::vector<double> > logLikelihoods_;
+  std::vector<std::string> modelNames_;
+
+public:
+  PairedSiteLikelihoods();
+
+  /**
+   * @brief Build a new object from a site likelihoods array.
+   *
+   * @param siteLogLikelihoods An nmodels*nsites array of loglikelihoods.
+   * @param modelNames <i>(Optional)</i> The names of the models.
+   *
+   * @throw Exception If the number of sites differ between the models,
+   * or if the number of names and site loglikelihood records differ.
+   */
+  PairedSiteLikelihoods(
+    const std::vector<std::vector<double> >& siteLogLikelihoods,
+    const std::vector<std::string>& modelNames = std::vector<std::string>()
+    ) throw (Exception);
+
+  ~PairedSiteLikelihoods() {}
+
+  /**
+   * @brief Append a model.
+   *
+   * @param siteLogLikelihoods The loglikelihoods of the sites under this model.
+   * @param modelName The name of the model.
+   *
+   * @throw Exception If the number of sites is not the same as in the container.
+   */
+  void appendModel(
+    const std::vector<double>& siteLogLikelihoods,
+    const std::string& modelName = "") throw (Exception);
+
+  /**
+   * @brief Append a model.
+   *
+   * @param treelikelihood A TreeLikelihood record.
+   *
+   * @throw Exception If the number of sites is not the same as in the container.
+   */
+  void appendModel(const bpp::TreeLikelihood& treelikelihood) throw (Exception);
+
+  /**
+   * @brief Append models by concatenation.
+   *
+   * @param psl the PairedSiteLikelihoods object to append to the caller.
+   *
+   * @throw Exception If the number of sites in the two object is not equal.
+   */
+  void appendModels(const PairedSiteLikelihoods& psl) throw (Exception);
+
+  /**
+   * @return The site-likelihoods of all models.
+   */
+  const std::vector<std::vector<double> >& getLikelihoods() const
+  {
+    return logLikelihoods_;
+  }
+
+  /**
+   * @return The model names.
+   */
+  const std::vector<std::string>& getModelNames() const
+  {
+    return modelNames_;
+  }
+
+  /** @brief Get the number of models in the container. */
+  size_t getNumberOfModels() const
+  {
+    return logLikelihoods_.size();
+  }
+
+  /**
+   * @return The number of sites for each model.
+   * @throw Exception If the container is empty.
+   */
+  std::size_t getNumberOfSites() const throw (Exception)
+  {
+    try
+    {
+      return logLikelihoods_.at(0).size();
+    }
+    catch (std::out_of_range&)
+    {
+      throw Exception("PairedSiteLikelihoods::nsites: The container is empty, there isn't a number of sites.");
+    }
+  }
+
+  /**
+   * @brief Set the name of a model.
+   *
+   * @param pos The position of the target model.
+   * @param name The new name.
+   */
+  void setName(std::size_t pos, std::string& name)
+  {
+    modelNames_.at(pos) = name;
+  }
+
+  /**
+   * @brief Compute the Expected Likelihood Weights of the models.
+   *
+   * The weight \f$W_m\f$ of a model is :
+   * \f[
+   * W_m
+   * = \frac{1}{B} \sum_{b \in B} \frac{L_m^{(b)}}{\sum L_k^{(b)}}
+   * = \frac{1}{B} \sum_{b \in B} \frac{exp(Y^{(b)}_m - Ymax^{(b)})}{\sum exp(Y_k^{(b)} - Y_{max}^{(b)})}
+   * \f]
+   * where \f$Y_k^{(b)}\f$ is the loglikelihood of model k for replicate b.
+   * @return A pair of vectors containing the names and weights of the models.
+   *
+   * @param replicates The number of pseudoreplicates over which the weights are to be averaged.
+   */
+  std::pair< std::vector<std::string>, std::vector<double> > computeExpectedLikelihoodWeights(int replicates = 10000) const;
+
+  /**
+   * @brief Draw a nonparametric pseudoreplicate
+   *
+   * @param length The length of the data.
+   * @param scaling The length of the pseudoreplicate, in fraction of
+   *  the length of the data.
+   *
+   * @return A vector of the same length as the data, containing the count
+   * of each element in the pseudoreplicate.
+   */
+  static std::vector<int> bootstrap(std::size_t length, double scaling = 1);
+  
+};
+} // namespace bpp.
+
+#endif  //_PAIREDSITELLIKELIHOODS_H_
diff --git a/src/Bpp/Phyl/Likelihood/PseudoNewtonOptimizer.cpp b/src/Bpp/Phyl/Likelihood/PseudoNewtonOptimizer.cpp
new file mode 100755
index 0000000..d5785fc
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/PseudoNewtonOptimizer.cpp
@@ -0,0 +1,194 @@
+//
+// File: PseudoNewtonOptimizer.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Nov 16 12:33 2004
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+/**************************************************************************/
+
+#include "../TreeTemplateTools.h"
+#include "PseudoNewtonOptimizer.h"
+#include "DRHomogeneousTreeLikelihood.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Function/ConjugateGradientMultiDimensions.h>
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/App/ApplicationTools.h>
+
+using namespace bpp;
+
+/**************************************************************************/
+           
+double PseudoNewtonOptimizer::PNStopCondition::getCurrentTolerance() const
+{
+  return NumTools::abs<double>(
+      dynamic_cast<const PseudoNewtonOptimizer*>(optimizer_)->currentValue_ -
+      dynamic_cast<const PseudoNewtonOptimizer*>(optimizer_)->previousValue_); 
+}
+ 
+/**************************************************************************/
+           
+bool PseudoNewtonOptimizer::PNStopCondition::isToleranceReached() const
+{
+  return getCurrentTolerance() < tolerance_; 
+}
+   
+/**************************************************************************/
+  
+PseudoNewtonOptimizer::PseudoNewtonOptimizer(DerivableSecondOrder* function) :
+  AbstractOptimizer(function),
+  previousPoint_(),
+  previousValue_(0),
+  n_(0),
+  params_(),
+  maxCorrection_(10),
+  useCG_(true)
+{
+  setDefaultStopCondition_(new FunctionStopCondition(this));
+  setStopCondition(*getDefaultStopCondition());
+}
+
+/**************************************************************************/
+
+void PseudoNewtonOptimizer::doInit(const ParameterList& params) throw (Exception)
+{
+  n_ = getParameters().size();
+  params_ = getParameters().getParameterNames();
+  getFunction()->enableSecondOrderDerivatives(true);
+  getFunction()->setParameters(getParameters());
+}
+
+/**************************************************************************/
+
+double PseudoNewtonOptimizer::doStep() throw (Exception)
+{
+  ParameterList* bckPoint = 0;
+  if (updateParameters()) bckPoint = new ParameterList(getFunction()->getParameters());
+  double newValue = 0;
+  // Compute derivative at current point:
+  std::vector<double> movements(n_);
+  ParameterList newPoint = getParameters();
+  for (size_t i = 0; i < n_; i++)
+  {
+    double  firstOrderDerivative = getFunction()->getFirstOrderDerivative(params_[i]);
+    double secondOrderDerivative = getFunction()->getSecondOrderDerivative(params_[i]);
+    if (secondOrderDerivative == 0)
+    {
+      movements[i] = 0;
+    }
+    else if (secondOrderDerivative < 0)
+    {
+      printMessage("!!! Second order derivative is negative for parameter " + params_[i] + "(" + TextTools::toString(getParameters()[i].getValue()) + "). Moving in the other direction.");
+      //movements[i] = 0;  // We want to reach a minimum, not a maximum!
+      // My personnal improvement:
+      movements[i] = -firstOrderDerivative / secondOrderDerivative;
+    }
+    else movements[i] = firstOrderDerivative / secondOrderDerivative;
+    if (std::isnan(movements[i]))
+    {
+      printMessage("!!! Non derivable point at " + params_[i] + ". No move performed. (f=" + TextTools::toString(currentValue_) + ", d1=" + TextTools::toString(firstOrderDerivative) + ", d2=" + TextTools::toString(secondOrderDerivative) + ").");
+      movements[i] = 0; // Either first or second order derivative is infinity. This may happen when the function == inf at this point.
+    }
+    //DEBUG:
+    //cerr << "PN[" << params_[i] << "]=" << getParameters().getParameter(params_[i]).getValue() << "\t" << movements[i] << "\t " << firstOrderDerivative << "\t" << secondOrderDerivative << endl;
+    newPoint[i].setValue(getParameters()[i].getValue() - movements[i]);
+    //Correct the movement in case of constraint (this is used in case of Felsenstein-Churchill correction:
+    movements[i] = getParameters()[i].getValue() - newPoint[i].getValue(); 
+  }
+  newValue = getFunction()->f(newPoint);
+
+  // Check newValue:
+  unsigned int count = 0;
+  while ((count < maxCorrection_) && ((newValue > currentValue_ + getStopCondition()->getTolerance()) || std::isnan(newValue))) {
+    //Restore previous point (all parameters in case of global constraint):
+    if ((count==0) && updateParameters()) getFunction()->setParameters(*bckPoint);
+    
+    if (!(useCG_ && (count==3))){
+      printMessage("!!! Function at new point is greater than at current point: " + TextTools::toString(newValue) + ">" + TextTools::toString(currentValue_) + ". Applying Felsenstein-Churchill correction: " + TextTools::toString(count));
+        
+      for (size_t i = 0; i < movements.size(); i++) {
+        movements[i] = movements[i] / 2;
+        newPoint[i].setValue(getParameters()[i].getValue() - movements[i]);
+      }
+      newValue = getFunction()->f(newPoint);
+    }
+    else {
+      printMessage("!!! Felsenstein-Churchill correction applied too many times.");
+      printMessage("Use conjugate gradients optimization.");
+      getFunction()->enableSecondOrderDerivatives(false);
+      ConjugateGradientMultiDimensions opt(getFunction());
+      opt.setConstraintPolicy(getConstraintPolicy());
+      opt.setProfiler(getProfiler());
+      opt.setMessageHandler(getMessageHandler());
+      opt.setVerbose(0);
+      double tol = std::max(getStopCondition()->getCurrentTolerance() / 2., getStopCondition()->getTolerance());
+      opt.getStopCondition()->setTolerance(tol);
+      opt.setMaximumNumberOfEvaluations(nbEvalMax_);
+      getFunction()->setParameters(getParameters());
+      opt.init(getParameters());
+      opt.optimize();
+      newPoint = opt.getParameters();
+      newValue = opt.getFunctionValue();
+      
+      if (newValue > currentValue_ + tol) {
+        printMessage("!!! Conjugate gradient method failed to improve likelihood.");
+        printMessage("Back to Felsenstein-Churchill method.");
+      }
+    }
+    count++;
+  }
+  
+  if (newValue > currentValue_ + getStopCondition()->getTolerance()){
+    printMessage("PseudoNewtonOptimizer::doStep. Value could not be ameliorated!");
+    newValue = currentValue_;
+  }
+  else  {
+    //getFunction()->enableFirstOrderDerivatives(true);
+    getFunction()->enableSecondOrderDerivatives(true);
+    getFunction()->setParameters(newPoint); //Compute derivatives for this point
+    
+    previousPoint_ = getParameters();
+    previousValue_ = currentValue_;
+    getParameters_() = newPoint;
+  }
+
+  if (updateParameters()) delete bckPoint;
+  return newValue;
+  
+}
+
+/**************************************************************************/
+
diff --git a/src/Bpp/Phyl/Likelihood/PseudoNewtonOptimizer.h b/src/Bpp/Phyl/Likelihood/PseudoNewtonOptimizer.h
new file mode 100755
index 0000000..fb17179
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/PseudoNewtonOptimizer.h
@@ -0,0 +1,139 @@
+//
+// File: PseudoNewtonOptimizer.h
+// Created by; Julien Dutheil
+// Created on: Tue Nov 16 11:52 2004
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _PSEUDONEWTONOPTIMIZER_H_
+#define _PSEUDONEWTONOPTIMIZER_H_
+
+#include <Bpp/Numeric/Function/AbstractOptimizer.h>
+
+namespace bpp
+{
+
+  /**
+   * @brief This Optimizer implements Newton's algorithm for finding a minimum of a function.
+   * This is in fact a modified version of the algorithm, as suggested by Nicolas Galtier, for
+   * the purpose of optimizing phylogenetic likelihoods.
+   *
+   * Only second simple order derivative are computed, no cross derivative, following Galtier's
+   * algorithm.
+   * Felsenstein and Churchill's (1996) correction is applied when new trial as a likelihood
+   * lower than the starting point.
+   */
+  class PseudoNewtonOptimizer:
+    public AbstractOptimizer
+  {
+  public:
+    class PNStopCondition:
+      public AbstractOptimizationStopCondition
+    {
+    public:
+      PNStopCondition(PseudoNewtonOptimizer* pno) :
+        AbstractOptimizationStopCondition(pno) {}
+      virtual ~PNStopCondition() {}
+
+      PNStopCondition* clone() const { return new PNStopCondition(*this); }
+          
+    public:
+      bool isToleranceReached() const;
+      double getCurrentTolerance() const;
+    };
+   
+    friend class PNStopCondition;
+         
+  private:
+
+    ParameterList previousPoint_; // Current point is in parameters_
+
+    double previousValue_;
+
+    size_t n_; // Number of parameters
+
+    std::vector<std::string> params_; // All parameter names
+
+    unsigned int maxCorrection_;
+
+    bool useCG_;
+
+  public:
+
+    PseudoNewtonOptimizer(DerivableSecondOrder* function);
+
+    virtual ~PseudoNewtonOptimizer() {}
+
+    PseudoNewtonOptimizer* clone() const { return new PseudoNewtonOptimizer(*this); }
+
+  public:
+    const DerivableSecondOrder* getFunction() const
+    {
+      return dynamic_cast<const DerivableSecondOrder*>(AbstractOptimizer::getFunction());
+    }
+    DerivableSecondOrder* getFunction()
+    {
+      return dynamic_cast<DerivableSecondOrder*>(AbstractOptimizer::getFunction());
+    }
+
+    /**
+     * @name The Optimizer interface.
+     *
+     * @{
+     */
+    double getFunctionValue() const throw (NullPointerException) { return currentValue_; }
+    /** @} */
+
+    void doInit(const ParameterList& params) throw (Exception);
+
+    double doStep() throw (Exception);
+
+    void setMaximumNumberOfCorrections(unsigned int mx) { maxCorrection_ = mx; }
+
+    void disableCG() { useCG_ = false; }
+
+  protected:
+    DerivableSecondOrder* getFunction_()
+    {
+      return dynamic_cast<DerivableSecondOrder*>(AbstractOptimizer::getFunction_());
+    }
+    
+
+  };
+
+} //end of namespace bpp.
+
+#endif //_PSEUDONEWTONOPTIMIZER_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/RASTools.cpp b/src/Bpp/Phyl/Likelihood/RASTools.cpp
new file mode 100644
index 0000000..4f55083
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/RASTools.cpp
@@ -0,0 +1,73 @@
+//
+// File: RASTools.cpp
+// Created by: Julien Dutheil <Julien.Dutheil at univ-montp2.fr>
+// Created on: May 24 2004
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "RASTools.h"
+
+#include <Bpp/Numeric/Prob/SimpleDiscreteDistribution.h>
+
+using namespace bpp;
+
+// From the STL
+#include <map>
+
+using namespace std;
+
+DiscreteDistribution* RASTools::getPosteriorRateDistribution(
+  const DiscreteRatesAcrossSitesTreeLikelihood& treeLikelihood)
+{
+  // Get all posterior rate classes for each sites:
+  vector<size_t> classes = treeLikelihood.getRateClassWithMaxPostProbOfEachSite();
+  map<size_t, size_t> counts;
+  for (size_t i = 0; i < classes.size(); i++)
+  {
+    counts[classes[i]]++;
+  }
+
+  // Now compute the distribution:
+  const DiscreteDistribution* rDist = treeLikelihood.getRateDistribution();
+  map<double, double> distribution;
+  for (map<size_t, size_t>::iterator i = counts.begin(); i != counts.end(); i++)
+  {
+    distribution[rDist->getCategory(i->first)] = (double)i->second / (double)classes.size();
+  }
+
+  // Build a new distribution and return it:
+  return new SimpleDiscreteDistribution(distribution);
+}
+
diff --git a/src/Bpp/Phyl/Likelihood/RASTools.h b/src/Bpp/Phyl/Likelihood/RASTools.h
new file mode 100755
index 0000000..9493958
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/RASTools.h
@@ -0,0 +1,76 @@
+//
+// File: RASTools.h
+// Created by: Julien Dutheil
+// Created on: May 24 2004
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+Julien.Dutheil at univ-montp2.fr
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _RASTOOLS_H_
+#define _RASTOOLS_H_
+
+#include "DiscreteRatesAcrossSitesTreeLikelihood.h"
+
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+
+namespace bpp
+{
+
+/**
+ * @brief Tools to deal with Rates Across Sites (RAS) models.
+ */
+class RASTools
+{
+	public:
+
+		/**
+		 * @brief Get the rate distribution estimated from a dataset.
+		 *
+		 * This methods takes an objet implementing the DiscreteRatesAcroossSites
+		 * interface as input and use the posterior probabilities of rates for each site
+		 * to generate the corresponding distribution.
+		 *
+		 * @param treeLikelihood A Likelihood calculation implmenting the RAS model interface.
+		 * @return The posterior distribution of rate classes.
+		 */
+		static DiscreteDistribution * getPosteriorRateDistribution(
+				const DiscreteRatesAcrossSitesTreeLikelihood & treeLikelihood);
+};
+
+} //end of namespace bpp.
+
+#endif // _RASTOOLS_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/RHomogeneousClockTreeLikelihood.cpp b/src/Bpp/Phyl/Likelihood/RHomogeneousClockTreeLikelihood.cpp
new file mode 100644
index 0000000..a82f034
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/RHomogeneousClockTreeLikelihood.cpp
@@ -0,0 +1,218 @@
+//
+// File: RHomogeneousClockTreeLikelihood.cpp
+// Created by: Benoît Nabholz
+//             Julien Dutheil
+// Created on: Fri Apr 06 14:11 2007
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "RHomogeneousClockTreeLikelihood.h"
+#include "../TreeTemplateTools.h"
+
+#include <iostream>
+
+using namespace std;
+
+#include <Bpp/App/ApplicationTools.h>
+
+using namespace bpp;
+
+/******************************************************************************/
+
+RHomogeneousClockTreeLikelihood::RHomogeneousClockTreeLikelihood(
+  const Tree & tree,
+  SubstitutionModel * model,
+  DiscreteDistribution * rDist,
+  bool checkRooted,
+  bool verbose)
+throw (Exception):
+  RHomogeneousTreeLikelihood(tree, model, rDist, false, verbose, true)
+{
+  init_();
+}
+
+/******************************************************************************/
+
+RHomogeneousClockTreeLikelihood::RHomogeneousClockTreeLikelihood(
+  const Tree & tree,
+  const SiteContainer & data,
+  SubstitutionModel * model,
+  DiscreteDistribution * rDist,
+  bool checkRooted,
+  bool verbose)
+throw (Exception):
+  RHomogeneousTreeLikelihood(tree, data, model, rDist, false, verbose, true)
+{
+  init_();
+}
+
+/******************************************************************************/
+
+void RHomogeneousClockTreeLikelihood::init_()
+{
+  //Check if the tree is rooted:
+  if (!tree_->isRooted()) throw Exception("RHomogeneousClockTreeLikelihood::init_(). Tree is unrooted!");
+  if (TreeTemplateTools::isMultifurcating(*tree_->getRootNode())) throw Exception("HomogeneousClockTreeLikelihood::init_(). Tree is multifurcating.");
+  setMinimumBranchLength(0.);
+}
+
+/******************************************************************************/
+
+void RHomogeneousClockTreeLikelihood::applyParameters() throw (Exception)
+{
+  if (!initialized_) throw Exception("RHomogeneousClockTreeLikelihood::applyParameters(). Object not initialized.");
+   //Apply branch lengths:
+  brLenParameters_.matchParametersValues(getParameters());
+  computeBranchLengthsFromHeights(tree_->getRootNode(), brLenParameters_.getParameter("TotalHeight").getValue());
+
+  //Apply substitution model parameters:
+  model_->matchParametersValues(getParameters());
+  //Apply rate distribution parameters:
+  rateDistribution_->matchParametersValues(getParameters());
+}
+
+/******************************************************************************/
+
+void RHomogeneousClockTreeLikelihood::fireParameterChanged(const ParameterList& params)
+{
+  applyParameters();
+
+  computeAllTransitionProbabilities();
+
+  computeTreeLikelihood();
+  
+  minusLogLik_ = - getLogLikelihood();
+}
+
+/******************************************************************************/
+
+void RHomogeneousClockTreeLikelihood::initBranchLengthsParameters()
+{
+  //Check branch lengths first:
+  for(unsigned int i = 0; i < nbNodes_; i++)
+  {
+    double d = minimumBrLen_;
+    if(!nodes_[i]->hasDistanceToFather())
+    {
+      ApplicationTools::displayWarning("Missing branch length " + TextTools::toString(i) + ". Value is set to " + TextTools::toString(minimumBrLen_));
+      nodes_[i]->setDistanceToFather(minimumBrLen_);
+    }
+    else
+    {
+      d = nodes_[i]->getDistanceToFather();
+      if (d < minimumBrLen_)
+      {
+        ApplicationTools::displayWarning("Branch length " + TextTools::toString(i) + " is too small: " + TextTools::toString(d) + ". Value is set to " + TextTools::toString(minimumBrLen_));
+        nodes_[i]->setDistanceToFather(minimumBrLen_);
+      }
+    }
+  }
+
+  brLenParameters_.reset();
+
+  map<const Node*, double> heights;
+  TreeTemplateTools::getHeights(*tree_->getRootNode(), heights);
+  double totalHeight = heights[tree_->getRootNode()];
+  brLenParameters_.addParameter(Parameter("TotalHeight", totalHeight, brLenConstraint_->clone(), true)); 
+  for (map<const Node *, double>::iterator it = heights.begin(); it != heights.end(); it++)
+  {
+    if (!it->first->isLeaf() && it->first->hasFather())
+    {
+      double fatherHeight = heights[it->first->getFather()];
+      brLenParameters_.addParameter(Parameter("HeightP" + TextTools::toString(it->first->getId()), it->second / fatherHeight, &Parameter::PROP_CONSTRAINT_IN));
+    }
+  }
+}
+
+/******************************************************************************/
+
+void RHomogeneousClockTreeLikelihood::computeBranchLengthsFromHeights(Node* node, double height) throw (Exception)
+{
+  for (unsigned int i = 0; i < node->getNumberOfSons(); i++)
+  {
+    Node* son = node->getSon(i);
+    if (son->isLeaf())
+    {
+      son->setDistanceToFather(std::max(minimumBrLen_, height));
+    }
+    else
+    {
+      Parameter* p = &brLenParameters_.getParameter(string("HeightP") + TextTools::toString(son->getId()));
+      double sonHeightP = p->getValue();
+      double sonHeight = sonHeightP * height;
+      son->setDistanceToFather(std::max(minimumBrLen_, height - sonHeight));
+      computeBranchLengthsFromHeights(son, sonHeight);
+    }
+  }
+}
+
+/******************************************************************************/
+
+ParameterList RHomogeneousClockTreeLikelihood::getDerivableParameters() const throw (Exception)
+{
+  if (!initialized_) throw Exception("RHomogeneousClockTreeLikelihood::getDerivableParameters(). Object is not initialized.");
+  return ParameterList();
+}
+
+/******************************************************************************/
+
+ParameterList RHomogeneousClockTreeLikelihood::getNonDerivableParameters() const throw (Exception)
+{
+  if (!initialized_) throw Exception("RHomogeneousClockTreeLikelihood::getNonDerivableParameters(). Object is not initialized.");
+  return getParameters();
+}
+
+/******************************************************************************
+ *                           First Order Derivatives                          *
+ ******************************************************************************/  
+
+double RHomogeneousClockTreeLikelihood::getFirstOrderDerivative(const std::string& variable) const
+throw (Exception)
+{ 
+  throw Exception("No first order derivative is implemented for this function.");
+}
+
+/******************************************************************************
+ *                           Second Order Derivatives                         *
+ ******************************************************************************/  
+
+double RHomogeneousClockTreeLikelihood::getSecondOrderDerivative(const std::string& variable) const
+throw (Exception)
+{
+  throw Exception("No second order derivative is implemented for this function.");
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Likelihood/RHomogeneousClockTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/RHomogeneousClockTreeLikelihood.h
new file mode 100644
index 0000000..35e9e6a
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/RHomogeneousClockTreeLikelihood.h
@@ -0,0 +1,168 @@
+//
+// File: RHomogeneousClockTreeLikelihood.h
+// Created by: Benoît Nabholz
+//             Julien Dutheil
+// Created on: Fri Apr 06 14:11 2007
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _RHOMOGENEOUSCLOCKTREELIKELIHOOD_H_
+#define _RHOMOGENEOUSCLOCKTREELIKELIHOOD_H_
+
+#include "RHomogeneousTreeLikelihood.h"
+#include "ClockTreeLikelihood.h"
+#include "../TreeTemplate.h"
+
+#include <Bpp/Numeric/ParameterList.h>
+
+namespace bpp
+{
+
+/**
+ *@brief Likelihood computation with a global clock.
+ *
+ * This class overrides the HomogeneousTreeLikelihood class, and change the branch length parameters
+ * which are the heights of the ancestral nodes.
+ * Heights are coded as percentage (HeightP) of the height of their father + the total height of the tree (TotalHeight).
+ * This parametrization resolve the linear constraint between heights, but has the limitation that the first and second
+ * order derivatives for HeightP parameters are not (easilly) computable analytically, and one may wish to use numerical
+ * derivatives instead.
+ * The tree must be rooted and fully resolved (no multifurcation).
+ *
+ * Constraint on parameters HeightP are of class IncludingInterval, initially set to [0,1].
+ *
+ * @deprecated See GlobalClockTreeLikelihoodFunctionWrapper as a more general replacement.
+ */
+class RHomogeneousClockTreeLikelihood:
+  public RHomogeneousTreeLikelihood,
+  public DiscreteRatesAcrossSitesClockTreeLikelihood
+{
+  public:
+    /**
+     * @brief Build a new HomogeneousClockTreeLikelihood object.
+     *
+     * @param tree The tree to use.
+     * @param model The substitution model to use.
+     * @param rDist The rate across sites distribution to use.
+     * @param checkRooted Tell if we have to check for the tree to be rooted.
+     * If true, any unrooted tree will throw an exception. If set to false, the
+     * tree will be considered rooted, and any basal multifurcation will be
+     * considered as a true multifurcation. In the current version of this class
+     * however, multifurcation are not supported, so this option is mainly for
+     * forward compatibility!
+     * @param verbose Should I display some info?
+     * @throw Exception in an error occured.
+     */
+    RHomogeneousClockTreeLikelihood(
+      const Tree& tree,
+      SubstitutionModel* model,
+      DiscreteDistribution* rDist,
+      bool checkRooted = true,
+      bool verbose = true)
+      throw (Exception);
+  
+    /**
+     * @brief Build a new RHomogeneousClockTreeLikelihood object.
+     *
+     * @param tree The tree to use.
+     * @param data Sequences to use.
+     * @param model The substitution model to use.
+     * @param rDist The rate across sites distribution to use.
+     * @param checkRooted Tell if we have to check for the tree to be rooted.
+     * If true, any unrooted tree will throw an exception. If set to false, the
+     * tree will be considered rooted, and any basal multifurcation will be
+     * considered as a true multifurcation. In the current version of this class
+     * however, multifurcation are not supported, so this option is mainly for
+     * forward compatibility!
+     * @param verbose Should I display some info?
+     * @throw Exception in an error occured.
+     */
+    RHomogeneousClockTreeLikelihood(
+      const Tree& tree,
+      const SiteContainer& data,
+      SubstitutionModel* model,
+      DiscreteDistribution* rDist,
+      bool checkRooted = true,
+      bool verbose = true)
+      throw (Exception);
+
+    RHomogeneousClockTreeLikelihood* clone() const { return new RHomogeneousClockTreeLikelihood(*this); }
+
+    virtual ~RHomogeneousClockTreeLikelihood() {}
+
+  private:
+
+    /**
+     * @brief Method called by constructor.
+     */
+    void init_();
+
+  public:
+
+    /**
+     * @name Re-implementation from the RHomogeneousTreeLikelihood class:
+     *
+     * @{
+     */
+    void applyParameters() throw (Exception);
+    void fireParameterChanged(const ParameterList& params);
+    void initBranchLengthsParameters();
+    ParameterList getDerivableParameters() const throw (Exception);
+    ParameterList getNonDerivableParameters() const throw (Exception);
+    double getFirstOrderDerivative(const std::string& variable) const throw (Exception);
+    double getSecondOrderDerivative(const std::string& variable) const throw (Exception);
+    double getSecondOrderDerivative(const std::string& variable1, const std::string& variable2) const throw (Exception) { return 0; } // Not implemented for now.
+    /** @} */
+
+  protected:
+
+    /**
+     * @brief Update all lengths according to parameter values.
+     * 
+     * Conflicting heights will be resolved arbitrarily.
+     *
+     * NB: This is a recursive method.
+     * @param node the current node.
+     * @param height the current height.
+     * @throw Exception If something unexpected happened.
+     */
+    void computeBranchLengthsFromHeights(Node* node, double height) throw (Exception);
+
+};
+
+} //end of namespace bpp.
+
+#endif // _RHOMOGENEOUSCLOCKTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/RHomogeneousMixedTreeLikelihood.cpp b/src/Bpp/Phyl/Likelihood/RHomogeneousMixedTreeLikelihood.cpp
new file mode 100644
index 0000000..2b42807
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/RHomogeneousMixedTreeLikelihood.cpp
@@ -0,0 +1,339 @@
+//
+// File: RHomogeneousMixedTreeLikelihood.h
+// Created by: David Fournier, Laurent Gueguen
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "RHomogeneousMixedTreeLikelihood.h"
+
+
+// From the STL:
+#include <iostream>
+
+#include <math.h>
+#include "../PatternTools.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/App/ApplicationTools.h>
+
+using namespace bpp;
+using namespace std;
+
+RHomogeneousMixedTreeLikelihood::RHomogeneousMixedTreeLikelihood(
+  const Tree& tree,
+  SubstitutionModel* model,
+  DiscreteDistribution* rDist,
+  bool checkRooted,
+  bool verbose,
+  bool usePatterns) throw (Exception) :
+  RHomogeneousTreeLikelihood(tree, model, rDist, checkRooted, verbose, usePatterns),
+  treeLikelihoodsContainer_(),
+  probas_()
+{
+  MixedSubstitutionModel* mixedmodel;
+  if ((mixedmodel = dynamic_cast<MixedSubstitutionModel*>(model_)) == 0)
+    throw Exception("Bad model: RHomogeneousMixedTreeLikelihood needs a MixedSubstitutionModel.");
+  size_t s = mixedmodel->getNumberOfModels();
+  for (size_t i = 0; i < s; i++)
+  {
+    treeLikelihoodsContainer_.push_back(
+      new RHomogeneousTreeLikelihood(tree, mixedmodel->getNModel(i), rDist, checkRooted, false, usePatterns));
+    probas_.push_back(mixedmodel->getNProbability(i));
+  }
+}
+
+RHomogeneousMixedTreeLikelihood::RHomogeneousMixedTreeLikelihood(
+  const Tree& tree,
+  const SiteContainer& data,
+  SubstitutionModel* model,
+  DiscreteDistribution* rDist,
+  bool checkRooted,
+  bool verbose,
+  bool usePatterns) throw (Exception) :
+  RHomogeneousTreeLikelihood(tree, model, rDist, checkRooted, verbose, usePatterns),
+  treeLikelihoodsContainer_(),
+  probas_()
+{
+  MixedSubstitutionModel* mixedmodel;
+
+  if ((mixedmodel = dynamic_cast<MixedSubstitutionModel*>(model_)) == 0)
+    throw Exception("Bad model: RHomogeneousMixedTreeLikelihood needs a MixedSubstitutionModel.");
+
+  size_t s = mixedmodel->getNumberOfModels();
+  for (size_t i = 0; i < s; i++)
+  {
+    treeLikelihoodsContainer_.push_back(
+      new RHomogeneousTreeLikelihood(tree, mixedmodel->getNModel(i), rDist, checkRooted, false, usePatterns));
+    probas_.push_back(mixedmodel->getNProbability(i));
+  }
+  setData(data);
+}
+
+RHomogeneousMixedTreeLikelihood& RHomogeneousMixedTreeLikelihood::operator=(const RHomogeneousMixedTreeLikelihood& lik)
+{
+  RHomogeneousTreeLikelihood::operator=(lik);
+
+  treeLikelihoodsContainer_.clear();
+  probas_.clear();
+
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_.push_back(lik.treeLikelihoodsContainer_[i]->clone());
+    probas_.push_back(lik.probas_[i]);
+  }
+
+  return *this;
+}
+
+
+RHomogeneousMixedTreeLikelihood::RHomogeneousMixedTreeLikelihood(const RHomogeneousMixedTreeLikelihood& lik) :
+  RHomogeneousTreeLikelihood(lik),
+  treeLikelihoodsContainer_(lik.treeLikelihoodsContainer_.size()),
+  probas_(lik.probas_.size())
+{
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i] = lik.treeLikelihoodsContainer_[i]->clone();
+    probas_.push_back(lik.probas_[i]);
+  }
+}
+
+RHomogeneousMixedTreeLikelihood::~RHomogeneousMixedTreeLikelihood()
+{
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    delete treeLikelihoodsContainer_[i];
+  }
+}
+
+
+void RHomogeneousMixedTreeLikelihood::initialize() throw (Exception)
+{
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->initialize();
+  }
+  
+  RHomogeneousTreeLikelihood::initialize();
+}
+
+void RHomogeneousMixedTreeLikelihood::setData(const SiteContainer& sites) throw (Exception)
+{
+  RHomogeneousTreeLikelihood::setData(sites);
+
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->setData(sites);
+  }
+}
+
+
+void RHomogeneousMixedTreeLikelihood::fireParameterChanged(const ParameterList& params)
+{
+  // checks in the model will change
+  bool modelC=model_->getParameters().testParametersValues(params);
+
+  applyParameters();
+  MixedSubstitutionModel* mixedmodel = dynamic_cast<MixedSubstitutionModel*>(model_);
+  size_t s = mixedmodel->getNumberOfModels();
+
+  const SubstitutionModel* pm;
+  for (size_t i = 0; i < s; i++)
+  {
+    ParameterList pl;
+    pm = mixedmodel->getNModel(i);
+    pl.addParameters(pm->getParameters());
+    pl.includeParameters(getParameters());
+
+    if (modelC){
+      treeLikelihoodsContainer_[i]->setParameters(pl);
+    }
+    else
+      treeLikelihoodsContainer_[i]->matchParametersValues(pl);
+  }
+  
+  probas_ = mixedmodel->getProbabilities();
+  minusLogLik_ = -getLogLikelihood();
+}
+
+void RHomogeneousMixedTreeLikelihood::computeTreeLikelihood()
+{
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeTreeLikelihood();
+  }
+}
+
+/******************************************************************************
+ *                                   Likelihoods                              *
+ ******************************************************************************/
+double RHomogeneousMixedTreeLikelihood::getLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  double res = 0;
+
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    res += treeLikelihoodsContainer_[i]->getLikelihoodForASiteForARateClass(site, rateClass) * probas_[i];
+  }
+
+  return res;
+}
+
+double RHomogeneousMixedTreeLikelihood::getLogLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  double x = getLikelihoodForASiteForARateClass(site, rateClass);
+  if (x < 0)
+    x = 0;
+  return log(x);
+}
+
+double RHomogeneousMixedTreeLikelihood::getLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const
+{
+  double res = 0;
+
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    res += treeLikelihoodsContainer_[i]->getLikelihoodForASiteForARateClassForAState(site, rateClass, state) * probas_[i];
+  }
+
+  return res;
+}
+
+double RHomogeneousMixedTreeLikelihood::getLogLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const
+{
+  double x = getLikelihoodForASiteForARateClassForAState(site, rateClass, state);
+  if (x < 0)
+    x = 0;
+  return log(x);
+}
+
+
+/******************************************************************************
+*                           First Order Derivatives                          *
+******************************************************************************/
+double RHomogeneousMixedTreeLikelihood::getDLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  double res = 0;
+
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    res += treeLikelihoodsContainer_[i]->getDLikelihoodForASiteForARateClass(site, rateClass) * probas_[i];
+  }
+
+  return res;
+}
+
+void RHomogeneousMixedTreeLikelihood::computeTreeDLikelihood(const string& variable)
+{
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeTreeDLikelihood(variable);
+  }
+}
+
+/******************************************************************************
+*                           Second Order Derivatives                          *
+******************************************************************************/
+double RHomogeneousMixedTreeLikelihood::getD2LikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  double res = 0;
+
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    res += treeLikelihoodsContainer_[i]->getD2LikelihoodForASiteForARateClass(site, rateClass) * probas_[i];
+  }
+
+  return res;
+}
+
+
+void RHomogeneousMixedTreeLikelihood::computeTreeD2Likelihood(const string& variable)
+{
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeTreeD2Likelihood(variable);
+  }
+}
+
+void RHomogeneousMixedTreeLikelihood::computeSubtreeLikelihood(const Node* node)
+{
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeSubtreeLikelihood(node);
+  }
+}
+
+void RHomogeneousMixedTreeLikelihood::computeDownSubtreeDLikelihood(const Node* node)
+{
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeDownSubtreeDLikelihood(node);
+  }
+}
+
+void RHomogeneousMixedTreeLikelihood::computeDownSubtreeD2Likelihood(const Node* node)
+{
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeDownSubtreeD2Likelihood(node);
+  }
+}
+
+
+void RHomogeneousMixedTreeLikelihood::computeAllTransitionProbabilities()
+{
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeAllTransitionProbabilities();
+  }
+}
+
+
+void RHomogeneousMixedTreeLikelihood::computeTransitionProbabilitiesForNode(const Node* node)
+{
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->computeTransitionProbabilitiesForNode(node);
+  }
+}
+
+
+void RHomogeneousMixedTreeLikelihood::displayLikelihood(const Node* node)
+{
+  for (size_t i = 0; i < treeLikelihoodsContainer_.size(); i++)
+  {
+    treeLikelihoodsContainer_[i]->displayLikelihood(node);
+  }
+}
diff --git a/src/Bpp/Phyl/Likelihood/RHomogeneousMixedTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/RHomogeneousMixedTreeLikelihood.h
new file mode 100644
index 0000000..185345a
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/RHomogeneousMixedTreeLikelihood.h
@@ -0,0 +1,211 @@
+//
+// File: RHomogeneousMixedTreeLikelihood.h
+// Created by: David Fournier, Laurent Gueguen
+//
+
+/*
+   Copyright or � or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _RHOMOGENEOUSMIXEDTREELIKELIHOOD_H_
+#define _RHOMOGENEOUSMIXEDTREELIKELIHOOD_H_
+
+#include "RHomogeneousTreeLikelihood.h"
+#include "../Model/SubstitutionModel.h"
+#include "../Model/MixedSubstitutionModel.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+
+namespace bpp
+{
+/**
+ *@ brief A class to compute the average of several
+ *RHomogeneousTreeLikelihood defined from a Mixed Substitution
+ *Model.
+ *
+ * In all the calculs, the average of the likelihoods, probabilities
+ * are computed.
+ **/
+
+class RHomogeneousMixedTreeLikelihood :
+  public RHomogeneousTreeLikelihood
+{
+private:
+  std::vector<RHomogeneousTreeLikelihood*> treeLikelihoodsContainer_;
+  std::vector<double> probas_;
+  
+public:
+  /**
+   * @brief Build a new RHomogeneousMixedTreeLikelihood object without
+   * data.
+   *
+   * This constructor only initialize the parameters. To compute a
+   * likelihood, you will need to call the setData() and the
+   * computeTreeLikelihood() methods.
+   *
+   * @param tree The tree to use.
+   * @param model The mixed substitution model to use.
+   * @param rDist The rate across sites distribution to use.
+   * @param checkRooted Tell if we have to check for the tree to be unrooted.
+   * If true, any rooted tree will be unrooted before likelihood computation.
+   * @param verbose Should I display some info?
+   * @param usePatterns Tell if recursive site compression should be performed.
+   * @throw Exception in an error occured.
+   */
+  RHomogeneousMixedTreeLikelihood(
+    const Tree& tree,
+    SubstitutionModel* model,
+    DiscreteDistribution* rDist,
+    bool checkRooted = true,
+    bool verbose = true,
+    bool usePatterns = true)
+  throw (Exception);
+
+  /**
+   * @brief Build a new RHomogeneousMixedTreeLikelihood object with data.
+   *
+   * This constructor initializes all parameters, data, and likelihood arrays.
+   *
+   * @param tree The tree to use.
+   * @param data Sequences to use.
+   * @param model The mixed substitution model to use.
+   * @param rDist The rate across sites distribution to use.
+   * @param checkRooted Tell if we have to check for the tree to be unrooted.
+   * If true, any rooted tree will be unrooted before likelihood computation.
+   * @param verbose Should I display some info?
+   * @param usePatterns Tell if recursive site compression should be performed.
+   * @throw Exception in an error occured.
+   */
+  RHomogeneousMixedTreeLikelihood(
+    const Tree& tree,
+    const SiteContainer& data,
+    SubstitutionModel* model,
+    DiscreteDistribution* rDist,
+    bool checkRooted = true,
+    bool verbose = true,
+    bool usePatterns = true)
+  throw (Exception);
+
+  RHomogeneousMixedTreeLikelihood(const RHomogeneousMixedTreeLikelihood& lik);
+
+  RHomogeneousMixedTreeLikelihood& operator=(const RHomogeneousMixedTreeLikelihood& lik);
+
+  virtual ~RHomogeneousMixedTreeLikelihood();
+
+  RHomogeneousMixedTreeLikelihood* clone() const { return new RHomogeneousMixedTreeLikelihood(*this); }
+
+public:
+  /**
+   * @name The TreeLikelihood interface.
+   *
+   * Other methods are implemented in the RHomogeneousTreeLikelihood class.
+   *
+   * @{
+   */
+  void setData(const SiteContainer& sites) throw (Exception);
+
+  /** @} */
+
+
+  /**
+   * @name The DiscreteRatesAcrossSites interface implementation:
+   *
+   * @{
+   */
+  double getLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+  double getLogLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+  double getLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const;
+  double getLogLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const;
+  /** @} */
+
+public:
+  // Specific methods:
+  void initialize() throw (Exception);
+
+  void fireParameterChanged(const ParameterList& params);
+
+  void computeTreeLikelihood();
+
+  virtual double getDLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+
+  virtual void computeTreeDLikelihood(const std::string& variable);
+
+  virtual double getD2LikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+
+  virtual void computeTreeD2Likelihood(const std::string& variable);
+
+protected:
+  /**
+   * @brief Compute the likelihood for a subtree defined by the Tree::Node <i>node</i>.
+   *
+   * @param node The root of the subtree.
+   */
+  virtual void computeSubtreeLikelihood(const Node* node); // Recursive method.
+
+  virtual void computeDownSubtreeDLikelihood(const Node*);
+
+  virtual void computeDownSubtreeD2Likelihood(const Node*);
+
+  /**
+   * @brief This method is used by fireParameterChanged method.
+   *
+   */
+  void computeAllTransitionProbabilities();
+  /**
+   * @brief This method is used by fireParameterChanged method.
+   *
+   */
+  void computeTransitionProbabilitiesForNode(const Node* node);
+
+  /**
+   * @brief This method is mainly for debugging purpose.
+   *
+   * @param node The node at which likelihood values must be displayed.
+   */
+  virtual void displayLikelihood(const Node* node);
+
+  virtual void setMinimumBranchLength(double brlen) throw (Exception) {
+    RHomogeneousMixedTreeLikelihood::setMinimumBranchLength(brlen);
+    for (size_t i = 0; i < treeLikelihoodsContainer_.size(); ++i)
+      treeLikelihoodsContainer_[i]->setMinimumBranchLength(brlen);
+  }
+  virtual void setMaximumBranchLength(double brlen) throw (Exception) {
+    RHomogeneousMixedTreeLikelihood::setMaximumBranchLength(brlen);
+    for (size_t i = 0; i < treeLikelihoodsContainer_.size(); ++i)
+      treeLikelihoodsContainer_[i]->setMaximumBranchLength(brlen);
+  }
+};
+} // end of namespace bpp.
+
+#endif  // _RHOMOGENEOUSMIXEDTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/RHomogeneousTreeLikelihood.cpp b/src/Bpp/Phyl/Likelihood/RHomogeneousTreeLikelihood.cpp
new file mode 100644
index 0000000..bee2be7
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/RHomogeneousTreeLikelihood.cpp
@@ -0,0 +1,882 @@
+//
+// File: RHomogeneousTreeLikelihood.cpp
+// Created by: Julien Dutheil
+// Created on: Fri Oct 17 18:14:51 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "RHomogeneousTreeLikelihood.h"
+#include "../PatternTools.h"
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/App/ApplicationTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+
+using namespace std;
+
+/******************************************************************************/
+
+RHomogeneousTreeLikelihood::RHomogeneousTreeLikelihood(
+  const Tree& tree,
+  SubstitutionModel* model,
+  DiscreteDistribution* rDist,
+  bool checkRooted,
+  bool verbose,
+  bool usePatterns)
+throw (Exception) :
+  AbstractHomogeneousTreeLikelihood(tree, model, rDist, checkRooted, verbose),
+  likelihoodData_(0),
+  minusLogLik_(-1.)
+{
+  init_(usePatterns);
+}
+
+/******************************************************************************/
+
+RHomogeneousTreeLikelihood::RHomogeneousTreeLikelihood(
+  const Tree& tree,
+  const SiteContainer& data,
+  SubstitutionModel* model,
+  DiscreteDistribution* rDist,
+  bool checkRooted,
+  bool verbose,
+  bool usePatterns)
+throw (Exception) :
+  AbstractHomogeneousTreeLikelihood(tree, model, rDist, checkRooted, verbose),
+  likelihoodData_(0),
+  minusLogLik_(-1.)
+{
+  init_(usePatterns);
+  setData(data);
+}
+
+/******************************************************************************/
+
+void RHomogeneousTreeLikelihood::init_(bool usePatterns) throw (Exception)
+{
+  likelihoodData_ = new DRASRTreeLikelihoodData(
+    tree_,
+    rateDistribution_->getNumberOfCategories(),
+    usePatterns);
+}
+
+/******************************************************************************/
+
+RHomogeneousTreeLikelihood::RHomogeneousTreeLikelihood(
+  const RHomogeneousTreeLikelihood& lik) :
+  AbstractHomogeneousTreeLikelihood(lik),
+  likelihoodData_(0),
+  minusLogLik_(lik.minusLogLik_)
+{
+  likelihoodData_ = dynamic_cast<DRASRTreeLikelihoodData*>(lik.likelihoodData_->clone());
+  likelihoodData_->setTree(tree_);
+}
+
+/******************************************************************************/
+
+RHomogeneousTreeLikelihood& RHomogeneousTreeLikelihood::operator=(
+  const RHomogeneousTreeLikelihood& lik)
+{
+  AbstractHomogeneousTreeLikelihood::operator=(lik);
+  if (likelihoodData_) delete likelihoodData_;
+  likelihoodData_ = dynamic_cast<DRASRTreeLikelihoodData*>(lik.likelihoodData_->clone());
+  likelihoodData_->setTree(tree_);
+  minusLogLik_ = lik.minusLogLik_;
+  return *this;
+}
+
+/******************************************************************************/
+
+RHomogeneousTreeLikelihood::~RHomogeneousTreeLikelihood()
+{
+  delete likelihoodData_;
+}
+
+/******************************************************************************/
+
+void RHomogeneousTreeLikelihood::setData(const SiteContainer& sites) throw (Exception)
+{
+  if (data_) delete data_;
+  data_ = PatternTools::getSequenceSubset(sites, *tree_->getRootNode());
+  if (verbose_) ApplicationTools::displayTask("Initializing data structure");
+  likelihoodData_->initLikelihoods(*data_, *model_);
+  if (verbose_) ApplicationTools::displayTaskDone();
+
+  nbSites_ = likelihoodData_->getNumberOfSites();
+  nbDistinctSites_ = likelihoodData_->getNumberOfDistinctSites();
+  nbStates_ = likelihoodData_->getNumberOfStates();
+
+  if (verbose_) ApplicationTools::displayResult("Number of distinct sites",
+                                                TextTools::toString(nbDistinctSites_));
+  initialized_ = false;
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getLikelihood() const
+{
+  double l = 1.;
+  for (size_t i = 0; i < nbSites_; i++)
+  {
+    l *= getLikelihoodForASite(i);
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getLogLikelihood() const
+{
+  double ll = 0;
+  vector<double> la(nbSites_);
+  for (size_t i = 0; i < nbSites_; i++)
+  {
+    la[i] = getLogLikelihoodForASite(i);
+  }
+  sort(la.begin(), la.end());
+  for (size_t i = nbSites_; i > 0; i--)
+  {
+    ll += la[i - 1];
+  }
+  return ll;
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getLikelihoodForASite(size_t site) const
+{
+  double l = 0;
+  for (size_t i = 0; i < nbClasses_; i++)
+  {
+    l += getLikelihoodForASiteForARateClass(site, i) * rateDistribution_->getProbability(i);
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getLogLikelihoodForASite(size_t site) const
+{
+  double l = 0;
+  for (size_t i = 0; i < nbClasses_; i++)
+  {
+    double li = getLikelihoodForASiteForARateClass(site, i) * rateDistribution_->getProbability(i);
+    if (li > 0) l+= li; //Corrects for numerical instabilities leading to slightly negative likelihoods
+  }
+  return log(l);
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  double l = 0;
+  Vdouble* la = &likelihoodData_->getLikelihoodArray(tree_->getRootNode()->getId())[likelihoodData_->getRootArrayPosition(site)][rateClass];
+  for (size_t i = 0; i < nbStates_; i++)
+  {
+    //cout << (*la)[i] << "\t" << rootFreqs_[i] << endl;
+    double li = (*la)[i] * rootFreqs_[i];
+    if (li > 0) l+= li; //Corrects for numerical instabilities leading to slightly negative likelihoods
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getLogLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  double l = 0;
+  Vdouble* la = &likelihoodData_->getLikelihoodArray(tree_->getRootNode()->getId())[likelihoodData_->getRootArrayPosition(site)][rateClass];
+  for (size_t i = 0; i < nbStates_; i++)
+  {
+    l += (*la)[i] * rootFreqs_[i];
+  }
+  //if(l <= 0.) cerr << "WARNING!!! Negative likelihood." << endl;
+  return log(l);
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const
+{
+  return likelihoodData_->getLikelihoodArray(tree_->getRootNode()->getId())[likelihoodData_->getRootArrayPosition(site)][rateClass][state];
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getLogLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const
+{
+  return log(likelihoodData_->getLikelihoodArray(tree_->getRootNode()->getId())[likelihoodData_->getRootArrayPosition(site)][rateClass][state]);
+}
+
+/******************************************************************************/
+
+void RHomogeneousTreeLikelihood::setParameters(const ParameterList& parameters)
+throw (ParameterNotFoundException, ConstraintException)
+{
+  setParametersValues(parameters);
+}
+
+/******************************************************************************/
+
+void RHomogeneousTreeLikelihood::fireParameterChanged(const ParameterList& params)
+{
+  applyParameters();
+
+  if (rateDistribution_->getParameters().getCommonParametersWith(params).size() > 0
+      || model_->getParameters().getCommonParametersWith(params).size() > 0)
+  {
+    //Rate parameter changed, need to recompute all probs:
+    computeAllTransitionProbabilities();
+  }
+  else if (params.size() > 0)
+  {
+    //We may save some computations:
+    for (size_t i = 0; i < params.size(); i++)
+    {
+      string s = params[i].getName();
+      if (s.substr(0, 5) == "BrLen")
+      {
+        //Branch length parameter:
+        computeTransitionProbabilitiesForNode(nodes_[TextTools::to<size_t>(s.substr(5))]);
+      }
+    }
+    rootFreqs_ = model_->getFrequencies();
+  }
+
+  computeTreeLikelihood();
+
+  minusLogLik_ = -getLogLikelihood();
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getValue() const
+throw (Exception)
+{
+  if (!isInitialized()) throw Exception("RHomogeneousTreeLikelihood::getValue(). Instance is not initialized.");
+  return minusLogLik_;
+}
+
+/******************************************************************************
+*                           First Order Derivatives                          *
+******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getDLikelihoodForASiteForARateClass(
+  size_t site,
+  size_t rateClass) const
+{
+  double dl = 0;
+  Vdouble* dla = &likelihoodData_->getDLikelihoodArray(tree_->getRootNode()->getId())[likelihoodData_->getRootArrayPosition(site)][rateClass];
+  for (size_t i = 0; i < nbStates_; i++)
+  {
+    dl += (*dla)[i] * rootFreqs_[i];
+  }
+  return dl;
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getDLikelihoodForASite(size_t site) const
+{
+  // Derivative of the sum is the sum of derivatives:
+  double dl = 0;
+  for (size_t i = 0; i < nbClasses_; i++)
+  {
+    dl += getDLikelihoodForASiteForARateClass(site, i) * rateDistribution_->getProbability(i);
+  }
+  return dl;
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getDLogLikelihoodForASite(size_t site) const
+{
+  // d(f(g(x)))/dx = dg(x)/dx . df(g(x))/dg :
+  return getDLikelihoodForASite(site) / getLikelihoodForASite(site);
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getDLogLikelihood() const
+{
+  // Derivative of the sum is the sum of derivatives:
+  double dl = 0;
+  for (size_t i = 0; i < nbSites_; i++)
+  {
+    dl += getDLogLikelihoodForASite(i);
+  }
+  return dl;
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getFirstOrderDerivative(const string& variable) const
+throw (Exception)
+{
+  if (!hasParameter(variable))
+    throw ParameterNotFoundException("RHomogeneousTreeLikelihood::getFirstOrderDerivative().", variable);
+  if (getRateDistributionParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to rate distribution parameter are not implemented.");
+  }
+  if (getSubstitutionModelParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to substitution model parameters are not implemented.");
+  }
+
+  const_cast<RHomogeneousTreeLikelihood*>(this)->computeTreeDLikelihood(variable);
+  return -getDLogLikelihood();
+}
+
+/******************************************************************************/
+
+void RHomogeneousTreeLikelihood::computeTreeDLikelihood(const string& variable)
+{
+  // Get the node with the branch whose length must be derivated:
+  size_t brI = TextTools::to<size_t>(variable.substr(5));
+  const Node* branch = nodes_[brI];
+  const Node* father = branch->getFather();
+  VVVdouble* _dLikelihoods_father = &likelihoodData_->getDLikelihoodArray(father->getId());
+
+  // Compute dLikelihoods array for the father node.
+  // Fist initialize to 1:
+  size_t nbSites  = _dLikelihoods_father->size();
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+      for (size_t s = 0; s < nbStates_; s++)
+      {
+        (*_dLikelihoods_father_i_c)[s] = 1.;
+      }
+    }
+  }
+
+  size_t nbNodes = father->getNumberOfSons();
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    const Node* son = father->getSon(l);
+
+    vector<size_t> * _patternLinks_father_son = &likelihoodData_->getArrayPositions(father->getId(), son->getId());
+    VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+
+    if (son == branch)
+    {
+      VVVdouble* dpxy__son = &dpxy_[son->getId()];
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+          Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+          VVdouble* dpxy__son_c = &(*dpxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double dl = 0;
+            Vdouble* dpxy__son_c_x = &(*dpxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              dl += (*dpxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+            }
+            (*_dLikelihoods_father_i_c)[x] *= dl;
+          }
+        }
+      }
+    }
+    else
+    {
+      VVVdouble* pxy__son = &pxy_[son->getId()];
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+          Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+          VVdouble* pxy__son_c = &(*pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double dl = 0;
+            Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              dl += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+            }
+            (*_dLikelihoods_father_i_c)[x] *= dl;
+          }
+        }
+      }
+    }
+  }
+
+  // Now we go down the tree toward the root node:
+  computeDownSubtreeDLikelihood(father);
+}
+
+/******************************************************************************/
+
+void RHomogeneousTreeLikelihood::computeDownSubtreeDLikelihood(const Node* node)
+{
+  const Node* father = node->getFather();
+  // We assume that the _dLikelihoods array has been filled for the current node 'node'.
+  // We will evaluate the array for the father node.
+  if (father == NULL) return; // We reached the root!
+
+  // Compute dLikelihoods array for the father node.
+  // Fist initialize to 1:
+  VVVdouble* _dLikelihoods_father = &likelihoodData_->getDLikelihoodArray(father->getId());
+  size_t nbSites  = _dLikelihoods_father->size();
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+      for (size_t s = 0; s < nbStates_; s++)
+      {
+        (*_dLikelihoods_father_i_c)[s] = 1.;
+      }
+    }
+  }
+
+  size_t nbNodes = father->getNumberOfSons();
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    const Node* son = father->getSon(l);
+
+    VVVdouble* pxy__son = &pxy_[son->getId()];
+    vector<size_t> * _patternLinks_father_son = &likelihoodData_->getArrayPositions(father->getId(), son->getId());
+
+    if (son == node)
+    {
+      VVVdouble* _dLikelihoods_son = &likelihoodData_->getDLikelihoodArray(son->getId());
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _dLikelihoods_son_i = &(*_dLikelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _dLikelihoods_son_i_c = &(*_dLikelihoods_son_i)[c];
+          Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+          VVdouble* pxy__son_c = &(*pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double dl = 0;
+            Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              dl += (*pxy__son_c_x)[y] * (*_dLikelihoods_son_i_c)[y];
+            }
+            (*_dLikelihoods_father_i_c)[x] *= dl;
+          }
+        }
+      }
+    }
+    else
+    {
+      VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+          Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+          VVdouble* pxy__son_c = &(*pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double dl = 0;
+            Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              dl += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+            }
+            (*_dLikelihoods_father_i_c)[x] *= dl;
+          }
+        }
+      }
+    }
+  }
+
+  //Next step: move toward grand father...
+  computeDownSubtreeDLikelihood(father);
+}
+
+/******************************************************************************
+*                           Second Order Derivatives                         *
+******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getD2LikelihoodForASiteForARateClass(
+  size_t site,
+  size_t rateClass) const
+{
+  double d2l = 0;
+  Vdouble* d2la = &likelihoodData_->getD2LikelihoodArray(tree_->getRootNode()->getId())[likelihoodData_->getRootArrayPosition(site)][rateClass];
+  for (size_t i = 0; i < nbStates_; i++)
+  {
+    d2l += (*d2la)[i] * rootFreqs_[i];
+  }
+  return d2l;
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getD2LikelihoodForASite(size_t site) const
+{
+  // Derivative of the sum is the sum of derivatives:
+  double d2l = 0;
+  for (size_t i = 0; i < nbClasses_; i++)
+  {
+    d2l += getD2LikelihoodForASiteForARateClass(site, i) * rateDistribution_->getProbability(i);
+  }
+  return d2l;
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getD2LogLikelihoodForASite(size_t site) const
+{
+  return getD2LikelihoodForASite(site) / getLikelihoodForASite(site)
+         - pow( getDLikelihoodForASite(site) / getLikelihoodForASite(site), 2);
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getD2LogLikelihood() const
+{
+  // Derivative of the sum is the sum of derivatives:
+  double dl = 0;
+  for (size_t i = 0; i < nbSites_; i++)
+  {
+    dl += getD2LogLikelihoodForASite(i);
+  }
+  return dl;
+}
+
+/******************************************************************************/
+
+double RHomogeneousTreeLikelihood::getSecondOrderDerivative(const string& variable) const
+throw (Exception)
+{
+  if (!hasParameter(variable))
+    throw ParameterNotFoundException("RHomogeneousTreeLikelihood::getSecondOrderDerivative().", variable);
+  if (getRateDistributionParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to rate distribution parameter are not implemented.");
+  }
+  if (getSubstitutionModelParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to substitution model parameters are not implemented.");
+  }
+
+  const_cast<RHomogeneousTreeLikelihood*>(this)->computeTreeD2Likelihood(variable);
+  return -getD2LogLikelihood();
+}
+
+/******************************************************************************/
+
+void RHomogeneousTreeLikelihood::computeTreeD2Likelihood(const string& variable)
+{
+  // Get the node with the branch whose length must be derivated:
+  size_t brI = TextTools::to<size_t>(variable.substr(5));
+  const Node* branch = nodes_[brI];
+  const Node* father = branch->getFather();
+
+  // Compute dLikelihoods array for the father node.
+  // Fist initialize to 1:
+  VVVdouble* _d2Likelihoods_father = &likelihoodData_->getD2LikelihoodArray(father->getId());
+  size_t nbSites  = _d2Likelihoods_father->size();
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+      for (size_t s = 0; s < nbStates_; s++)
+      {
+        (*_d2Likelihoods_father_i_c)[s] = 1.;
+      }
+    }
+  }
+
+  size_t nbNodes = father->getNumberOfSons();
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    const Node* son = father->getSon(l);
+
+    vector<size_t> * _patternLinks_father_son = &likelihoodData_->getArrayPositions(father->getId(), son->getId());
+    VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+
+    if (son == branch)
+    {
+      VVVdouble* d2pxy__son = &d2pxy_[son->getId()];
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+          Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+          VVdouble* d2pxy__son_c = &(*d2pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double d2l = 0;
+            Vdouble* d2pxy__son_c_x = &(*d2pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              d2l += (*d2pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+            }
+            (*_d2Likelihoods_father_i_c)[x] *= d2l;
+          }
+        }
+      }
+    }
+    else
+    {
+      VVVdouble* pxy__son = &pxy_[son->getId()];
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+          Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+          VVdouble* pxy__son_c = &(*pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double d2l = 0;
+            Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              d2l += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+            }
+            (*_d2Likelihoods_father_i_c)[x] *= d2l;
+          }
+        }
+      }
+    }
+  }
+
+  // Now we go down the tree toward the root node:
+  computeDownSubtreeD2Likelihood(father);
+}
+
+/******************************************************************************/
+
+void RHomogeneousTreeLikelihood::computeDownSubtreeD2Likelihood(const Node* node)
+{
+  const Node* father = node->getFather();
+  // We assume that the _dLikelihoods array has been filled for the current node 'node'.
+  // We will evaluate the array for the father node.
+  if (father == NULL) return; // We reached the root!
+
+  // Compute dLikelihoods array for the father node.
+  // Fist initialize to 1:
+  VVVdouble* _d2Likelihoods_father = &likelihoodData_->getD2LikelihoodArray(father->getId());
+  size_t nbSites  = _d2Likelihoods_father->size();
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+      for (size_t s = 0; s < nbStates_; s++)
+      {
+        (*_d2Likelihoods_father_i_c)[s] = 1.;
+      }
+    }
+  }
+
+  size_t nbNodes = father->getNumberOfSons();
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    const Node* son = father->getSon(l);
+
+    VVVdouble* pxy__son = &pxy_[son->getId()];
+    vector<size_t> * _patternLinks_father_son = &likelihoodData_->getArrayPositions(father->getId(), son->getId());
+
+    if (son == node)
+    {
+      VVVdouble* _d2Likelihoods_son = &likelihoodData_->getD2LikelihoodArray(son->getId());
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _d2Likelihoods_son_i = &(*_d2Likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _d2Likelihoods_son_i_c = &(*_d2Likelihoods_son_i)[c];
+          Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+          VVdouble* pxy__son_c = &(*pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double d2l = 0;
+            Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              d2l += (*pxy__son_c_x)[y] * (*_d2Likelihoods_son_i_c)[y];
+            }
+            (*_d2Likelihoods_father_i_c)[x] *= d2l;
+          }
+        }
+      }
+    }
+    else
+    {
+      VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+          Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+          VVdouble* pxy__son_c = &(*pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double dl = 0;
+            Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              dl += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+            }
+            (*_d2Likelihoods_father_i_c)[x] *= dl;
+          }
+        }
+      }
+    }
+  }
+
+  //Next step: move toward grand father...
+  computeDownSubtreeD2Likelihood(father);
+}
+
+/******************************************************************************/
+
+void RHomogeneousTreeLikelihood::computeTreeLikelihood()
+{
+  computeSubtreeLikelihood(tree_->getRootNode());
+}
+
+/******************************************************************************/
+
+void RHomogeneousTreeLikelihood::computeSubtreeLikelihood(const Node* node)
+{
+  if (node->isLeaf()) return;
+
+  size_t nbSites = likelihoodData_->getLikelihoodArray(node->getId()).size();
+  size_t nbNodes = node->getNumberOfSons();
+
+  // Must reset the likelihood array first (i.e. set all of them to 1):
+  VVVdouble* _likelihoods_node = &likelihoodData_->getLikelihoodArray(node->getId());
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    //For each site in the sequence,
+    VVdouble* _likelihoods_node_i = &(*_likelihoods_node)[i];
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      //For each rate classe,
+      Vdouble* _likelihoods_node_i_c = &(*_likelihoods_node_i)[c];
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        //For each initial state,
+        (*_likelihoods_node_i_c)[x] = 1.;
+      }
+    }
+  }
+
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    //For each son node,
+
+    const Node* son = node->getSon(l);
+
+    computeSubtreeLikelihood(son); //Recursive method:
+
+    VVVdouble* pxy__son = &pxy_[son->getId()];
+    vector<size_t> * _patternLinks_node_son = &likelihoodData_->getArrayPositions(node->getId(), son->getId());
+    VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+
+    for (size_t i = 0; i < nbSites; i++)
+    {
+      //For each site in the sequence,
+      VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_node_son)[i]];
+      VVdouble* _likelihoods_node_i = &(*_likelihoods_node)[i];
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        //For each rate classe,
+        Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+        Vdouble* _likelihoods_node_i_c = &(*_likelihoods_node_i)[c];
+        VVdouble* pxy__son_c = &(*pxy__son)[c];
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          //For each initial state,
+          Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+          double likelihood = 0;
+          for (size_t y = 0; y < nbStates_; y++)
+          {
+            likelihood += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+          }
+          (*_likelihoods_node_i_c)[x] *= likelihood;
+        }
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+void RHomogeneousTreeLikelihood::displayLikelihood(const Node* node)
+{
+  cout << "Likelihoods at node " << node->getName() << ": " << endl;
+  displayLikelihoodArray(likelihoodData_->getLikelihoodArray(node->getId()));
+  cout << "                                         ***" << endl;
+}
+
+/*******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Likelihood/RHomogeneousTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/RHomogeneousTreeLikelihood.h
new file mode 100644
index 0000000..c9f7e07
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/RHomogeneousTreeLikelihood.h
@@ -0,0 +1,276 @@
+//
+// File: RHomogeneousTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Fri Oct 17 18:14:51 2003
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _RHOMOGENEOUSTREELIKELIHOOD_H_
+#define _RHOMOGENEOUSTREELIKELIHOOD_H_
+
+#include "AbstractHomogeneousTreeLikelihood.h"
+#include "../Model/SubstitutionModel.h"
+#include "DRASRTreeLikelihoodData.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+
+namespace bpp
+{
+
+  /**
+   * @brief This class implement the 'traditional' way of computing likelihood for a tree.
+   *
+   * The substitution model is constant over the tree (homogeneous model).
+   * A non uniform distribution of rates among the sites is allowed (ASRV models).</p>
+   *
+   * This class uses an instance of the DRASRTreeLikelihoodData for conditionnal likelihood storage.
+   *
+   * This class can also use a simple or recursive site compression.
+   * In the simple case, computations for identical sites are not duplicated.
+   * In the recursive case, computations for identical sub-sites (<i>site patterns </i>) are also not duplicated:
+   * Following N. Galtier (personal communication ;-), we define a Pattern as a distinct site
+   * in a sub-dataset corresponding to the dataset with sequences associated to a particular subtree.
+   * The likelihood computation is the same for a given site, hence the idea is to save time from
+   * performing many times the same coputation.
+   * The network between all patterns is defined by the _patternLinks double map, initialized in the
+   * initLikelihoodsWithPatterns() method. This initialisation takes more time than the classic
+   * initTreeLikelihood one, where all likelihoods for a given site <i>i</i> are at the <i>i</i> coordinate
+   * in the likelihood tensor, but is really faster when computing the likelihood (computeLikelihoods() method).
+   * Hence, if you have to compute likelihood many times while holding the tree topology unchanged,
+   * you should use patterns.
+   * This decreases the likelihood computation time, but at a cost: some time is spent to establish the patterns
+   * relationships. Whether to use or not patterns depends on what you actllay need:
+   * - The more you compute likelihoods without changing the data or topology, the more patterns are interesting
+   *   (this divides the cost of computing patterns by the number of computation performed).
+   *   Patterns are hence usefull when you have a high number of computation to perform, while optimizing numerical
+   *   parameters for instance).
+   * - Patterns are more likely to occur whith small alphabet (nucleotides).
+   */
+  class RHomogeneousTreeLikelihood :
+    public AbstractHomogeneousTreeLikelihood
+  {
+  private:
+
+    mutable DRASRTreeLikelihoodData* likelihoodData_;
+
+  protected:
+    double minusLogLik_;
+
+  public:
+    /**
+     * @brief Build a new RHomogeneousTreeLikelihood object without data.
+     *
+     * This constructor only initialize the parameters.
+     * To compute a likelihood, you will need to call the setData() and the computeTreeLikelihood() methods.
+     *
+     * @param tree The tree to use.
+     * @param model The substitution model to use.
+     * @param rDist The rate across sites distribution to use.
+     * @param checkRooted Tell if we have to check for the tree to be unrooted.
+     * If true, any rooted tree will be unrooted before likelihood computation.
+     * @param verbose Should I display some info?
+     * @param usePatterns Tell if recursive site compression should be performed.
+     * @throw Exception in an error occured.
+     */
+    RHomogeneousTreeLikelihood(
+                               const Tree& tree,
+                               SubstitutionModel* model,
+                               DiscreteDistribution* rDist,
+                               bool checkRooted = true,
+                               bool verbose = true,
+                               bool usePatterns = true)
+      throw (Exception);
+	
+    /**
+     * @brief Build a new RHomogeneousTreeLikelihood object with data.
+     *
+     * This constructor initializes all parameters, data, and likelihood arrays.
+     *
+     * @param tree The tree to use.
+     * @param data Sequences to use.
+     * @param model The substitution model to use.
+     * @param rDist The rate across sites distribution to use.
+     * @param checkRooted Tell if we have to check for the tree to be unrooted.
+     * If true, any rooted tree will be unrooted before likelihood computation.
+     * @param verbose Should I display some info?
+     * @param usePatterns Tell if recursive site compression should be performed.
+     * @throw Exception in an error occured.
+     */
+    RHomogeneousTreeLikelihood(
+                               const Tree& tree,
+                               const SiteContainer& data,
+                               SubstitutionModel* model,
+                               DiscreteDistribution* rDist,
+                               bool checkRooted = true,
+                               bool verbose = true,
+                               bool usePatterns = true)
+      throw (Exception);
+
+    RHomogeneousTreeLikelihood(const RHomogeneousTreeLikelihood& lik);
+    
+    RHomogeneousTreeLikelihood& operator=(const RHomogeneousTreeLikelihood& lik);
+
+    virtual ~RHomogeneousTreeLikelihood();
+
+    RHomogeneousTreeLikelihood* clone() const { return new RHomogeneousTreeLikelihood(*this); }
+	
+  private:
+
+    /**
+     * @brief Method called by constructors.
+     */
+    void init_(bool usePatterns) throw (Exception);
+	
+  public:
+
+    /**
+     * @name The TreeLikelihood interface.
+     *
+     * Other methods are implemented in the AbstractHomogeneousTreeLikelihood class.
+     *
+     * @{
+     */
+    void setData(const SiteContainer& sites) throw (Exception);
+    double getLikelihood() const;
+    double getLogLikelihood() const;
+    double getLikelihoodForASite (size_t site) const;
+    double getLogLikelihoodForASite(size_t site) const;
+    /** @} */
+
+		
+    /**
+     * @name The DiscreteRatesAcrossSites interface implementation:
+     *
+     * @{
+     */
+    double getLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+    double getLogLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+    double getLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const;
+    double getLogLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const;
+    /** @} */
+
+    /**
+     * @brief Implements the Function interface.
+     *
+     * Update the parameter list and call the applyParameters() method.
+     * Then compute the likelihoods at each node (computeLikelihood() method)
+     * and call the getLogLikelihood() method.
+     *
+     * If a subset of the whole parameter list is passed to the function,
+     * only these parameters are updated and the other remain constant (i.e.
+     * equal to their last value).
+     *
+     * @param parameters The parameter list to pass to the function.
+     */
+    void setParameters(const ParameterList& parameters) throw (ParameterNotFoundException, ConstraintException);
+    double getValue() const throw(Exception);
+		
+    size_t getSiteIndex(size_t site) const throw (IndexOutOfBoundsException) { return likelihoodData_->getRootArrayPosition(site); }
+
+    /**
+     * @name DerivableFirstOrder interface.
+     *
+     * @{
+     */
+    double getFirstOrderDerivative(const std::string& variable) const throw (Exception);
+    /** @} */
+
+    /**
+     * @name DerivableSecondOrder interface.
+     *
+     * @{
+     */
+    double getSecondOrderDerivative(const std::string& variable) const throw (Exception);
+    double getSecondOrderDerivative(const std::string& variable1, const std::string& variable2) const throw (Exception) { return 0; } // Not implemented for now.
+    /** @} */
+	
+  public:	// Specific methods:
+	
+    DRASRTreeLikelihoodData* getLikelihoodData() { return likelihoodData_; }
+    const DRASRTreeLikelihoodData* getLikelihoodData() const { return likelihoodData_; }
+
+    void computeTreeLikelihood();
+
+    virtual double getDLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+
+    virtual double getDLikelihoodForASite(size_t site) const;
+
+    virtual double getDLogLikelihoodForASite(size_t site) const;
+		
+    virtual double getDLogLikelihood() const;
+		
+    virtual void computeTreeDLikelihood(const std::string& variable);
+
+    virtual double getD2LikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+
+    virtual double getD2LikelihoodForASite(size_t site) const;
+
+    virtual double getD2LogLikelihoodForASite(size_t site) const;
+		
+    virtual double getD2LogLikelihood() const;
+		
+    virtual void computeTreeD2Likelihood(const std::string& variable);
+
+	
+  protected:
+			
+    /**
+     * @brief Compute the likelihood for a subtree defined by the Tree::Node <i>node</i>.
+     *
+     * @param node The root of the subtree.
+     */
+    virtual void computeSubtreeLikelihood(const Node* node); //Recursive method.			
+    virtual void computeDownSubtreeDLikelihood(const Node*);
+		
+    virtual void computeDownSubtreeD2Likelihood(const Node*);
+	
+    void fireParameterChanged(const ParameterList& params);
+	
+    /**
+     * @brief This method is mainly for debugging purpose.
+     *
+     * @param node The node at which likelihood values must be displayed.
+     */
+    virtual void displayLikelihood(const Node* node);
+
+    friend class RHomogeneousMixedTreeLikelihood;
+  };
+
+
+} //end of namespace bpp.
+
+#endif	//_RHOMOGENEOUSTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/RNonHomogeneousMixedTreeLikelihood.cpp b/src/Bpp/Phyl/Likelihood/RNonHomogeneousMixedTreeLikelihood.cpp
new file mode 100644
index 0000000..d0a5722
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/RNonHomogeneousMixedTreeLikelihood.cpp
@@ -0,0 +1,825 @@
+//
+// File: RNonHomogeneousMixedTreeLikelihood.cpp
+// Created by: Laurent Gueguen
+// Created on: jeudi 11 novembre 2010, à 07h 56
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "RNonHomogeneousMixedTreeLikelihood.h"
+#include "../PatternTools.h"
+#include "../Model/MixedSubstitutionModel.h"
+#include "../TreeTools.h"
+
+#include <Bpp/Numeric/NumConstants.h>
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/App/ApplicationTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+
+using namespace std;
+
+/******************************************************************************/
+
+RNonHomogeneousMixedTreeLikelihood::RNonHomogeneousMixedTreeLikelihood(const Tree& tree,
+                                                                       MixedSubstitutionModelSet* modelSet,
+                                                                       DiscreteDistribution* rDist,
+                                                                       bool verbose,
+                                                                       bool usePatterns)
+throw (Exception) :
+  RNonHomogeneousTreeLikelihood(tree, modelSet, rDist, verbose, usePatterns),
+  mvTreeLikelihoods_(),
+  hyperNode_(modelSet),
+  upperNode_(tree.getRootId()),
+  main_(true)
+{
+  if (!modelSet->isFullySetUpFor(tree))
+    throw Exception("RNonHomogeneousMixedTreeLikelihood(constructor). Model set is not fully specified.");
+
+  for (size_t i=0;i<modelSet->getNumberOfHyperNodes();i++){
+    mvTreeLikelihoods_[tree.getRootId()].push_back(new RNonHomogeneousMixedTreeLikelihood(tree, modelSet, modelSet->getHyperNode(i), upperNode_, rDist, false, usePatterns));
+  }
+
+}
+
+/******************************************************************************/
+
+RNonHomogeneousMixedTreeLikelihood::RNonHomogeneousMixedTreeLikelihood(const Tree& tree,
+                                                                       const SiteContainer& data,
+                                                                       MixedSubstitutionModelSet* modelSet,
+                                                                       DiscreteDistribution* rDist,
+                                                                       bool verbose,
+                                                                       bool usePatterns)
+throw (Exception) :
+  RNonHomogeneousTreeLikelihood(tree, data, modelSet, rDist, verbose, usePatterns),
+  mvTreeLikelihoods_(),
+  hyperNode_(modelSet),
+  upperNode_(tree.getRootId()),
+  main_(true)
+{
+  if (!modelSet->isFullySetUpFor(tree))
+    throw Exception("RNonHomogeneousMixedTreeLikelihood(constructor). Model set is not fully specified.");
+
+  for (size_t i=0;i<modelSet->getNumberOfHyperNodes();i++)
+    mvTreeLikelihoods_[tree.getRootId()].push_back(new RNonHomogeneousMixedTreeLikelihood(tree, data, modelSet, modelSet->getHyperNode(i), upperNode_, rDist, false, usePatterns));
+}
+
+/******************************************************************************/
+
+RNonHomogeneousMixedTreeLikelihood::RNonHomogeneousMixedTreeLikelihood(const Tree& tree,
+                                                                       MixedSubstitutionModelSet* modelSet,
+                                                                       const MixedSubstitutionModelSet::HyperNode& hyperNode,
+                                                                       int upperNode,
+                                                                       DiscreteDistribution* rDist,
+                                                                       bool verbose,
+                                                                       bool usePatterns) :
+  RNonHomogeneousTreeLikelihood(tree, modelSet, rDist, verbose, usePatterns),
+  mvTreeLikelihoods_(),
+  hyperNode_(hyperNode),
+  upperNode_(upperNode),
+  main_(false)
+{
+  if (!modelSet->isFullySetUpFor(tree))
+    throw Exception("RNonHomogeneousMixedTreeLikelihood(constructor). Model set is not fully specified.");
+
+  init(usePatterns);
+}
+
+/******************************************************************************/
+
+RNonHomogeneousMixedTreeLikelihood::RNonHomogeneousMixedTreeLikelihood(const Tree& tree,
+                                                                       const SiteContainer& data,
+                                                                       MixedSubstitutionModelSet* modelSet,
+                                                                       const MixedSubstitutionModelSet::HyperNode& hyperNode,
+                                                                       int upperNode,
+                                                                       DiscreteDistribution* rDist,
+                                                                       bool verbose,
+                                                                       bool usePatterns) :
+  RNonHomogeneousTreeLikelihood(tree, data, modelSet, rDist, verbose, usePatterns),
+  mvTreeLikelihoods_(),
+  hyperNode_(hyperNode),
+  upperNode_(upperNode),
+  main_(false)
+{
+  if (!modelSet->isFullySetUpFor(tree))
+    throw Exception("RNonHomogeneousMixedTreeLikelihood(constructor). Model set is not fully specified.");
+
+  init(usePatterns);
+}
+
+/******************************************************************************/
+
+void RNonHomogeneousMixedTreeLikelihood::init(bool usePatterns)
+{
+  std::vector<int> vDesc; // vector of the explorated descendents
+  int desc;
+  vector<int> vn;
+  size_t nbmodels = modelSet_->getNumberOfModels();
+
+  const SiteContainer* pdata=getData();
+  
+  const Tree& tree = getTree();
+  
+  vDesc.push_back(upperNode_); // start of the exploration
+
+  while (vDesc.size() != 0)  {
+    desc = vDesc.back();
+    vDesc.pop_back();
+    vector<int> vExpMod; // vector of the ids of the MixedModels which
+                         // nodes are not in only one subtree under desc
+
+    vector<int> vson = tree.getSonsId(desc);
+    std::map<int, vector<int> > mdesc; // map of the subtree nodes for
+                                       // each son of desc
+    for (size_t i = 0; i < vson.size(); i++)
+    {
+      std::vector<int> vi;
+      TreeTools::getNodesId(tree, vson[i], vi);
+      mdesc[vson[i]] = vi;
+    }
+
+    for (size_t i = 0; i < nbmodels; i++)
+    {
+      const MixedSubstitutionModelSet::HyperNode::Node& node = hyperNode_.getNode(i);
+      
+      if (node.size()>1)
+      {
+        vn = modelSet_->getNodesWithModel(i); // tree nodes associated to model
+
+        /* Check if the vn members are in the same subtree */
+        size_t flag = 0; // count of the subtrees that have vn members
+        std::map<int, vector<int> >::iterator it;
+        for (it = mdesc.begin(); it != mdesc.end(); it++)
+        {
+          for (size_t j = 0; j < it->second.size(); j++)
+            {
+            if (it->second[j] != it->first)
+            {
+              if (find(vn.begin(), vn.end(), it->second[j]) != vn.end())
+              {
+                flag += (find(vn.begin(), vn.end(), it->first) != vn.end()) ? 2 : 1; // check if the son
+                // has this model too
+                break;
+              }
+            }
+            else if (find(vn.begin(), vn.end(), it->first) != vn.end())
+              flag++;
+          }
+          if (flag >= 2)
+            break;
+        }
+        if (flag >= 2)
+          vExpMod.push_back(static_cast<int>(i));  // mixed model that must be expanded
+      }
+    }
+
+    if (vExpMod.size() != 0)
+    {
+      std::map<int, int> mapmodels;
+      size_t ttmodels = 1;
+      for (vector<int>::iterator it = vExpMod.begin(); it != vExpMod.end(); it++)
+      {
+        mapmodels[*it] = static_cast<int>(hyperNode_.getNode(*it).size());
+        ttmodels *= mapmodels[*it];
+      }
+
+      for (size_t i = 0; i < ttmodels; i++)
+      {
+        int s = static_cast<int>(i);
+        MixedSubstitutionModelSet::HyperNode hn(hyperNode_);
+        
+        for (size_t j = 0; j < nbmodels; j++)
+        {
+          if ((hyperNode_.getNode(j).size() >= 1) && find(vExpMod.begin(), vExpMod.end(), static_cast<int>(j)) != vExpMod.end())
+          {
+            hn.setModel(j, Vint(1, hyperNode_.getNode(j)[s % mapmodels[static_cast<int>(j)]]));
+            s /= mapmodels[static_cast<int>(j)];
+          }
+        }
+        hn.setProbability((dynamic_cast<MixedSubstitutionModelSet*>(modelSet_))->getHyperNodeProbability(hn));
+        RNonHomogeneousMixedTreeLikelihood* pr;
+
+        if (pdata)
+          pr = new RNonHomogeneousMixedTreeLikelihood(tree, *pdata, dynamic_cast<MixedSubstitutionModelSet*>(modelSet_), hn, desc, rateDistribution_, false, usePatterns);
+        else
+          pr = new RNonHomogeneousMixedTreeLikelihood(tree, dynamic_cast<MixedSubstitutionModelSet*>(modelSet_), hn, desc, rateDistribution_, false, usePatterns);
+        pr->resetParameters_();
+        mvTreeLikelihoods_[desc].push_back(pr);
+      }
+    }
+    else
+      for (size_t i = 0; i < vson.size(); i++)
+      {
+        vDesc.push_back(vson[i]);
+      }
+  }
+}
+
+
+/******************************************************************************/
+
+RNonHomogeneousMixedTreeLikelihood::RNonHomogeneousMixedTreeLikelihood(
+  const RNonHomogeneousMixedTreeLikelihood& lik) :
+  RNonHomogeneousTreeLikelihood(lik),
+  mvTreeLikelihoods_(),
+  hyperNode_(lik.hyperNode_),
+  upperNode_(lik.upperNode_),
+  main_(lik.main_)
+{
+  map<int, vector<RNonHomogeneousMixedTreeLikelihood*> >::const_iterator it;
+  for (it = lik.mvTreeLikelihoods_.begin(); it != lik.mvTreeLikelihoods_.end(); it++)
+  {
+    for (size_t i = 0; i < it->second.size(); i++)
+    {
+      mvTreeLikelihoods_[it->first].push_back(new RNonHomogeneousMixedTreeLikelihood(*it->second[i]));
+    }
+  }
+}
+
+/******************************************************************************/
+
+RNonHomogeneousMixedTreeLikelihood& RNonHomogeneousMixedTreeLikelihood::operator=(
+  const RNonHomogeneousMixedTreeLikelihood& lik)
+{
+  RNonHomogeneousTreeLikelihood::operator=(lik);
+
+  mvTreeLikelihoods_.clear();
+
+  upperNode_ = lik.upperNode_;
+  main_ = lik.main_;
+
+  map<int, vector<RNonHomogeneousMixedTreeLikelihood*> >::const_iterator it;
+  for (it = lik.mvTreeLikelihoods_.begin(); it != lik.mvTreeLikelihoods_.end(); it++)
+  {
+    for (size_t i = 0; i < it->second.size(); i++)
+    {
+      mvTreeLikelihoods_[it->first].push_back(new RNonHomogeneousMixedTreeLikelihood(*it->second[i]));
+    }
+  }
+
+  hyperNode_=lik.hyperNode_;
+
+  return *this;
+}
+
+/******************************************************************************/
+
+RNonHomogeneousMixedTreeLikelihood::~RNonHomogeneousMixedTreeLikelihood()
+{
+  map<int, vector<RNonHomogeneousMixedTreeLikelihood*> >::iterator it;
+  for (it = mvTreeLikelihoods_.begin(); it != mvTreeLikelihoods_.end(); it++)
+  {
+    for (size_t i = 0; i < it->second.size(); i++)
+    {
+      delete it->second[i];
+    }
+  }
+}
+
+/******************************************************************************/
+ void RNonHomogeneousMixedTreeLikelihood::initialize() throw (Exception)
+{
+  if (main_)
+    initParameters();
+  else {
+    initBranchLengthsParameters();
+    addParameters_(brLenParameters_);
+  }
+
+  map<int, vector<RNonHomogeneousMixedTreeLikelihood*> >::iterator it;
+  for (it = mvTreeLikelihoods_.begin(); it != mvTreeLikelihoods_.end(); it++)
+  {
+    for (size_t i = 0; i < it->second.size(); i++)
+    {
+      it->second[i]->initialize();
+    }
+  }
+
+  RNonHomogeneousTreeLikelihood::initialize();
+}
+
+/******************************************************************************/
+
+ void RNonHomogeneousMixedTreeLikelihood::fireParameterChanged(const ParameterList& params)
+{
+  if (main_)
+    applyParameters();
+  else {
+    for (size_t i = 0; i < nbNodes_; i++)
+      {
+        int id = nodes_[i]->getId();
+        if (reparametrizeRoot_ && id == root1_)
+          {
+            const Parameter* rootBrLen = &getParameter("BrLenRoot");
+            const Parameter* rootPos = &getParameter("RootPosition");
+            nodes_[i]->setDistanceToFather(rootBrLen->getValue() * rootPos->getValue());
+          }
+        else if (reparametrizeRoot_ && id == root2_)
+          {
+            const Parameter* rootBrLen = &getParameter("BrLenRoot");
+            const Parameter* rootPos = &getParameter("RootPosition");
+            nodes_[i]->setDistanceToFather(rootBrLen->getValue() * (1. - rootPos->getValue()));
+          }
+        else
+          {
+            const Parameter* brLen = &getParameter(string("BrLen") + TextTools::toString(i));
+            if (brLen) nodes_[i]->setDistanceToFather(brLen->getValue());
+          }
+      }
+  }
+
+  map<int, vector<RNonHomogeneousMixedTreeLikelihood*> >::const_iterator it2;
+  for (it2 = mvTreeLikelihoods_.begin(); it2 != mvTreeLikelihoods_.end(); it2++)
+    for (size_t i = 0; i < it2->second.size(); i++){
+      (it2->second)[i]->setProbability((dynamic_cast<MixedSubstitutionModelSet*>(modelSet_))->getHyperNodeProbability((it2->second)[i]->getHyperNode()));
+    }
+
+  if (main_){
+    for (size_t i=0;i< mvTreeLikelihoods_[upperNode_].size(); i++)
+      mvTreeLikelihoods_[upperNode_][i]->matchParametersValues(params);
+    rootFreqs_ = modelSet_->getRootFrequencies();
+  }
+  else {
+    if (params.getCommonParametersWith(rateDistribution_->getIndependentParameters()).size() > 0)
+      {
+        computeAllTransitionProbabilities();
+      }
+    else
+      {
+        vector<int> ids;
+        vector<string> tmp = params.getCommonParametersWith(modelSet_->getNodeParameters()).getParameterNames();
+        for (size_t i = 0; i < tmp.size(); i++)
+          {
+            vector<int> tmpv = modelSet_->getNodesWithParameter(tmp[i]);
+            ids = VectorTools::vectorUnion(ids, tmpv);
+          }
+        tmp = params.getCommonParametersWith(brLenParameters_).getParameterNames();
+        vector<const Node*> nodes;
+        for (size_t i = 0; i < ids.size(); i++)
+          {
+            nodes.push_back(idToNode_[ids[i]]);
+          }
+        vector<const Node*> tmpv;
+        bool test = false;
+        for (size_t i = 0; i < tmp.size(); i++)
+          {
+            if (tmp[i] == "BrLenRoot" || tmp[i] == "RootPosition")
+              {
+                if (!test)
+                  {
+                    tmpv.push_back(tree_->getRootNode()->getSon(0));
+                    tmpv.push_back(tree_->getRootNode()->getSon(1));
+                    test = true; // Add only once.
+                  }
+              }
+            else
+              tmpv.push_back(nodes_[TextTools::to < size_t > (tmp[i].substr(5))]);
+          }
+        nodes = VectorTools::vectorUnion(nodes, tmpv);
+        
+        for (size_t i = 0; i < nodes.size(); i++){
+          computeTransitionProbabilitiesForNode(nodes[i]);
+        }
+      }
+
+    map<int, vector<RNonHomogeneousMixedTreeLikelihood*> >::iterator it;
+    for (it = mvTreeLikelihoods_.begin(); it != mvTreeLikelihoods_.end(); it++)
+      {
+        for (size_t i = 0; i < it->second.size(); i++)
+          {
+            it->second[i]->matchParametersValues(params);
+          }
+      }
+  }
+  
+  if (main_)
+    {
+      computeTreeLikelihood();
+      minusLogLik_ = -getLogLikelihood();
+    }
+}
+
+/******************************************************************************/
+void RNonHomogeneousMixedTreeLikelihood::setData(const SiteContainer& sites) throw (Exception)
+{
+  RNonHomogeneousTreeLikelihood::setData(sites);
+  map<int, vector<RNonHomogeneousMixedTreeLikelihood*> >::iterator it;
+  for (it = mvTreeLikelihoods_.begin(); it != mvTreeLikelihoods_.end(); it++)
+  {
+    for (size_t i = 0; i < it->second.size(); i++)
+    {
+      it->second[i]->setData(sites);
+    }
+  }
+}
+
+
+/******************************************************************************/
+double RNonHomogeneousMixedTreeLikelihood::getProbability() const
+{
+  return hyperNode_.getProbability();
+}
+
+/******************************************************************************/
+void RNonHomogeneousMixedTreeLikelihood::setProbability(double x)
+{
+  return hyperNode_.setProbability(x);
+}
+
+/******************************************************************************/
+
+void RNonHomogeneousMixedTreeLikelihood::computeSubtreeLikelihood(const Node* node)
+{
+  // if the subtree is divided in several RNonHomogeneousMixedTreeLikelihood*
+  if (node->isLeaf())
+    return;
+
+  int nodeId=main_?upperNode_:node->getId();
+  if (mvTreeLikelihoods_.find(nodeId) != mvTreeLikelihoods_.end()) {
+
+    size_t nbSites  = likelihoodData_->getLikelihoodArray(nodeId).size();
+    
+    // Must reset the likelihood array first (i.e. set all of them to 0):
+    VVVdouble* _likelihoods_node = &likelihoodData_->getLikelihoodArray(nodeId);
+    for (size_t i = 0; i < nbSites; i++)
+      {
+        // For each site in the sequence,
+        VVdouble* _likelihoods_node_i = &(*_likelihoods_node)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+          {
+              // For each rate classe,
+            Vdouble* _likelihoods_node_i_c = &(*_likelihoods_node_i)[c];
+            for (size_t x = 0; x < nbStates_; x++)
+              {
+                // For each initial state,
+                (*_likelihoods_node_i_c)[x] = 0.;
+              }
+          }
+      }
+
+    if (getProbability()==0)
+      return;
+  
+    vector<RNonHomogeneousMixedTreeLikelihood* > vr = mvTreeLikelihoods_[nodeId];
+    for (size_t t = 0; t < vr.size(); t++)
+      vr[t]->computeSubtreeLikelihood(node);
+
+    // for each specific subtree
+    for (size_t t = 0; t < vr.size(); t++)
+    {
+      VVVdouble* _vt_likelihoods_node = &vr[t]->likelihoodData_->getLikelihoodArray(nodeId);
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        // For each site in the sequence,
+        VVdouble* _likelihoods_node_i = &(*_likelihoods_node)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          // For each rate classe,
+          Vdouble* _likelihoods_node_i_c = &(*_likelihoods_node_i)[c];
+          Vdouble* _vt_likelihoods_node_i_c = &(*_vt_likelihoods_node)[i][c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            (*_likelihoods_node_i_c)[x] +=  (*_vt_likelihoods_node_i_c)[x] * vr[t]->getProbability()/getProbability();
+          }
+        }
+      }
+    }
+  }
+  
+
+  // otherwise...
+
+  // nb: if the subtree is made of independent branches the computing is
+  // as in the non mixed case, where the mean of the probas of
+  // transition of a mixed model are taken.
+
+  else
+    RNonHomogeneousTreeLikelihood::computeSubtreeLikelihood(node); 
+}
+
+/******************************************************************************
+*                           First Order Derivatives                          *
+******************************************************************************/
+void RNonHomogeneousMixedTreeLikelihood::computeTreeDLikelihood(const string& variable)
+{
+  const Node* father, father2;
+    
+    
+  if (main_)
+    father = tree_->getRootNode();
+  else {
+    if ((variable == "BrLenRoot") ||  (variable == "RootPosition"))
+      father = tree_->getRootNode();
+    else
+      {
+        size_t brI = TextTools::to<size_t>(variable.substr(5));
+        const Node* branch = nodes_[brI];
+        father = branch->getFather();
+      }
+  }
+  
+  bool flok = 0;
+  while (father){
+    if (mvTreeLikelihoods_.find(father->getId()) != mvTreeLikelihoods_.end()) {
+      flok = 1;
+      break;
+    }
+    if (father->getId() == upperNode_)
+      break;
+    father = father->getFather();
+  }
+    
+  if (flok) {  // there is an expanded model above the derivated branch
+    int fatherId = father->getId();
+    // Compute dLikelihoods array for the father node.
+    // Fist initialize to 0:
+    VVVdouble* _dLikelihoods_father = &likelihoodData_->getDLikelihoodArray(fatherId);
+    size_t nbSites  = _dLikelihoods_father->size();
+    for (size_t i = 0; i < nbSites; i++) {
+      VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+      for (size_t c = 0; c < nbClasses_; c++) {
+        Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+        for (size_t s = 0; s < nbStates_; s++){
+          (*_dLikelihoods_father_i_c)[s] = 0.;
+        }
+      }
+    }
+
+    if (getProbability()!=0){
+      vector<RNonHomogeneousMixedTreeLikelihood* > vr = mvTreeLikelihoods_[fatherId];
+      for (size_t t = 0; t < vr.size(); t++)
+        vr[t]->computeTreeDLikelihood(variable);
+      
+    
+      // for each specific subtree
+      for (size_t t = 0; t < vr.size(); t++) {
+        VVVdouble* _vt_dLikelihoods_father = &vr[t]->likelihoodData_->getDLikelihoodArray(fatherId);
+        for (size_t i = 0; i < nbSites; i++){
+          // For each site in the sequence,
+          VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+          for (size_t c = 0; c < nbClasses_; c++){
+            // For each rate classe,
+            Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+            Vdouble* _vt_dLikelihoods_father_i_c = &(*_vt_dLikelihoods_father)[i][c];
+            for (size_t x = 0; x < nbStates_; x++) {
+              (*_dLikelihoods_father_i_c)[x] +=  (*_vt_dLikelihoods_father_i_c)[x] * vr[t]->getProbability()/getProbability();
+            }
+          }
+        }
+      }
+    }
+    computeDownSubtreeDLikelihood(father);
+  }
+  else
+    RNonHomogeneousTreeLikelihood::computeTreeDLikelihood(variable); 
+}
+
+void RNonHomogeneousMixedTreeLikelihood::computeDownSubtreeDLikelihood(const Node* node)
+{
+  const Node* father = node->getFather();
+  // // We assume that the _dLikelihoods array has been filled for the current node 'node'.
+  // // We will evaluate the array for the father node.
+  if (father == 0)
+    return;  // We reached the up!
+
+  if (node->getId() == upperNode_)
+    return;  // We reached the top of the subtree
+
+  RNonHomogeneousTreeLikelihood::computeDownSubtreeDLikelihood(node);
+}
+
+/******************************************************************************
+*                           Second Order Derivatives                         *
+******************************************************************************/
+void RNonHomogeneousMixedTreeLikelihood::computeTreeD2Likelihood(const string& variable)
+{
+  const Node* father, father2;
+
+  if (main_)
+    father = tree_->getRootNode();
+  else {
+    if ((variable == "BrLenRoot") ||  (variable == "RootPosition"))
+      father = tree_->getRootNode();
+    else
+      {
+        size_t brI = TextTools::to<size_t>(variable.substr(5));
+        const Node* branch = nodes_[brI];
+        father = branch->getFather();
+      }
+  }
+  
+  bool flok = 0;
+  while (father){
+    if (mvTreeLikelihoods_.find(father->getId()) != mvTreeLikelihoods_.end())
+      {
+        flok = 1;
+        break;
+      }
+    if (father->getId() == upperNode_)
+      break;
+    father = father->getFather();
+  }
+
+  if (flok)  // there is an expanded model above the derivated branch
+    {
+      int fatherId = father->getId();
+      // Compute d2Likelihoods array for the father node.
+      // Fist initialize to 0:
+      VVVdouble* _d2Likelihoods_father = &likelihoodData_->getD2LikelihoodArray(fatherId);
+      size_t nbSites  = _d2Likelihoods_father->size();
+      for (size_t i = 0; i < nbSites; i++) {
+        VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++) {
+          Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+          for (size_t s = 0; s < nbStates_; s++) {
+            (*_d2Likelihoods_father_i_c)[s] = 0.;
+          }
+        }
+      }
+
+      if (getProbability()!=0){
+        
+        vector<RNonHomogeneousMixedTreeLikelihood* > vr = mvTreeLikelihoods_[fatherId];
+        for (size_t t = 0; t < vr.size(); t++)
+          vr[t]->computeTreeD2Likelihood(variable);
+      
+        // for each specific subtree
+        for (size_t t = 0; t < vr.size(); t++) {
+          VVVdouble* _vt_d2Likelihoods_father = &vr[t]->likelihoodData_->getD2LikelihoodArray(fatherId);
+          for (size_t i = 0; i < nbSites; i++) {
+            // For each site in the sequence,
+            VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+            for (size_t c = 0; c < nbClasses_; c++){
+              // For each rate classe,
+              Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+              Vdouble* _vt_d2Likelihoods_father_i_c = &(*_vt_d2Likelihoods_father)[i][c];
+              for (size_t x = 0; x < nbStates_; x++) {
+                (*_d2Likelihoods_father_i_c)[x] +=  (*_vt_d2Likelihoods_father_i_c)[x] * vr[t]->getProbability() / getProbability();
+              }
+            }
+          }
+        }
+      }
+      computeDownSubtreeD2Likelihood(father);
+    }
+  else
+    RNonHomogeneousTreeLikelihood::computeTreeD2Likelihood(variable);
+}
+
+
+void RNonHomogeneousMixedTreeLikelihood::computeDownSubtreeD2Likelihood(const Node* node)
+{
+  const Node* father = node->getFather();
+  // // We assume that the _dLikelihoods array has been filled for the current node 'node'.
+  // // We will evaluate the array for the father node.
+  if (father == 0)
+    return;  // We reached the up!
+
+  if (node->getId() == upperNode_)
+    return;  // We reached the top of the subtree
+
+  RNonHomogeneousTreeLikelihood::computeDownSubtreeD2Likelihood(node);
+}
+
+
+/*******************************************************************************/
+
+void RNonHomogeneousMixedTreeLikelihood::computeTransitionProbabilitiesForNode(const Node* node)
+{
+  const SubstitutionModel* model = modelSet_->getModelForNode(node->getId());
+  size_t modelnum = modelSet_->getModelIndexForNode(node->getId());
+
+  vector<const SubstitutionModel*> vModel;
+  vector<double> vProba;
+  
+  const MixedSubstitutionModelSet::HyperNode::Node& nd=hyperNode_.getNode(modelnum);
+  if (nd.size() == 0) {
+    vModel.push_back(model);
+    vProba.push_back(1);
+  }
+  else {
+    const MixedSubstitutionModel* mmodel = dynamic_cast<const MixedSubstitutionModel*>(model);
+    double x=0;
+    for (size_t i=0;i<nd.size();i++){
+      vModel.push_back(mmodel->getNModel(nd[i]));
+      vProba.push_back(mmodel->getNProbability(nd[i]));
+      x+=vProba[i];
+    }
+    if (x!=0)
+      for (size_t i=0;i<nd.size();i++)
+        vProba[i]/=x;
+  }
+
+  double l = node->getDistanceToFather();
+  // Computes all pxy and pyx once for all:
+  VVVdouble* pxy__node = &pxy_[node->getId()];
+  for (size_t c = 0; c < nbClasses_; c++) {
+    VVdouble* pxy__node_c = &(*pxy__node)[c];
+    for (size_t x = 0; x < nbStates_; x++){
+      Vdouble* pxy__node_c_x = &(*pxy__node_c)[x];
+      for (size_t y = 0; y < nbStates_; y++){
+        (*pxy__node_c_x)[y] = 0;
+      }
+    }
+    
+    for (size_t i=0;i<vModel.size();i++){
+      RowMatrix<double> Q = vModel[i]->getPij_t(l * rateDistribution_->getCategory(c));
+      for (size_t x = 0; x < nbStates_; x++){
+        Vdouble* pxy__node_c_x = &(*pxy__node_c)[x];
+        for (size_t y = 0; y < nbStates_; y++){
+          (*pxy__node_c_x)[y] += vProba[i] * Q(x, y);
+        }
+      }
+    }
+  }
+  
+  if (computeFirstOrderDerivatives_) {
+    // Computes all dpxy/dt once for all:
+    VVVdouble* dpxy__node = &dpxy_[node->getId()];
+
+    for (size_t c = 0; c < nbClasses_; c++){
+      VVdouble* dpxy__node_c = &(*dpxy__node)[c];
+      double rc = rateDistribution_->getCategory(c);
+      for (size_t x = 0; x < nbStates_; x++){
+        Vdouble* dpxy__node_c_x = &(*dpxy__node_c)[x];
+        for (size_t y = 0; y < nbStates_; y++){
+          (*dpxy__node_c_x)[y] = 0;
+        }
+      }
+
+      for (size_t i=0;i<vModel.size();i++){
+        RowMatrix<double> dQ = vModel[i]->getdPij_dt(l * rc);
+
+        for (size_t x = 0; x < nbStates_; x++){
+          Vdouble* dpxy__node_c_x = &(*dpxy__node_c)[x];
+          for (size_t y = 0; y < nbStates_; y++){
+            (*dpxy__node_c_x)[y] +=  vProba[i] * rc * dQ(x, y);
+          }
+        }
+      }
+    }
+  }
+  
+  if (computeSecondOrderDerivatives_) {
+    // Computes all d2pxy/dt2 once for all:
+    VVVdouble* d2pxy__node = &d2pxy_[node->getId()];
+    for (size_t c = 0; c < nbClasses_; c++){
+      VVdouble* d2pxy__node_c = &(*d2pxy__node)[c];
+      for (size_t x = 0; x < nbStates_; x++){
+        Vdouble* d2pxy__node_c_x = &(*d2pxy__node_c)[x];
+        for (size_t y = 0; y < nbStates_; y++){
+          (*d2pxy__node_c_x)[y] = 0;
+        }
+      }
+      
+      double rc =  rateDistribution_->getCategory(c);
+      for (size_t i=0;i<vModel.size();i++){
+        RowMatrix<double> d2Q = vModel[i]->getd2Pij_dt2(l * rc);
+        for (size_t x = 0; x < nbStates_; x++){
+          Vdouble* d2pxy__node_c_x = &(*d2pxy__node_c)[x];
+          for (size_t y = 0; y < nbStates_; y++){
+            (*d2pxy__node_c_x)[y] +=  vProba[i] * rc * rc * d2Q(x, y);
+          }
+        }
+      }
+    }
+  }
+  
+}
+
+/*******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Likelihood/RNonHomogeneousMixedTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/RNonHomogeneousMixedTreeLikelihood.h
new file mode 100644
index 0000000..d0f7076
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/RNonHomogeneousMixedTreeLikelihood.h
@@ -0,0 +1,294 @@
+//
+// File: RNonHomogeneousMixedLikelihood.h
+// Created by: Laurent Gueguen
+// Created on: jeudi 11 novembre 2010, à 07h 56
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _RNONHOMOGENEOUSMIXEDTREELIKELIHOOD_H_
+#define _RNONHOMOGENEOUSMIXEDTREELIKELIHOOD_H_
+
+#include "RNonHomogeneousTreeLikelihood.h"
+#include "../Model/MixedSubstitutionModelSet.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+
+using namespace std;
+namespace bpp
+{
+/**
+ *@ brief A class to compute the average of several
+ *RNonHomogeneousTreeLikelihood defined from a Mixed Substitution
+ *Model.
+ *
+ * This class is made recursively. At each node, we test if an
+ * expansion of a mixed model is necessary. This is the case when this
+ * model points towards different subtrees under this node, or towards
+ * a son of this node and a branch under it. If an expansion is
+ * necessary, a vector of RNonHomogeneousMixedLikelihood* is built
+ * with all the submodels combinations.
+ *
+ * Note that this approach is not the most efficient, since a graph
+ * based one would avoid some computations, but it seems much more
+ * difficult to do it in the extant hierarchy.
+ **/
+
+class RNonHomogeneousMixedTreeLikelihood :
+  public RNonHomogeneousTreeLikelihood
+{
+private:
+
+  /**
+   * @brief the map of the branch numbers to the vectors of the
+   * TreeLikelihoods for the expanded model on this branch.
+   *
+   */
+
+  map<int, vector<RNonHomogeneousMixedTreeLikelihood*> > mvTreeLikelihoods_;
+
+  /**
+   * @brief A specific HyperNode in which the computation is
+   * processed. If the probability of this HyperNode is -1, it means
+   * that it should not be used, and the HyperNodes are all in the
+   * MixedSubstitutionModelSet object.
+   *
+   * This object owns the HyperNode pointers of the owned
+   * RNonHomogeneousMixedTreeLikelihood.
+   */
+  
+  MixedSubstitutionModelSet::HyperNode hyperNode_;
+
+  /**
+   * @brief the number of the node under which tree the Treelikelihood
+   * is computed.
+   *
+   */
+  
+  int upperNode_;
+
+  /**
+   * @brief a flag to say if this object is the head of the hierarchy
+   *
+   **/
+
+  bool main_;
+  
+  /**
+   * @brief Build a new RNonHomogeneousMixeTreeLikelihood object
+   * without data.
+   *
+   * This constructor only initialize the parameters. To compute a
+   * likelihood, you will need to call the setData() and the
+   * computeTreeLikelihood() methods.
+   *
+   * @param tree The tree to use.
+   * @param modelSet The set of substitution models to use.
+   * @param hyperNode an hypernode of the numbers of the submodels
+   *  used in the mixed models.
+   * @param upperNode the number of the node under which the treelikelihood
+   *  is computed.
+   * @param rDist The rate across sites distribution to use.
+   *  If true, any rooted tree will be unrooted before likelihood computation.
+   * @param verbose Should I display some info?
+   * @param usePatterns Tell if recursive site compression should be performed.
+   * @throw Exception in an error occured.
+   */
+
+  RNonHomogeneousMixedTreeLikelihood(const Tree& tree,
+                                     MixedSubstitutionModelSet* modelSet,
+                                     const MixedSubstitutionModelSet::HyperNode& hyperNode,
+                                     int upperNode,
+                                     DiscreteDistribution* rDist,
+                                     bool verbose,
+                                     bool usePatterns);
+
+  /**
+   * @brief Build a new RNonHomogeneousMixeTreeLikelihood object
+   * with data.
+   *
+   * This constructor only initialize the parameters. To compute a
+   * likelihood, you will need to call the setData() and the
+   * computeTreeLikelihood() methods.
+   *
+   * @param tree The tree to use.
+   * @param data Sequences to use.
+   * @param modelSet The set of substitution models to use.
+   * @param hyperNode an hypernode of the numbers of the submodels
+   *  used in the mixed models.
+   * @param upperNode the number of the node under which the treelikelihood
+   *  is computed.
+   * @param rDist The rate across sites distribution to use.
+   *  If true, any rooted tree will be unrooted before likelihood computation.
+   * @param verbose Should I display some info?
+   * @param usePatterns Tell if recursive site compression should be performed.
+   * @throw Exception in an error occured.
+   */
+
+  RNonHomogeneousMixedTreeLikelihood(const Tree& tree,
+                                     const SiteContainer& data,
+                                     MixedSubstitutionModelSet* modelSet,
+                                     const MixedSubstitutionModelSet::HyperNode& hyperNode,
+                                     int upperNode,
+                                     DiscreteDistribution* rDist,
+                                     bool verbose,
+                                     bool usePatterns);
+
+
+  /**
+   * brief method where the recursive structure is built.
+   *
+   */
+  
+  void init(bool usePatterns);
+
+  
+public:
+  /**
+   * @brief Build a new RNonHomogeneousMixeTreeLikelihood object
+   * without data.
+   *
+   * This constructor only initialize the parameters. To compute a
+   * likelihood, you will need to call the setData() and the
+   * computeTreeLikelihood() methods.
+   *
+   * @param tree The tree to use.
+   * @param modelSet The set of substitution models to use.
+   * @param rDist The rate across sites distribution to use.
+   * If true, any rooted tree will be unrooted before likelihood computation.
+   * @param verbose Should I display some info?
+   * @param usePatterns Tell if recursive site compression should be performed.
+   * @throw Exception in an error occured.
+   */
+  RNonHomogeneousMixedTreeLikelihood(
+    const Tree& tree,
+    MixedSubstitutionModelSet* modelSet,
+    DiscreteDistribution* rDist,
+    bool verbose = true,
+    bool usePatterns = true)
+  throw (Exception);
+
+  /**
+   * @brief Build a new RNonHomogeneousMixedTreeLikelihood object
+   * and compute the corresponding likelihood.
+   *
+   * This constructor initializes all parameters, data, and
+   * likelihood arrays.
+   *
+   * @param tree The tree to use.
+   * @param data Sequences to use.
+   * @param modelSet The set of substitution models to use.
+   * @param rDist The rate across sites distribution to use.
+   * @param verbose Should I display some info?
+   * @param usePatterns Tell if recursive site compression should be performed.
+   * @throw Exception in an error occured.
+   */
+  RNonHomogeneousMixedTreeLikelihood(const Tree& tree,
+                                     const SiteContainer& data,
+                                     MixedSubstitutionModelSet* modelSet,
+                                     DiscreteDistribution* rDist,
+                                     bool verbose = true,
+                                     bool usePatterns = true)
+    throw (Exception);
+
+  RNonHomogeneousMixedTreeLikelihood(const RNonHomogeneousMixedTreeLikelihood& lik);
+
+  RNonHomogeneousMixedTreeLikelihood& operator=(const RNonHomogeneousMixedTreeLikelihood& lik);
+
+  virtual ~RNonHomogeneousMixedTreeLikelihood();
+
+  RNonHomogeneousMixedTreeLikelihood* clone() const { return new RNonHomogeneousMixedTreeLikelihood(*this); }
+
+public:
+  /**
+   * @name The TreeLikelihood interface.
+   *
+   * Other methods are implemented in the AbstractHomogeneousTreeLikelihood class.
+   *
+   * @{
+   */
+  void setData(const SiteContainer& sites) throw (Exception);
+
+public:
+  // Specific methods:
+  void initialize() throw (Exception);
+
+  void computeTreeDLikelihood(const string& variable);
+
+  void computeTreeD2Likelihood(const string& variable);
+
+  /**
+   * @brief returns the probability of this object in the hierarchy
+   *
+   */
+  
+  double getProbability() const;
+
+  /**
+   * @brief sets the probability of this object in the hierarchy
+   *
+   */
+  
+  void setProbability(double x);
+
+  /**
+   * @brief returns the HyperNode describing the owned submodels.
+   *
+   */
+
+  const MixedSubstitutionModelSet::HyperNode& getHyperNode() { return hyperNode_;}
+protected:
+
+
+  /**
+   * @brief Compute the likelihood for a subtree defined by the Tree::Node <i>node</i>.
+   *
+   * @param node The root of the subtree.
+   */
+  virtual void computeSubtreeLikelihood(const Node* node); // Recursive method.
+
+  virtual void computeDownSubtreeDLikelihood(const Node*);
+
+  virtual void computeDownSubtreeD2Likelihood(const Node*);
+
+  void fireParameterChanged(const ParameterList& params);
+
+  void computeTransitionProbabilitiesForNode(const Node* node);
+
+};
+} // end of namespace bpp.
+
+#endif  // _RNONHOMOGENEOUSMIXEDTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/RNonHomogeneousTreeLikelihood.cpp b/src/Bpp/Phyl/Likelihood/RNonHomogeneousTreeLikelihood.cpp
new file mode 100644
index 0000000..acd7572
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/RNonHomogeneousTreeLikelihood.cpp
@@ -0,0 +1,1365 @@
+//
+// File: RNonHomogeneousTreeLikelihood.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Oct 09 16:07 2007
+// From file: RHomogeneousTreeLikelihood.cpp
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "RNonHomogeneousTreeLikelihood.h"
+#include "../PatternTools.h"
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/App/ApplicationTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+
+using namespace std;
+
+/******************************************************************************/
+
+RNonHomogeneousTreeLikelihood::RNonHomogeneousTreeLikelihood(
+  const Tree& tree,
+  SubstitutionModelSet* modelSet,
+  DiscreteDistribution* rDist,
+  bool verbose,
+  bool usePatterns,
+  bool reparametrizeRoot)
+throw (Exception) :
+  AbstractNonHomogeneousTreeLikelihood(tree, modelSet, rDist, verbose, reparametrizeRoot),
+  likelihoodData_(0),
+  minusLogLik_(-1.)
+{
+  if (!modelSet->isFullySetUpFor(tree))
+    throw Exception("RNonHomogeneousTreeLikelihood(constructor). Model set is not fully specified.");
+  init_(usePatterns);
+}
+
+/******************************************************************************/
+
+RNonHomogeneousTreeLikelihood::RNonHomogeneousTreeLikelihood(
+  const Tree& tree,
+  const SiteContainer& data,
+  SubstitutionModelSet* modelSet,
+  DiscreteDistribution* rDist,
+  bool verbose,
+  bool usePatterns,
+  bool reparametrizeRoot)
+throw (Exception) :
+  AbstractNonHomogeneousTreeLikelihood(tree, modelSet, rDist, verbose, reparametrizeRoot),
+  likelihoodData_(0),
+  minusLogLik_(-1.)
+{
+  if (!modelSet->isFullySetUpFor(tree))
+    throw Exception("RNonHomogeneousTreeLikelihood(constructor). Model set is not fully specified.");
+  init_(usePatterns);
+  setData(data);
+}
+
+/******************************************************************************/
+
+void RNonHomogeneousTreeLikelihood::init_(bool usePatterns) throw (Exception)
+{
+  likelihoodData_ = new DRASRTreeLikelihoodData(
+    tree_,
+    rateDistribution_->getNumberOfCategories(),
+    usePatterns);
+}
+
+/******************************************************************************/
+
+RNonHomogeneousTreeLikelihood::RNonHomogeneousTreeLikelihood(
+  const RNonHomogeneousTreeLikelihood& lik) :
+  AbstractNonHomogeneousTreeLikelihood(lik),
+  likelihoodData_(0),
+  minusLogLik_(lik.minusLogLik_)
+{
+  likelihoodData_ = dynamic_cast<DRASRTreeLikelihoodData*>(lik.likelihoodData_->clone());
+  likelihoodData_->setTree(tree_);
+}
+
+/******************************************************************************/
+
+RNonHomogeneousTreeLikelihood& RNonHomogeneousTreeLikelihood::operator=(
+  const RNonHomogeneousTreeLikelihood& lik)
+{
+  AbstractNonHomogeneousTreeLikelihood::operator=(lik);
+  if (likelihoodData_) delete likelihoodData_;
+  likelihoodData_ = dynamic_cast<DRASRTreeLikelihoodData*>(lik.likelihoodData_->clone());
+  likelihoodData_->setTree(tree_);
+  minusLogLik_ = lik.minusLogLik_;
+  return *this;
+}
+
+/******************************************************************************/
+
+RNonHomogeneousTreeLikelihood::~RNonHomogeneousTreeLikelihood()
+{
+  delete likelihoodData_;
+}
+
+/******************************************************************************/
+
+void RNonHomogeneousTreeLikelihood::setData(const SiteContainer& sites) throw (Exception)
+{
+  if (data_) delete data_;
+  data_ = PatternTools::getSequenceSubset(sites, *tree_->getRootNode());
+  if (verbose_) ApplicationTools::displayTask("Initializing data structure");
+  likelihoodData_->initLikelihoods(*data_, *modelSet_->getModel(0)); //We assume here that all models have the same number of states, and that they have the same 'init' method,
+                                                                     //Which is a reasonable assumption as long as they share the same alphabet.
+  if (verbose_) ApplicationTools::displayTaskDone();
+
+  nbSites_         = likelihoodData_->getNumberOfSites();
+  nbDistinctSites_ = likelihoodData_->getNumberOfDistinctSites();
+  nbStates_        = likelihoodData_->getNumberOfStates();
+
+  if (verbose_) ApplicationTools::displayResult("Number of distinct sites",
+                                                TextTools::toString(nbDistinctSites_));
+  initialized_ = false;
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getLikelihood() const
+{
+  double l = 1.;
+  for (size_t i = 0; i < nbSites_; i++)
+  {
+    l *= getLikelihoodForASite(i);
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getLogLikelihood() const
+{
+  double ll = 0;
+  vector<double> la(nbSites_);
+  for (size_t i = 0; i < nbSites_; i++)
+  {
+    la[i] = getLogLikelihoodForASite(i);
+  }
+  sort(la.begin(), la.end());
+  for (size_t i = nbSites_; i > 0; i--)
+  {
+    ll += la[i - 1];
+  }
+  return ll;
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getLikelihoodForASite(size_t site) const
+{
+  double l = 0;
+  for (size_t i = 0; i < nbClasses_; i++)
+  {
+    l += getLikelihoodForASiteForARateClass(site, i) * rateDistribution_->getProbability(i);
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getLogLikelihoodForASite(size_t site) const
+{
+  double l = 0;
+  for (size_t i = 0; i < nbClasses_; i++)
+  {
+    l += getLikelihoodForASiteForARateClass(site, i) * rateDistribution_->getProbability(i);
+  }
+  //if(l <= 0.) cerr << "WARNING!!! Negative likelihood." << endl;
+  if (l < 0) l = 0; //May happen because of numerical errors.
+  return log(l);
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  double l = 0;
+  Vdouble* la = &likelihoodData_->getLikelihoodArray(tree_->getRootNode()->getId())[likelihoodData_->getRootArrayPosition(site)][rateClass];
+  for (size_t i = 0; i < nbStates_; i++)
+  {
+    l += (*la)[i] * rootFreqs_[i];
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getLogLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const
+{
+  double l = 0;
+  Vdouble* la = &likelihoodData_->getLikelihoodArray(tree_->getRootNode()->getId())[likelihoodData_->getRootArrayPosition(site)][rateClass];
+  for (size_t i = 0; i < nbStates_; i++)
+  {
+    l += (*la)[i] * rootFreqs_[i];
+  }
+  return log(l);
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const
+{
+  return likelihoodData_->getLikelihoodArray(tree_->getRootNode()->getId())[likelihoodData_->getRootArrayPosition(site)][rateClass][state];
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getLogLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const
+{
+  return log(likelihoodData_->getLikelihoodArray(tree_->getRootNode()->getId())[likelihoodData_->getRootArrayPosition(site)][rateClass][state]);
+}
+
+/******************************************************************************/
+
+void RNonHomogeneousTreeLikelihood::setParameters(const ParameterList& parameters)
+throw (ParameterNotFoundException, ConstraintException)
+{
+  setParametersValues(parameters);
+}
+
+/******************************************************************************/
+
+void RNonHomogeneousTreeLikelihood::fireParameterChanged(const ParameterList& params)
+{
+  applyParameters();
+
+  if (params.getCommonParametersWith(rateDistribution_->getIndependentParameters()).size() > 0)
+  {
+    computeAllTransitionProbabilities();
+  }
+  else
+  {
+    vector<int> ids;
+    vector<string> tmp = params.getCommonParametersWith(modelSet_->getNodeParameters()).getParameterNames();
+    for (size_t i = 0; i < tmp.size(); i++)
+    {
+      vector<int> tmpv = modelSet_->getNodesWithParameter(tmp[i]);
+      ids = VectorTools::vectorUnion(ids, tmpv);
+    }
+    tmp = params.getCommonParametersWith(brLenParameters_).getParameterNames();
+    vector<const Node*> nodes;
+    for (size_t i = 0; i < ids.size(); i++)
+    {
+      nodes.push_back(idToNode_[ids[i]]);
+    }
+    vector<const Node*> tmpv;
+    bool test = false;
+    for (size_t i = 0; i < tmp.size(); i++)
+    {
+      if (tmp[i] == "BrLenRoot" || tmp[i] == "RootPosition")
+      {
+        if (!test)
+        {
+          tmpv.push_back(tree_->getRootNode()->getSon(0));
+          tmpv.push_back(tree_->getRootNode()->getSon(1));
+          test = true; //Add only once.
+        }
+      }
+      else
+        tmpv.push_back(nodes_[TextTools::to < size_t > (tmp[i].substr(5))]);
+    }
+    nodes = VectorTools::vectorUnion(nodes, tmpv);
+
+    for (size_t i = 0; i < nodes.size(); i++)
+    {
+      computeTransitionProbabilitiesForNode(nodes[i]);
+    }
+    rootFreqs_ = modelSet_->getRootFrequencies();
+  }
+  computeTreeLikelihood();
+
+  minusLogLik_ = -getLogLikelihood();
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getValue() const
+throw (Exception)
+{
+  if (!isInitialized()) throw Exception("RNonHomogeneousTreeLikelihood::getValue(). Instance is not initialized.");
+  return minusLogLik_;
+}
+
+/******************************************************************************
+*                           First Order Derivatives                          *
+******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getDLikelihoodForASiteForARateClass(
+  size_t site,
+  size_t rateClass) const
+{
+  double dl = 0;
+  Vdouble* dla = &likelihoodData_->getDLikelihoodArray(tree_->getRootNode()->getId())[likelihoodData_->getRootArrayPosition(site)][rateClass];
+  for (size_t i = 0; i < nbStates_; i++)
+  {
+    dl += (*dla)[i] * rootFreqs_[i];
+  }
+  return dl;
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getDLikelihoodForASite(size_t site) const
+{
+  // Derivative of the sum is the sum of derivatives:
+  double dl = 0;
+  for (size_t i = 0; i < nbClasses_; i++)
+  {
+    dl += getDLikelihoodForASiteForARateClass(site, i) * rateDistribution_->getProbability(i);
+  }
+  return dl;
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getDLogLikelihoodForASite(size_t site) const
+{
+  // d(f(g(x)))/dx = dg(x)/dx . df(g(x))/dg :
+  return getDLikelihoodForASite(site) / getLikelihoodForASite(site);
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getDLogLikelihood() const
+{
+  // Derivative of the sum is the sum of derivatives:
+  double dl = 0;
+  for (size_t i = 0; i < nbSites_; i++)
+  {
+    dl += getDLogLikelihoodForASite(i);
+  }
+  return dl;
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getFirstOrderDerivative(const string& variable) const
+throw (Exception)
+{
+  if (!hasParameter(variable))
+    throw ParameterNotFoundException("RNonHomogeneousTreeLikelihood::getFirstOrderDerivative().", variable);
+  if (getRateDistributionParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to rate distribution parameter are not implemented.");
+  }
+  if (getSubstitutionModelParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to substitution model parameters are not implemented.");
+  }
+
+  const_cast<RNonHomogeneousTreeLikelihood*>(this)->computeTreeDLikelihood(variable);
+  return -getDLogLikelihood();
+}
+
+/******************************************************************************/
+
+void RNonHomogeneousTreeLikelihood::computeTreeDLikelihood(const string& variable)
+{
+  if (variable == "BrLenRoot")
+  {
+    const Node* father = tree_->getRootNode();
+
+    // Compute dLikelihoods array for the father node.
+    // Fist initialize to 1:
+    VVVdouble* _dLikelihoods_father = &likelihoodData_->getDLikelihoodArray(father->getId());
+    size_t nbSites  = _dLikelihoods_father->size();
+    for (size_t i = 0; i < nbSites; i++)
+    {
+      VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+        for (size_t s = 0; s < nbStates_; s++)
+        {
+          (*_dLikelihoods_father_i_c)[s] = 1.;
+        }
+      }
+    }
+
+    size_t nbNodes = father->getNumberOfSons();
+    for (size_t l = 0; l < nbNodes; l++)
+    {
+      const Node* son = father->getSon(l);
+
+      if (son->getId() == root1_)
+      {
+        const Node* root1 = father->getSon(0);
+        const Node* root2 = father->getSon(1);
+        vector<size_t> * _patternLinks_fatherroot1_ = &likelihoodData_->getArrayPositions(father->getId(), root1->getId());
+        vector<size_t> * _patternLinks_fatherroot2_ = &likelihoodData_->getArrayPositions(father->getId(), root2->getId());
+        VVVdouble* _likelihoodsroot1_ = &likelihoodData_->getLikelihoodArray(root1->getId());
+        VVVdouble* _likelihoodsroot2_ = &likelihoodData_->getLikelihoodArray(root2->getId());
+        double pos = getParameterValue("RootPosition");
+
+        VVVdouble* dpxy_root1_  = &dpxy_[root1_];
+        VVVdouble* dpxy_root2_  = &dpxy_[root2_];
+        VVVdouble* pxy_root1_   = &pxy_[root1_];
+        VVVdouble* pxy_root2_   = &pxy_[root2_];
+        for (size_t i = 0; i < nbSites; i++)
+        {
+          VVdouble* _likelihoodsroot1__i = &(*_likelihoodsroot1_)[(*_patternLinks_fatherroot1_)[i]];
+          VVdouble* _likelihoodsroot2__i = &(*_likelihoodsroot2_)[(*_patternLinks_fatherroot2_)[i]];
+          VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+          for (size_t c = 0; c < nbClasses_; c++)
+          {
+            Vdouble* _likelihoodsroot1__i_c = &(*_likelihoodsroot1__i)[c];
+            Vdouble* _likelihoodsroot2__i_c = &(*_likelihoodsroot2__i)[c];
+            Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+            VVdouble* dpxy_root1__c  = &(*dpxy_root1_)[c];
+            VVdouble* dpxy_root2__c  = &(*dpxy_root2_)[c];
+            VVdouble* pxy_root1__c   = &(*pxy_root1_)[c];
+            VVdouble* pxy_root2__c   = &(*pxy_root2_)[c];
+            for (size_t x = 0; x < nbStates_; x++)
+            {
+              Vdouble* dpxy_root1__c_x  = &(*dpxy_root1__c)[x];
+              Vdouble* dpxy_root2__c_x  = &(*dpxy_root2__c)[x];
+              Vdouble* pxy_root1__c_x   = &(*pxy_root1__c)[x];
+              Vdouble* pxy_root2__c_x   = &(*pxy_root2__c)[x];
+              double dl1 = 0, dl2 = 0, l1 = 0, l2 = 0;
+              for (size_t y = 0; y < nbStates_; y++)
+              {
+                dl1  += (*dpxy_root1__c_x)[y]  * (*_likelihoodsroot1__i_c)[y];
+                dl2  += (*dpxy_root2__c_x)[y]  * (*_likelihoodsroot2__i_c)[y];
+                l1   += (*pxy_root1__c_x)[y]   * (*_likelihoodsroot1__i_c)[y];
+                l2   += (*pxy_root2__c_x)[y]   * (*_likelihoodsroot2__i_c)[y];
+              }
+              double dl = pos * dl1 * l2 + (1. - pos) * dl2 * l1;
+              (*_dLikelihoods_father_i_c)[x] *= dl;
+            }
+          }
+        }
+      }
+      else if (son->getId() == root2_)
+      {
+        //Do nothing, this was accounted when dealing with root1_
+      }
+      else
+      {
+        //Account for a putative multifurcation:
+        vector<size_t> * _patternLinks_father_son = &likelihoodData_->getArrayPositions(father->getId(), son->getId());
+        VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+
+        VVVdouble* pxy__son = &pxy_[son->getId()];
+        for (size_t i = 0; i < nbSites; i++)
+        {
+          VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+          VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+          for (size_t c = 0; c < nbClasses_; c++)
+          {
+            Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+            Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+            VVdouble* pxy__son_c = &(*pxy__son)[c];
+            for (size_t x = 0; x < nbStates_; x++)
+            {
+              double dl = 0;
+              Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+              for (size_t y = 0; y < nbStates_; y++)
+              {
+                dl += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+              }
+              (*_dLikelihoods_father_i_c)[x] *= dl;
+            }
+          }
+        }
+      }
+    }
+    return;
+  }
+  else if (variable == "RootPosition")
+  {
+    const Node* father = tree_->getRootNode();
+
+    // Compute dLikelihoods array for the father node.
+    // Fist initialize to 1:
+    VVVdouble* _dLikelihoods_father = &likelihoodData_->getDLikelihoodArray(father->getId());
+    size_t nbSites  = _dLikelihoods_father->size();
+    for (size_t i = 0; i < nbSites; i++)
+    {
+      VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+        for (size_t s = 0; s < nbStates_; s++)
+        {
+          (*_dLikelihoods_father_i_c)[s] = 1.;
+        }
+      }
+    }
+
+    size_t nbNodes = father->getNumberOfSons();
+    for (size_t l = 0; l < nbNodes; l++)
+    {
+      const Node* son = father->getSon(l);
+
+      if (son->getId() == root1_)
+      {
+        const Node* root1 = father->getSon(0);
+        const Node* root2 = father->getSon(1);
+        vector<size_t> * _patternLinks_fatherroot1_ = &likelihoodData_->getArrayPositions(father->getId(), root1->getId());
+        vector<size_t> * _patternLinks_fatherroot2_ = &likelihoodData_->getArrayPositions(father->getId(), root2->getId());
+        VVVdouble* _likelihoodsroot1_ = &likelihoodData_->getLikelihoodArray(root1->getId());
+        VVVdouble* _likelihoodsroot2_ = &likelihoodData_->getLikelihoodArray(root2->getId());
+        double len = getParameterValue("BrLenRoot");
+
+        VVVdouble* dpxy_root1_  = &dpxy_[root1_];
+        VVVdouble* dpxy_root2_  = &dpxy_[root2_];
+        VVVdouble* pxy_root1_   = &pxy_[root1_];
+        VVVdouble* pxy_root2_   = &pxy_[root2_];
+        for (size_t i = 0; i < nbSites; i++)
+        {
+          VVdouble* _likelihoodsroot1__i = &(*_likelihoodsroot1_)[(*_patternLinks_fatherroot1_)[i]];
+          VVdouble* _likelihoodsroot2__i = &(*_likelihoodsroot2_)[(*_patternLinks_fatherroot2_)[i]];
+          VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+          for (size_t c = 0; c < nbClasses_; c++)
+          {
+            Vdouble* _likelihoodsroot1__i_c = &(*_likelihoodsroot1__i)[c];
+            Vdouble* _likelihoodsroot2__i_c = &(*_likelihoodsroot2__i)[c];
+            Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+            VVdouble* dpxy_root1__c  = &(*dpxy_root1_)[c];
+            VVdouble* dpxy_root2__c  = &(*dpxy_root2_)[c];
+            VVdouble* pxy_root1__c   = &(*pxy_root1_)[c];
+            VVdouble* pxy_root2__c   = &(*pxy_root2_)[c];
+            for (size_t x = 0; x < nbStates_; x++)
+            {
+              Vdouble* dpxy_root1__c_x  = &(*dpxy_root1__c)[x];
+              Vdouble* dpxy_root2__c_x  = &(*dpxy_root2__c)[x];
+              Vdouble* pxy_root1__c_x   = &(*pxy_root1__c)[x];
+              Vdouble* pxy_root2__c_x   = &(*pxy_root2__c)[x];
+              double dl1 = 0, dl2 = 0, l1 = 0, l2 = 0;
+              for (size_t y = 0; y < nbStates_; y++)
+              {
+                dl1  += (*dpxy_root1__c_x)[y]  * (*_likelihoodsroot1__i_c)[y];
+                dl2  += (*dpxy_root2__c_x)[y]  * (*_likelihoodsroot2__i_c)[y];
+                l1   += (*pxy_root1__c_x)[y]   * (*_likelihoodsroot1__i_c)[y];
+                l2   += (*pxy_root2__c_x)[y]   * (*_likelihoodsroot2__i_c)[y];
+              }
+              double dl = len * (dl1 * l2 - dl2 * l1);
+              (*_dLikelihoods_father_i_c)[x] *= dl;
+            }
+          }
+        }
+      }
+      else if (son->getId() == root2_)
+      {
+        //Do nothing, this was accounted when dealing with root1_
+      }
+      else
+      {
+        //Account for a putative multifurcation:
+        vector<size_t> * _patternLinks_father_son = &likelihoodData_->getArrayPositions(father->getId(), son->getId());
+        VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+
+        VVVdouble* pxy__son = &pxy_[son->getId()];
+        for (size_t i = 0; i < nbSites; i++)
+        {
+          VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+          VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+          for (size_t c = 0; c < nbClasses_; c++)
+          {
+            Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+            Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+            VVdouble* pxy__son_c = &(*pxy__son)[c];
+            for (size_t x = 0; x < nbStates_; x++)
+            {
+              double dl = 0;
+              Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+              for (size_t y = 0; y < nbStates_; y++)
+              {
+                dl += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+              }
+              (*_dLikelihoods_father_i_c)[x] *= dl;
+            }
+          }
+        }
+      }
+    }
+    return;
+  }
+
+  // Get the node with the branch whose length must be derivated:
+  size_t brI = TextTools::to<size_t>(variable.substr(5));
+  const Node* branch = nodes_[brI];
+  const Node* father = branch->getFather();
+  VVVdouble* _dLikelihoods_father = &likelihoodData_->getDLikelihoodArray(father->getId());
+
+  // Compute dLikelihoods array for the father node.
+  // Fist initialize to 1:
+  size_t nbSites  = _dLikelihoods_father->size();
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+      for (size_t s = 0; s < nbStates_; s++)
+      {
+        (*_dLikelihoods_father_i_c)[s] = 1.;
+      }
+    }
+  }
+
+  size_t nbNodes = father->getNumberOfSons();
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    const Node* son = father->getSon(l);
+
+    vector<size_t> * _patternLinks_father_son = &likelihoodData_->getArrayPositions(father->getId(), son->getId());
+    VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+
+    if (son == branch)
+    {
+      VVVdouble* dpxy__son = &dpxy_[son->getId()];
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+          Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+          VVdouble* dpxy__son_c = &(*dpxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double dl = 0;
+            Vdouble* dpxy__son_c_x = &(*dpxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              dl += (*dpxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+            }
+            (*_dLikelihoods_father_i_c)[x] *= dl;
+          }
+        }
+      }
+    }
+    else
+    {
+      VVVdouble* pxy__son = &pxy_[son->getId()];
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+          Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+          VVdouble* pxy__son_c = &(*pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double dl = 0;
+            Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              dl += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+            }
+            (*_dLikelihoods_father_i_c)[x] *= dl;
+          }
+        }
+      }
+    }
+  }
+
+  // Now we go down the tree toward the root node:
+  computeDownSubtreeDLikelihood(father);
+}
+
+/******************************************************************************/
+
+void RNonHomogeneousTreeLikelihood::computeDownSubtreeDLikelihood(const Node* node)
+{
+  const Node* father = node->getFather();
+  // We assume that the _dLikelihoods array has been filled for the current node 'node'.
+  // We will evaluate the array for the father node.
+  if (father == 0) return; // We reached the root!
+
+  // Compute dLikelihoods array for the father node.
+  // Fist initialize to 1:
+  VVVdouble* _dLikelihoods_father = &likelihoodData_->getDLikelihoodArray(father->getId());
+  size_t nbSites  = _dLikelihoods_father->size();
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+      for (size_t s = 0; s < nbStates_; s++)
+      {
+        (*_dLikelihoods_father_i_c)[s] = 1.;
+      }
+    }
+  }
+
+  size_t nbNodes = father->getNumberOfSons();
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    const Node* son = father->getSon(l);
+
+    VVVdouble* pxy__son = &pxy_[son->getId()];
+    vector<size_t> * _patternLinks_father_son = &likelihoodData_->getArrayPositions(father->getId(), son->getId());
+
+    if (son == node)
+    {
+      VVVdouble* _dLikelihoods_son = &likelihoodData_->getDLikelihoodArray(son->getId());
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _dLikelihoods_son_i = &(*_dLikelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _dLikelihoods_son_i_c = &(*_dLikelihoods_son_i)[c];
+          Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+          VVdouble* pxy__son_c = &(*pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double dl = 0;
+            Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              dl += (*pxy__son_c_x)[y] * (*_dLikelihoods_son_i_c)[y];
+            }
+            (*_dLikelihoods_father_i_c)[x] *= dl;
+          }
+        }
+      }
+    }
+    else
+    {
+      VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _dLikelihoods_father_i = &(*_dLikelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+          Vdouble* _dLikelihoods_father_i_c = &(*_dLikelihoods_father_i)[c];
+          VVdouble* pxy__son_c = &(*pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double dl = 0;
+            Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              dl += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+            }
+            (*_dLikelihoods_father_i_c)[x] *= dl;
+          }
+        }
+      }
+    }
+  }
+
+  //Next step: move toward grand father...
+  computeDownSubtreeDLikelihood(father);
+}
+
+/******************************************************************************
+*                           Second Order Derivatives                         *
+******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getD2LikelihoodForASiteForARateClass(
+  size_t site,
+  size_t rateClass) const
+{
+  double d2l = 0;
+  Vdouble* d2la = &likelihoodData_->getD2LikelihoodArray(tree_->getRootNode()->getId())[likelihoodData_->getRootArrayPosition(site)][rateClass];
+  for (size_t i = 0; i < nbStates_; i++)
+  {
+    d2l += (*d2la)[i] * rootFreqs_[i];
+  }
+  return d2l;
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getD2LikelihoodForASite(size_t site) const
+{
+  // Derivative of the sum is the sum of derivatives:
+  double d2l = 0;
+  for (size_t i = 0; i < nbClasses_; i++)
+  {
+    d2l += getD2LikelihoodForASiteForARateClass(site, i) * rateDistribution_->getProbability(i);
+  }
+  return d2l;
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getD2LogLikelihoodForASite(size_t site) const
+{
+  return getD2LikelihoodForASite(site) / getLikelihoodForASite(site)
+         - pow( getDLikelihoodForASite(site) / getLikelihoodForASite(site), 2);
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getD2LogLikelihood() const
+{
+  // Derivative of the sum is the sum of derivatives:
+  double dl = 0;
+  for (size_t i = 0; i < nbSites_; i++)
+  {
+    dl += getD2LogLikelihoodForASite(i);
+  }
+  return dl;
+}
+
+/******************************************************************************/
+
+double RNonHomogeneousTreeLikelihood::getSecondOrderDerivative(const string& variable) const
+throw (Exception)
+{
+  if (!hasParameter(variable))
+    throw ParameterNotFoundException("RNonHomogeneousTreeLikelihood::getSecondOrderDerivative().", variable);
+  if (getRateDistributionParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to rate distribution parameter are not implemented.");
+  }
+  if (getSubstitutionModelParameters().hasParameter(variable))
+  {
+    throw Exception("Derivatives respective to substitution model parameters are not implemented.");
+  }
+
+  const_cast<RNonHomogeneousTreeLikelihood*>(this)->computeTreeD2Likelihood(variable);
+  return -getD2LogLikelihood();
+}
+
+/******************************************************************************/
+
+void RNonHomogeneousTreeLikelihood::computeTreeD2Likelihood(const string& variable)
+{
+  if (variable == "BrLenRoot")
+  {
+    const Node* father = tree_->getRootNode();
+
+    // Compute dLikelihoods array for the father node.
+    // Fist initialize to 1:
+    VVVdouble* _d2Likelihoods_father = &likelihoodData_->getD2LikelihoodArray(father->getId());
+    size_t nbSites  = _d2Likelihoods_father->size();
+    for (size_t i = 0; i < nbSites; i++)
+    {
+      VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+        for (size_t s = 0; s < nbStates_; s++)
+        {
+          (*_d2Likelihoods_father_i_c)[s] = 1.;
+        }
+      }
+    }
+
+    size_t nbNodes = father->getNumberOfSons();
+    for (size_t l = 0; l < nbNodes; l++)
+    {
+      const Node* son = father->getSon(l);
+
+      if (son->getId() == root1_)
+      {
+        const Node* root1 = father->getSon(0);
+        const Node* root2 = father->getSon(1);
+        vector<size_t> * _patternLinks_fatherroot1_ = &likelihoodData_->getArrayPositions(father->getId(), root1->getId());
+        vector<size_t> * _patternLinks_fatherroot2_ = &likelihoodData_->getArrayPositions(father->getId(), root2->getId());
+        VVVdouble* _likelihoodsroot1_ = &likelihoodData_->getLikelihoodArray(root1->getId());
+        VVVdouble* _likelihoodsroot2_ = &likelihoodData_->getLikelihoodArray(root2->getId());
+        double pos = getParameterValue("RootPosition");
+
+        VVVdouble* d2pxy_root1_ = &d2pxy_[root1_];
+        VVVdouble* d2pxy_root2_ = &d2pxy_[root2_];
+        VVVdouble* dpxy_root1_  = &dpxy_[root1_];
+        VVVdouble* dpxy_root2_  = &dpxy_[root2_];
+        VVVdouble* pxy_root1_   = &pxy_[root1_];
+        VVVdouble* pxy_root2_   = &pxy_[root2_];
+        for (size_t i = 0; i < nbSites; i++)
+        {
+          VVdouble* _likelihoodsroot1__i = &(*_likelihoodsroot1_)[(*_patternLinks_fatherroot1_)[i]];
+          VVdouble* _likelihoodsroot2__i = &(*_likelihoodsroot2_)[(*_patternLinks_fatherroot2_)[i]];
+          VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+          for (size_t c = 0; c < nbClasses_; c++)
+          {
+            Vdouble* _likelihoodsroot1__i_c = &(*_likelihoodsroot1__i)[c];
+            Vdouble* _likelihoodsroot2__i_c = &(*_likelihoodsroot2__i)[c];
+            Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+            VVdouble* d2pxy_root1__c = &(*d2pxy_root1_)[c];
+            VVdouble* d2pxy_root2__c = &(*d2pxy_root2_)[c];
+            VVdouble* dpxy_root1__c  = &(*dpxy_root1_)[c];
+            VVdouble* dpxy_root2__c  = &(*dpxy_root2_)[c];
+            VVdouble* pxy_root1__c   = &(*pxy_root1_)[c];
+            VVdouble* pxy_root2__c   = &(*pxy_root2_)[c];
+            for (size_t x = 0; x < nbStates_; x++)
+            {
+              Vdouble* d2pxy_root1__c_x = &(*d2pxy_root1__c)[x];
+              Vdouble* d2pxy_root2__c_x = &(*d2pxy_root2__c)[x];
+              Vdouble* dpxy_root1__c_x  = &(*dpxy_root1__c)[x];
+              Vdouble* dpxy_root2__c_x  = &(*dpxy_root2__c)[x];
+              Vdouble* pxy_root1__c_x   = &(*pxy_root1__c)[x];
+              Vdouble* pxy_root2__c_x   = &(*pxy_root2__c)[x];
+              double d2l1 = 0, d2l2 = 0, dl1 = 0, dl2 = 0, l1 = 0, l2 = 0;
+              for (size_t y = 0; y < nbStates_; y++)
+              {
+                d2l1 += (*d2pxy_root1__c_x)[y] * (*_likelihoodsroot1__i_c)[y];
+                d2l2 += (*d2pxy_root2__c_x)[y] * (*_likelihoodsroot2__i_c)[y];
+                dl1  += (*dpxy_root1__c_x)[y]  * (*_likelihoodsroot1__i_c)[y];
+                dl2  += (*dpxy_root2__c_x)[y]  * (*_likelihoodsroot2__i_c)[y];
+                l1   += (*pxy_root1__c_x)[y]   * (*_likelihoodsroot1__i_c)[y];
+                l2   += (*pxy_root2__c_x)[y]   * (*_likelihoodsroot2__i_c)[y];
+              }
+              double d2l = pos * pos * d2l1 * l2 + (1. - pos) * (1. - pos) * d2l2 * l1 + 2 * pos * (1. - pos) * dl1 * dl2;
+              (*_d2Likelihoods_father_i_c)[x] *= d2l;
+            }
+          }
+        }
+      }
+      else if (son->getId() == root2_)
+      {
+        //Do nothing, this was accounted when dealing with root1_
+      }
+      else
+      {
+        //Account for a putative multifurcation:
+        vector<size_t> * _patternLinks_father_son = &likelihoodData_->getArrayPositions(father->getId(), son->getId());
+        VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+
+        VVVdouble* pxy__son = &pxy_[son->getId()];
+        for (size_t i = 0; i < nbSites; i++)
+        {
+          VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+          VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+          for (size_t c = 0; c < nbClasses_; c++)
+          {
+            Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+            Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+            VVdouble* pxy__son_c = &(*pxy__son)[c];
+            for (size_t x = 0; x < nbStates_; x++)
+            {
+              double d2l = 0;
+              Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+              for (size_t y = 0; y < nbStates_; y++)
+              {
+                d2l += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+              }
+              (*_d2Likelihoods_father_i_c)[x] *= d2l;
+            }
+          }
+        }
+      }
+    }
+    return;
+  }
+  else if (variable == "RootPosition")
+  {
+    const Node* father = tree_->getRootNode();
+
+    // Compute dLikelihoods array for the father node.
+    // Fist initialize to 1:
+    VVVdouble* _d2Likelihoods_father = &likelihoodData_->getD2LikelihoodArray(father->getId());
+    size_t nbSites  = _d2Likelihoods_father->size();
+    for (size_t i = 0; i < nbSites; i++)
+    {
+      VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+        for (size_t s = 0; s < nbStates_; s++)
+        {
+          (*_d2Likelihoods_father_i_c)[s] = 1.;
+        }
+      }
+    }
+
+    size_t nbNodes = father->getNumberOfSons();
+    for (size_t l = 0; l < nbNodes; l++)
+    {
+      const Node* son = father->getSon(l);
+
+      if (son->getId() == root1_)
+      {
+        const Node* root1 = father->getSon(0);
+        const Node* root2 = father->getSon(1);
+        vector<size_t> * _patternLinks_fatherroot1_ = &likelihoodData_->getArrayPositions(father->getId(), root1->getId());
+        vector<size_t> * _patternLinks_fatherroot2_ = &likelihoodData_->getArrayPositions(father->getId(), root2->getId());
+        VVVdouble* _likelihoodsroot1_ = &likelihoodData_->getLikelihoodArray(root1->getId());
+        VVVdouble* _likelihoodsroot2_ = &likelihoodData_->getLikelihoodArray(root2->getId());
+        double len = getParameterValue("BrLenRoot");
+
+        VVVdouble* d2pxy_root1_ = &d2pxy_[root1_];
+        VVVdouble* d2pxy_root2_ = &d2pxy_[root2_];
+        VVVdouble* dpxy_root1_  = &dpxy_[root1_];
+        VVVdouble* dpxy_root2_  = &dpxy_[root2_];
+        VVVdouble* pxy_root1_   = &pxy_[root1_];
+        VVVdouble* pxy_root2_   = &pxy_[root2_];
+        for (size_t i = 0; i < nbSites; i++)
+        {
+          VVdouble* _likelihoodsroot1__i = &(*_likelihoodsroot1_)[(*_patternLinks_fatherroot1_)[i]];
+          VVdouble* _likelihoodsroot2__i = &(*_likelihoodsroot2_)[(*_patternLinks_fatherroot2_)[i]];
+          VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+          for (size_t c = 0; c < nbClasses_; c++)
+          {
+            Vdouble* _likelihoodsroot1__i_c = &(*_likelihoodsroot1__i)[c];
+            Vdouble* _likelihoodsroot2__i_c = &(*_likelihoodsroot2__i)[c];
+            Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+            VVdouble* d2pxy_root1__c = &(*d2pxy_root1_)[c];
+            VVdouble* d2pxy_root2__c = &(*d2pxy_root2_)[c];
+            VVdouble* dpxy_root1__c  = &(*dpxy_root1_)[c];
+            VVdouble* dpxy_root2__c  = &(*dpxy_root2_)[c];
+            VVdouble* pxy_root1__c   = &(*pxy_root1_)[c];
+            VVdouble* pxy_root2__c   = &(*pxy_root2_)[c];
+            for (size_t x = 0; x < nbStates_; x++)
+            {
+              Vdouble* d2pxy_root1__c_x = &(*d2pxy_root1__c)[x];
+              Vdouble* d2pxy_root2__c_x = &(*d2pxy_root2__c)[x];
+              Vdouble* dpxy_root1__c_x  = &(*dpxy_root1__c)[x];
+              Vdouble* dpxy_root2__c_x  = &(*dpxy_root2__c)[x];
+              Vdouble* pxy_root1__c_x   = &(*pxy_root1__c)[x];
+              Vdouble* pxy_root2__c_x   = &(*pxy_root2__c)[x];
+              double d2l1 = 0, d2l2 = 0, dl1 = 0, dl2 = 0, l1 = 0, l2 = 0;
+              for (size_t y = 0; y < nbStates_; y++)
+              {
+                d2l1 += (*d2pxy_root1__c_x)[y] * (*_likelihoodsroot1__i_c)[y];
+                d2l2 += (*d2pxy_root2__c_x)[y] * (*_likelihoodsroot2__i_c)[y];
+                dl1  += (*dpxy_root1__c_x)[y]  * (*_likelihoodsroot1__i_c)[y];
+                dl2  += (*dpxy_root2__c_x)[y]  * (*_likelihoodsroot2__i_c)[y];
+                l1   += (*pxy_root1__c_x)[y]   * (*_likelihoodsroot1__i_c)[y];
+                l2   += (*pxy_root2__c_x)[y]   * (*_likelihoodsroot2__i_c)[y];
+              }
+              double d2l = len * len * (d2l1 * l2 + d2l2 * l1 - 2 * dl1 * dl2);
+              (*_d2Likelihoods_father_i_c)[x] *= d2l;
+            }
+          }
+        }
+      }
+      else if (son->getId() == root2_)
+      {
+        //Do nothing, this was accounted when dealing with root1_
+      }
+      else
+      {
+        //Account for a putative multifurcation:
+        vector<size_t> * _patternLinks_father_son = &likelihoodData_->getArrayPositions(father->getId(), son->getId());
+        VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+
+        VVVdouble* pxy__son = &pxy_[son->getId()];
+        for (size_t i = 0; i < nbSites; i++)
+        {
+          VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+          VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+          for (size_t c = 0; c < nbClasses_; c++)
+          {
+            Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+            Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+            VVdouble* pxy__son_c = &(*pxy__son)[c];
+            for (size_t x = 0; x < nbStates_; x++)
+            {
+              double d2l = 0;
+              Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+              for (size_t y = 0; y < nbStates_; y++)
+              {
+                d2l += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+              }
+              (*_d2Likelihoods_father_i_c)[x] *= d2l;
+            }
+          }
+        }
+      }
+    }
+    return;
+  }
+
+  // Get the node with the branch whose length must be derivated:
+  size_t brI = TextTools::to<size_t>(variable.substr(5));
+  const Node* branch = nodes_[brI];
+  const Node* father = branch->getFather();
+
+  // Compute dLikelihoods array for the father node.
+  // Fist initialize to 1:
+  VVVdouble* _d2Likelihoods_father = &likelihoodData_->getD2LikelihoodArray(father->getId());
+  size_t nbSites  = _d2Likelihoods_father->size();
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+      for (size_t s = 0; s < nbStates_; s++)
+      {
+        (*_d2Likelihoods_father_i_c)[s] = 1.;
+      }
+    }
+  }
+
+  size_t nbNodes = father->getNumberOfSons();
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    const Node* son = father->getSon(l);
+
+    vector<size_t> * _patternLinks_father_son = &likelihoodData_->getArrayPositions(father->getId(), son->getId());
+    VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+
+    if (son == branch)
+    {
+      VVVdouble* d2pxy__son = &d2pxy_[son->getId()];
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+          Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+          VVdouble* d2pxy__son_c = &(*d2pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double d2l = 0;
+            Vdouble* d2pxy__son_c_x = &(*d2pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              d2l += (*d2pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+            }
+            (*_d2Likelihoods_father_i_c)[x] *= d2l;
+          }
+        }
+      }
+    }
+    else
+    {
+      VVVdouble* pxy__son = &pxy_[son->getId()];
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+          Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+          VVdouble* pxy__son_c = &(*pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double d2l = 0;
+            Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              d2l += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+            }
+            (*_d2Likelihoods_father_i_c)[x] *= d2l;
+          }
+        }
+      }
+    }
+  }
+
+  // Now we go down the tree toward the root node:
+  computeDownSubtreeD2Likelihood(father);
+}
+
+/******************************************************************************/
+
+void RNonHomogeneousTreeLikelihood::computeDownSubtreeD2Likelihood(const Node* node)
+{
+  const Node* father = node->getFather();
+  // We assume that the _dLikelihoods array has been filled for the current node 'node'.
+  // We will evaluate the array for the father node.
+  if (father == 0) return; // We reached the root!
+
+  // Compute dLikelihoods array for the father node.
+  // Fist initialize to 1:
+  VVVdouble* _d2Likelihoods_father = &likelihoodData_->getD2LikelihoodArray(father->getId());
+  size_t nbSites  = _d2Likelihoods_father->size();
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+      for (size_t s = 0; s < nbStates_; s++)
+      {
+        (*_d2Likelihoods_father_i_c)[s] = 1.;
+      }
+    }
+  }
+
+  size_t nbNodes = father->getNumberOfSons();
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    const Node* son = father->getSon(l);
+
+    VVVdouble* pxy__son = &pxy_[son->getId()];
+    vector<size_t> * _patternLinks_father_son = &likelihoodData_->getArrayPositions(father->getId(), son->getId());
+
+    if (son == node)
+    {
+      VVVdouble* _d2Likelihoods_son = &likelihoodData_->getD2LikelihoodArray(son->getId());
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _d2Likelihoods_son_i = &(*_d2Likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _d2Likelihoods_son_i_c = &(*_d2Likelihoods_son_i)[c];
+          Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+          VVdouble* pxy__son_c = &(*pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double d2l = 0;
+            Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              d2l += (*pxy__son_c_x)[y] * (*_d2Likelihoods_son_i_c)[y];
+            }
+            (*_d2Likelihoods_father_i_c)[x] *= d2l;
+          }
+        }
+      }
+    }
+    else
+    {
+      VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+      for (size_t i = 0; i < nbSites; i++)
+      {
+        VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_father_son)[i]];
+        VVdouble* _d2Likelihoods_father_i = &(*_d2Likelihoods_father)[i];
+        for (size_t c = 0; c < nbClasses_; c++)
+        {
+          Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+          Vdouble* _d2Likelihoods_father_i_c = &(*_d2Likelihoods_father_i)[c];
+          VVdouble* pxy__son_c = &(*pxy__son)[c];
+          for (size_t x = 0; x < nbStates_; x++)
+          {
+            double dl = 0;
+            Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+            for (size_t y = 0; y < nbStates_; y++)
+            {
+              dl += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+            }
+            (*_d2Likelihoods_father_i_c)[x] *= dl;
+          }
+        }
+      }
+    }
+  }
+
+  //Next step: move toward grand father...
+  computeDownSubtreeD2Likelihood(father);
+}
+
+/******************************************************************************/
+
+void RNonHomogeneousTreeLikelihood::computeTreeLikelihood()
+{
+  computeSubtreeLikelihood(tree_->getRootNode());
+}
+
+/******************************************************************************/
+
+void RNonHomogeneousTreeLikelihood::computeSubtreeLikelihood(const Node* node)
+{
+  if (node->isLeaf()) return;
+
+  size_t nbSites  = likelihoodData_->getLikelihoodArray(node->getId()).size();
+  size_t nbNodes  = node->getNumberOfSons();
+
+  // Must reset the likelihood array first (i.e. set all of them to 1):
+  VVVdouble* _likelihoods_node = &likelihoodData_->getLikelihoodArray(node->getId());
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    //For each site in the sequence,
+    VVdouble* _likelihoods_node_i = &(*_likelihoods_node)[i];
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      //For each rate classe,
+      Vdouble* _likelihoods_node_i_c = &(*_likelihoods_node_i)[c];
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        //For each initial state,
+        (*_likelihoods_node_i_c)[x] = 1.;
+      }
+    }
+  }
+
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    //For each son node,
+
+    const Node* son = node->getSon(l);
+
+    computeSubtreeLikelihood(son); //Recursive method:
+
+    VVVdouble* pxy__son = &pxy_[son->getId()];
+    vector<size_t> * _patternLinks_node_son = &likelihoodData_->getArrayPositions(node->getId(), son->getId());
+    VVVdouble* _likelihoods_son = &likelihoodData_->getLikelihoodArray(son->getId());
+
+    for (size_t i = 0; i < nbSites; i++)
+    {
+      //For each site in the sequence,
+      VVdouble* _likelihoods_son_i = &(*_likelihoods_son)[(*_patternLinks_node_son)[i]];
+      VVdouble* _likelihoods_node_i = &(*_likelihoods_node)[i];
+      for (size_t c = 0; c < nbClasses_; c++)
+      {
+        //For each rate classe,
+        Vdouble* _likelihoods_son_i_c = &(*_likelihoods_son_i)[c];
+        Vdouble* _likelihoods_node_i_c = &(*_likelihoods_node_i)[c];
+        VVdouble* pxy__son_c = &(*pxy__son)[c];
+        for (size_t x = 0; x < nbStates_; x++)
+        {
+          //For each initial state,
+          Vdouble* pxy__son_c_x = &(*pxy__son_c)[x];
+          double likelihood = 0;
+          for (size_t y = 0; y < nbStates_; y++)
+          {
+            likelihood += (*pxy__son_c_x)[y] * (*_likelihoods_son_i_c)[y];
+          }
+          (*_likelihoods_node_i_c)[x] *= likelihood;
+        }
+      }
+    }
+  }
+}
+
+
+/******************************************************************************/
+
+void RNonHomogeneousTreeLikelihood::displayLikelihood(const Node* node)
+{
+  cout << "Likelihoods at node " << node->getName() << ": " << endl;
+  displayLikelihoodArray(likelihoodData_->getLikelihoodArray(node->getId()));
+  cout << "                                         ***" << endl;
+}
+
diff --git a/src/Bpp/Phyl/Likelihood/RNonHomogeneousTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/RNonHomogeneousTreeLikelihood.h
new file mode 100644
index 0000000..d84b351
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/RNonHomogeneousTreeLikelihood.h
@@ -0,0 +1,278 @@
+//
+// File: RNonHomogeneousTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Tue Oct 9 16:03 2007
+// From file: RHomogeneousTreeLikelihood.h
+//
+
+/*
+  Copyright or © or Copr. CNRS, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _RNONHOMOGENEOUSTREELIKELIHOOD_H_
+#define _RNONHOMOGENEOUSTREELIKELIHOOD_H_
+
+#include "AbstractNonHomogeneousTreeLikelihood.h"
+#include "../Model/SubstitutionModelSet.h"
+#include "DRASRTreeLikelihoodData.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+
+namespace bpp
+{
+
+  /**
+   * @brief This class implement the 'traditional' way of computing likelihood for a tree, allowing for non-homogeneous models of substitutions.
+   *
+   * A non uniform distribution of rates among the sites is allowed (ASRV models).</p>
+   *
+   * This class uses an instance of the DRASRTreeLikelihoodData for conditionnal likelihood storage.
+   *
+   * This class can also use a simple or recursive site compression.
+   * In the simple case, computations for identical sites are not duplicated.
+   * In the recursive case, computations for identical sub-sites (<i>site patterns </i>) are also not duplicated:
+   * Following N. Galtier (personal communication), we define a Pattern as a distinct site
+   * in a sub-dataset corresponding to the dataset with sequences associated to a particular subtree.
+   * The likelihood computation is the same for a given site, hence the idea is to save time from
+   * performing many times the same coputation.
+   * The network between all patterns is defined by the _patternLinks double map, initialized in the
+   * initLikelihoodsWithPatterns() method. This initialisation takes more time than the classic
+   * initTreeLikelihood one, where all likelihoods for a given site <i>i</i> are at the <i>i</i> coordinate
+   * in the likelihood tensor, but is really faster when computing the likelihood (computeLikelihoods() method).
+   * Hence, if you have to compute likelihood many times while holding the tree topology unchanged,
+   * you should use patterns.
+   * This decreases the likelihood computation time, but at a cost: some time is spent to establish the patterns
+   * relationships. Whether to use or not patterns depends on what you actllay need:
+   * - The more you compute likelihoods without changing the data or topology, the more patterns are interesting
+   *   (this divides the cost of computing patterns by the number of computation performed).
+   *   Patterns are hence usefull when you have a high number of computation to perform, while optimizing numerical
+   *   parameters for instance).
+   * - Patterns are more likely to occur whith small alphabet (nucleotides).
+   *
+   * Important note: The input tree will be considered as rooted, since the likelihood of non-stationary models
+   * depends on the position of the root. If the input tree is not rooted, it will be considered as a rotted tree
+   * with a root multifurcation.
+   */
+  class RNonHomogeneousTreeLikelihood :
+    public AbstractNonHomogeneousTreeLikelihood
+  {
+  private:
+
+    mutable DRASRTreeLikelihoodData* likelihoodData_;
+    double minusLogLik_;
+
+  public:
+    /**
+     * @brief Build a new NonHomogeneousTreeLikelihood object without data.
+     *
+     * This constructor only initialize the parameters.
+     * To compute a likelihood, you will need to call the setData() and the computeTreeLikelihood() methods.
+     *
+     * @param tree The tree to use.
+     * @param modelSet The set of substitution models to use.
+     * @param rDist The rate across sites distribution to use.
+     * If true, any rooted tree will be unrooted before likelihood computation.
+     * @param verbose Should I display some info?
+     * @param usePatterns Tell if recursive site compression should be performed.
+     * @param reparametrizeRoot Should we reparametrize the branch lengths at root?
+     * @throw Exception in an error occured.
+     */
+    RNonHomogeneousTreeLikelihood(
+                                  const Tree& tree,
+                                  SubstitutionModelSet* modelSet,
+                                  DiscreteDistribution* rDist,
+                                  bool verbose = true,
+                                  bool usePatterns = true,
+                                  bool reparametrizeRoot = false)
+      throw (Exception);
+	
+    /**
+     * @brief Build a new NonHomogeneousTreeLikelihood object and compute the corresponding likelihood.
+     *
+     * This constructor initializes all parameters, data, and likelihood arrays.
+     *
+     * @param tree The tree to use.
+     * @param data Sequences to use.
+     * @param modelSet The set of substitution models to use.
+     * @param rDist The rate across sites distribution to use.
+     * @param verbose Should I display some info?
+     * @param usePatterns Tell if recursive site compression should be performed.
+     * @param reparametrizeRoot Should we reparametrize the branch lengths at root?
+     * @throw Exception in an error occured.
+     */
+    RNonHomogeneousTreeLikelihood(
+                                  const Tree& tree,
+                                  const SiteContainer& data,
+                                  SubstitutionModelSet* modelSet,
+                                  DiscreteDistribution* rDist,
+                                  bool verbose = true,
+                                  bool usePatterns = true,
+                                  bool reparametrizeRoot = false)
+      throw (Exception);
+
+    RNonHomogeneousTreeLikelihood(const RNonHomogeneousTreeLikelihood& lik);
+    
+    RNonHomogeneousTreeLikelihood & operator=(const RNonHomogeneousTreeLikelihood& lik);
+
+    virtual ~RNonHomogeneousTreeLikelihood();
+
+    RNonHomogeneousTreeLikelihood* clone() const { return new RNonHomogeneousTreeLikelihood(*this); }
+	
+  private:
+
+    /**
+     * @brief Method called by constructors.
+     */
+    void init_(bool usePatterns) throw (Exception);
+	
+  public:
+
+    /**
+     * @name The TreeLikelihood interface.
+     *
+     * Other methods are implemented in the AbstractHomogeneousTreeLikelihood class.
+     *
+     * @{
+     */
+    void setData(const SiteContainer& sites) throw (Exception);
+    double getLikelihood() const;
+    double getLogLikelihood() const;
+    double getLikelihoodForASite(size_t site) const;
+    double getLogLikelihoodForASite(size_t site) const;
+    size_t getSiteIndex(size_t site) const throw (IndexOutOfBoundsException) { return likelihoodData_->getRootArrayPosition(site); }
+    /** @} */
+
+		
+    /**
+     * @name The DiscreteRatesAcrossSites interface implementation:
+     *
+     * @{
+     */
+    double getLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+    double getLogLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+    double getLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const;
+    double getLogLikelihoodForASiteForARateClassForAState(size_t site, size_t rateClass, int state) const;
+    /** @} */
+
+    /**
+     * @brief Implements the Function interface.
+     *
+     * Update the parameter list and call the applyParameters() method.
+     * Then compute the likelihoods at each node (computeLikelihood() method)
+     * and call the getLogLikelihood() method.
+     *
+     * If a subset of the whole parameter list is passed to the function,
+     * only these parameters are updated and the other remain constant (i.e.
+     * equal to their last value).
+     *
+     * @param parameters The parameter list to pass to the function.
+     */
+    void setParameters(const ParameterList& parameters) throw (ParameterNotFoundException, ConstraintException);
+    double getValue() const throw(Exception);
+		
+    /**
+     * @name DerivableFirstOrder interface.
+     *
+     * @{
+     */
+    double getFirstOrderDerivative(const std::string& variable) const throw (Exception);
+    /** @} */
+
+    /**
+     * @name DerivableSecondOrder interface.
+     *
+     * @{
+     */
+    double getSecondOrderDerivative(const std::string& variable) const throw (Exception);
+    double getSecondOrderDerivative(const std::string& variable1, const std::string& variable2) const throw (Exception) { return 0; } // Not implemented for now.
+    /** @} */
+	
+  public:	// Specific methods:
+	
+    DRASRTreeLikelihoodData* getLikelihoodData() { return likelihoodData_; }
+    const DRASRTreeLikelihoodData* getLikelihoodData() const { return likelihoodData_; }
+ 
+    virtual void computeTreeLikelihood();
+
+    virtual double getDLikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+
+    virtual double getDLikelihoodForASite(size_t site) const;
+
+    virtual double getDLogLikelihoodForASite(size_t site) const;
+		
+    virtual double getDLogLikelihood() const;
+		
+    virtual void computeTreeDLikelihood(const std::string& variable);
+
+    virtual double getD2LikelihoodForASiteForARateClass(size_t site, size_t rateClass) const;
+
+    virtual double getD2LikelihoodForASite(size_t site) const;
+
+    virtual double getD2LogLikelihoodForASite(size_t site) const;
+		
+    virtual double getD2LogLikelihood() const;
+		
+    virtual void computeTreeD2Likelihood(const std::string& variable);
+
+	
+  protected:
+			
+    /**
+     * @brief Compute the likelihood for a subtree defined by the Tree::Node <i>node</i>.
+     *
+     * @param node The root of the subtree.
+     */
+    virtual void computeSubtreeLikelihood(const Node * node); //Recursive method.			
+
+    virtual void computeDownSubtreeDLikelihood(const Node *);
+		
+    virtual void computeDownSubtreeD2Likelihood(const Node *);
+	
+    void fireParameterChanged(const ParameterList & params);
+	
+    /**
+     * @brief This method is mainly for debugging purpose.
+     *
+     * @param node The node at which likelihood values must be displayed.
+     */
+    virtual void displayLikelihood(const Node * node);
+
+
+    friend class RNonHomogeneousMixedTreeLikelihood;
+  };
+
+
+} //end of namespace bpp.
+
+#endif	//_RNONHOMOGENEOUSTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/SitePartitionTreeLikelihood.h b/src/Bpp/Phyl/Likelihood/SitePartitionTreeLikelihood.h
new file mode 100644
index 0000000..72c9e97
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/SitePartitionTreeLikelihood.h
@@ -0,0 +1,96 @@
+//
+// File: SitePartitionTreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Mon Dec 7 11:02 2009
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+
+#ifndef _SITEPARTITIONTREELIKELIHOOD_H_
+#define _SITEPARTITIONTREELIKELIHOOD_H_
+
+#include "TreeLikelihood.h"
+
+namespace bpp
+{
+
+/**
+ * @brief Specialization of the TreeLikelihood interface for partition models, homogeneous case.
+ *
+ * These models allow the distinct sites of an alignment to have a different model.
+ * The substitution model is however assumed to be the same along the tree.
+ * suche models are hence homogeneous in time.
+ */
+class SitePartitionHomogeneousTreeLikelihood :
+	public virtual TreeLikelihood
+{
+	public:
+#ifndef NO_VIRTUAL_COV
+    SitePartitionHomogeneousTreeLikelihood* clone() const = 0;
+#endif
+
+  public:
+    const SubstitutionModel* getSubstitutionModel(int nodeId, unsigned int siteIndex) const throw (NodeNotFoundException)
+    {
+      return getSubstitutionModelForSite(siteIndex);
+    }
+
+    SubstitutionModel* getSubstitutionModel(int nodeId, unsigned int siteIndex) throw (NodeNotFoundException)
+    {
+      return getSubstitutionModelForSite(siteIndex);
+    }
+
+    /**
+     * @brief Get the substitution model associated to a given node.
+     *
+     * @param siteIndex The position in the alignment.
+     * @return A pointer toward the corresponding model.
+     */
+    virtual const SubstitutionModel* getSubstitutionModelForSite(int siteIndex) const = 0;
+
+    /**
+     * @brief Get the substitution model associated to a given node.
+     *
+     * @param siteIndex The position in the alignment.
+     * @return A pointer toward the corresponding model.
+     */
+    virtual SubstitutionModel* getSubstitutionModelForSite(unsigned int siteIndex) = 0;
+
+};
+
+} //end of namespace bpp.
+
+#endif	//_SITEPARTITIONTREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/TreeLikelihood.h b/src/Bpp/Phyl/Likelihood/TreeLikelihood.h
new file mode 100755
index 0000000..c9cfc65
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/TreeLikelihood.h
@@ -0,0 +1,430 @@
+//
+// File: TreeLikelihood.h
+// Created by: Julien Dutheil
+// Created on: Fri Oct 17 17:36:44 2003
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _TREELIKELIHOOD_H_
+#define _TREELIKELIHOOD_H_
+
+#include "../Node.h"
+#include "../Tree.h"
+#include "../Model/SubstitutionModel.h"
+#include "TreeLikelihoodData.h"
+
+#include <Bpp/Numeric/ParameterList.h>
+#include <Bpp/Numeric/Parametrizable.h>
+#include <Bpp/Numeric/Function/Functions.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/Alphabet.h>
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The TreeLikelihood interface.
+ *
+ * This interface defines the methods needed for computing the likelihood
+ * of a phylogenetic tree, given a dataset.
+ */ 
+class TreeLikelihood:
+  public virtual DerivableSecondOrder
+{
+  public:
+    /**
+     * @brief An iterator over a set of branches, specified by their node ids.
+     */
+    class BranchIterator
+    {
+      public:
+        virtual ~BranchIterator() {}
+
+      public:
+        /**
+         * @return The id of the next node in the set.
+         */
+        virtual int next() throw (Exception) = 0;
+        /**
+         * @return True if there is at least another node in the set.
+         */
+        virtual bool hasNext() const = 0;
+    };
+
+    /**
+     * @brief An iterator over a set of sites, speicfied by their position.
+     *
+     * In most cases, the position will reflect the index of an inner array used for likelihood storage.
+     */
+    class SiteIterator
+    {
+      public:
+        virtual ~SiteIterator() {}
+
+      public:
+        /**
+         * @return The position of the next site in the set.
+         */
+        virtual size_t next() throw (Exception) = 0;
+        /**
+         * @return True is there is at least another site in the set.
+         */
+        virtual bool hasNext() const = 0;
+    };
+
+    /**
+     * @brief A pair of SubstitutionModel / SiteIterator.
+     */
+    class ConstBranchModelDescription
+    {
+      public:
+        virtual ~ConstBranchModelDescription() {}
+
+      public:
+        virtual const SubstitutionModel* getModel() const = 0;
+        virtual SiteIterator* getNewSiteIterator() const = 0;
+    };
+
+    /**
+     * @brief Iterates through all models used for all sites on a given branch.
+     */
+    class ConstBranchModelIterator
+    {
+      public:
+        virtual ~ConstBranchModelIterator() {}
+
+      public:
+        virtual ConstBranchModelDescription* next() throw (Exception) = 0;
+        virtual bool hasNext() const = 0;
+    };
+
+    /**
+     * @brief A pair of SubstitutionModel / BranchIterator.
+     */
+    class ConstSiteModelDescription
+    {
+      public:
+        virtual ~ConstSiteModelDescription() {}
+
+      public:
+        virtual const SubstitutionModel* getModel() const = 0;
+        virtual BranchIterator* getNewBranchIterator() const = 0;
+    };
+
+    /**
+     * @brief Iterates through all models used for all branches on a given site.
+     */
+    class ConstSiteModelIterator
+    {
+      public:
+        virtual ~ConstSiteModelIterator() {}
+
+      public:
+        virtual ConstSiteModelDescription* next() throw (Exception) = 0;
+        virtual bool hasNext() const = 0;
+    };
+
+  public:
+    TreeLikelihood() {}
+    virtual ~TreeLikelihood() {}
+
+#ifndef NO_VIRTUAL_COV
+    TreeLikelihood* clone() const = 0;
+#endif
+
+  public:
+
+    /**
+     * @brief Set the dataset for which the likelihood must be evaluated.
+     *
+     * @param sites The data set to use.
+     */
+    virtual void setData(const SiteContainer& sites) = 0;
+    
+    /**
+     * @brief Get the dataset for which the likelihood must be evaluated.
+     *
+     * @return A pointer toward the site container where the sequences are stored.
+     */
+    virtual const SiteContainer* getData() const = 0;
+
+    /**
+     * @brief Init the likelihood object.
+     *
+     * This method is used to initialize all parameters.
+     * It is typically called after the constructor and the setData method.
+     * It contains virtual methods that can't be called in the constructor.
+     * @throw Exception if something bad happened, for instance if no data are associated to the likelihood function.
+     */
+    virtual void initialize() throw (Exception) = 0;
+
+    /**
+     * @return 'true' is the likelihood function has been initialized.
+     */
+    virtual bool isInitialized() const = 0;
+
+    /**
+     * @return The underlying likelihood data structure.
+     */
+    virtual TreeLikelihoodData* getLikelihoodData() = 0;
+
+    /**
+     * @return The underlying likelihood data structure.
+     */
+    virtual const TreeLikelihoodData* getLikelihoodData() const = 0;
+
+    /**
+     * @brief Get the likelihood for a site.
+     *
+     * @param site The site index to analyse.
+     * @return The likelihood for site <i>site</i>.
+     */
+    virtual double getLikelihoodForASite(size_t site) const = 0;
+
+    /**
+     * @brief Get the logarithm of the likelihood for a site.
+     *
+     * @param site The site index to analyse.
+     * @return The logarithm of the likelihood for site <i>site</i>.
+     */
+    virtual double getLogLikelihoodForASite(size_t site) const = 0;
+
+    /**
+     * @brief Get the likelihood for a site and for a state.
+     *
+     * @param site The site index to analyse.
+     * @param state The state to consider.
+     * @return The likelihood for site <i>site</i> and state <i>state</i>.
+     */
+    virtual double getLikelihoodForASiteForAState(size_t site, int state) const = 0;
+
+    /**
+     * @brief Get the logarithm of the likelihood for a site and for a state.
+     *
+     * @param site The site index to analyse.
+     * @param state The state to consider.
+     * @return The logarithm of the likelihood for site <i>site</i> and state <i>state</i>.
+     */
+    virtual double getLogLikelihoodForASiteForAState(size_t site, int state) const = 0;
+
+    /**
+     * @brief Get the likelihood for each site.
+     *
+     * @return A vector with all likelihoods for each site.
+     */
+    virtual Vdouble getLikelihoodForEachSite() const = 0;
+
+    /**
+     * @brief Get the logarithm of the likelihood for each site.
+     *
+     * @return A vector with all log likelihoods for each site.
+     */
+    virtual Vdouble getLogLikelihoodForEachSite() const = 0;
+
+    /**
+     * @brief Get the likelihood for each site and for each state.
+     *
+     * @return A 2d vector with all likelihoods for each site and for each state.
+     */
+    virtual VVdouble getLikelihoodForEachSiteForEachState() const = 0;
+
+    /**
+     * @brief Get the logarithm of the likelihood for each site and for each state.
+     *
+     * @return A 2d vector with all log likelihoods for each site and for each state.
+     */
+    virtual VVdouble getLogLikelihoodForEachSiteForEachState() const = 0;
+    
+    /**
+     * @brief Get the likelihood for the whole dataset.
+     *
+     * @return The likelihood of the dataset.
+     */
+    virtual double getLikelihood() const = 0;
+
+    /**
+     * @brief Get the logarithm of the likelihood for the whole dataset.
+     *
+     * @return The logarithm of the likelihood of the dataset.
+     */
+    virtual double getLogLikelihood() const = 0;
+  
+    /**
+     * @brief Get the tree (topology and branch lengths).
+     *
+     * @return The tree of this TreeLikelihood object.
+      */
+    virtual const Tree& getTree() const = 0;
+
+    /**
+     * @brief Get the number of sites in the dataset.
+     *
+     * @return the number of sites in the dataset.
+     */
+    virtual size_t getNumberOfSites() const = 0;
+
+    /**
+     * @brief Get the number of states in the alphabet associated to the dataset.
+     *
+     * @return the number of states in the alphabet associated to the dataset.
+     */    
+    virtual size_t getNumberOfStates() const = 0;
+    
+    /**
+     * @brief Get the alphabet associated to the dataset.
+     *
+     * @return the alphabet associated to the dataset.
+     */    
+    virtual const Alphabet* getAlphabet() const = 0;
+   
+    /**
+     * @name Retrieve some particular parameters subsets.
+     *
+     * @{
+     */
+    
+    /**
+     * @brief Get the branch lengths parameters.
+     *
+     * @return A ParameterList with all branch lengths.
+     */
+    virtual ParameterList getBranchLengthsParameters() const = 0;
+    
+    /**
+     * @brief Get the parameters associated to substitution model(s).
+     *
+     * @return A ParameterList.
+     */
+    virtual ParameterList getSubstitutionModelParameters() const = 0;
+
+    /**
+     * @brief Get the substitution model associated to a given node and alignment column.
+     *
+     * @param nodeId The id of the request node.
+     * @param siteIndex The index of the alignment position.
+     * @see getSiteIndex
+     * @return A pointer toward the corresponding model.
+     * @throw NodeNotFoundException This exception may be thrown if the node is not found (depending on the implementation).
+     */
+    virtual const SubstitutionModel* getSubstitutionModel(int nodeId, size_t siteIndex) const throw (NodeNotFoundException) = 0;
+
+    /**
+     * @brief Get the substitution model associated to a given node and alignment column.
+     *
+     * @param nodeId The id of the request node.
+     * @param siteIndex The index of the alignment position.
+     * @see getSiteIndex
+     * @return A pointer toward the corresponding model.
+     * @throw NodeNotFoundException This exception may be thrown if the node is not found (depending on the implementation).
+     */
+    virtual SubstitutionModel* getSubstitutionModel(int nodeId, size_t siteIndex) throw (NodeNotFoundException) = 0;
+
+    /**
+     * @brief Retrieves all Pij(t) for a particular branch, defined by the upper node and site.
+     *
+     * These intermediate results may be used by other methods.
+     *
+     * @param nodeId The node defining the branch of interest.
+     * @param siteIndex The index of the alignment position.
+     * @see getSiteIndex
+     * @return An array of dimension 2, where a[x][y] is the probability of substituting from x to y.
+     */
+    virtual VVdouble getTransitionProbabilities(int nodeId, size_t siteIndex) const = 0;
+
+    virtual ConstBranchModelIterator* getNewBranchModelIterator(int nodeId) const = 0;
+
+    virtual ConstSiteModelIterator* getNewSiteModelIterator(size_t siteIndex) const = 0;
+
+    /**
+     * @brief Get the index (used for inner computations) of a given site (original alignment column).
+     *
+     * @param site An alignment position.
+     * @return The site index corresponding to the given input alignment position.
+     */
+    virtual size_t getSiteIndex(size_t site) const throw (IndexOutOfBoundsException) = 0;
+
+    /**
+     * @brief Get the values of the frequencies for each state in the alphabet at the root node.
+     *
+     * For reversible models, these are the equilibrium frequencies.
+     * For non-reversible models, these usually are distinct parameters.
+     *
+     * For models without site partitioning, the set of frequencies is the same for all positions.
+     * For partition models, the frequencies may differ from one site to another.
+     *
+     * @param siteIndex The index of the alignment position.
+     * @see getSiteIndex
+     * @return A vector with ancestral frequencies for each state in the alphabet;
+     */
+    virtual const std::vector<double>& getRootFrequencies(size_t siteIndex) const = 0;
+    
+    /** @} */
+
+    /**
+     * @brief Tell if derivatives must be computed.
+     *
+     * This methods calls the enableFirstOrderDerivatives and enableSecondOrderDerivatives.
+     *
+     * @param yn Yes or no.
+     */
+    virtual void enableDerivatives(bool yn) = 0;
+
+    /**
+     * @brief All derivable parameters.
+     *
+     * Usually, this contains all branch lengths parameters.
+     *
+     * @return A ParameterList.
+     */
+    virtual ParameterList getDerivableParameters() const = 0;
+
+    /**
+     * @brief All non derivable parameters.
+     *
+     * Usually, this contains all substitution model parameters and rate distribution.
+     *
+     * @return A ParameterList.
+     */
+    virtual ParameterList getNonDerivableParameters() const = 0;
+
+};
+
+} //end of namespace bpp.
+
+#endif  //_TREELIKELIHOOD_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/TreeLikelihoodData.h b/src/Bpp/Phyl/Likelihood/TreeLikelihoodData.h
new file mode 100644
index 0000000..eed1a53
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/TreeLikelihoodData.h
@@ -0,0 +1,151 @@
+//
+// File: TreeLikelihoodData.h
+// Created by: Julien Dutheil
+// Created on: Sat Dec 30 12:48 2006
+// From file AbstractTreeLikelihood.h
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _TREELIKELIHOODDATA_H_
+#define _TREELIKELIHOODDATA_H_
+
+#include "../Node.h"
+#include "../TreeTemplate.h"
+
+//From SeqLib:
+#include <Bpp/Seq/Alphabet/Alphabet.h>
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+namespace bpp
+{
+
+/**
+ * @brief TreeLikelihood partial data structure.
+ *
+ * Stores inner computation for a given node.
+ *
+ * @see TreeLikelihoodData
+ */
+class TreeLikelihoodNodeData:
+  public virtual Clonable
+{
+  public:
+    TreeLikelihoodNodeData() {}
+    virtual ~TreeLikelihoodNodeData() {}
+
+#ifndef NO_VIRTUAL_COV
+    TreeLikelihoodNodeData*
+#else
+    Clonable*
+#endif
+    clone() const = 0;
+
+  public:
+    /**
+     * @brief Get the node associated to this data structure.
+     *
+     * @return The node associated to this structure.
+     */
+    virtual const Node* getNode() const = 0;
+
+    /**
+     * @brief Set the node associated to this data
+     *
+     * A pointer toward this node will be created and associated to this data.
+     *
+     * @param node The node to be associated to this data.
+     */
+    virtual void setNode(const Node* node) = 0;
+};
+
+/**
+ * @brief TreeLikelihood data structure.
+ *
+ * Stores all the inner computations:
+ * - conditionnal likelihoods for each node,
+ * - correspondance between sites in the dataset and array indices.
+ * 
+ * @see TreeLikelihoodNodeData
+ */
+class TreeLikelihoodData:
+  public virtual Clonable
+{
+  public:
+    TreeLikelihoodData() {}
+    virtual ~TreeLikelihoodData() {}
+    
+#ifndef NO_VIRTUAL_COV
+    TreeLikelihoodData* clone() const = 0;
+#endif
+
+  public:
+    virtual const Alphabet* getAlphabet() const = 0;
+    virtual const TreeTemplate<Node>* getTree() const = 0;
+    virtual size_t getArrayPosition(int parentId, int sonId, size_t currentPosition) const = 0;
+    virtual size_t getRootArrayPosition(size_t site) const = 0;
+    virtual       TreeLikelihoodNodeData& getNodeData(int nodeId) = 0;
+    virtual const TreeLikelihoodNodeData& getNodeData(int nodeId) const = 0;
+
+    /**
+     * @return The number of non redundant patterns.
+     */
+    virtual size_t getNumberOfDistinctSites() const = 0;
+    
+    /**
+     * @return The total number of sites.
+     */
+    virtual size_t getNumberOfSites() const = 0;
+    
+    /**
+     * @return Get the number of states used in the model.
+     */
+    virtual size_t getNumberOfStates() const = 0;
+
+    /**
+     * @return The frequency of a given pattern.
+     */
+    virtual unsigned int getWeight(size_t pos) const = 0;
+    
+    /**
+     * @return Frequencies for each pattern.
+     */
+    virtual const std::vector<unsigned int>& getWeights() const = 0;
+
+};
+
+} //end of namespace bpp.
+
+#endif //_TREELIKELIHOODDATA_H_
+
diff --git a/src/Bpp/Phyl/Likelihood/TreeLikelihoodTools.cpp b/src/Bpp/Phyl/Likelihood/TreeLikelihoodTools.cpp
new file mode 100644
index 0000000..f990951
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/TreeLikelihoodTools.cpp
@@ -0,0 +1,121 @@
+//
+// File: TreeLikelihoodTools.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Jun 30 12:25 2009
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "TreeLikelihoodTools.h"
+
+using namespace std;
+using namespace bpp;
+
+void TreeLikelihoodTools::getAncestralFrequencies(
+        const TreeLikelihood& tl,
+        size_t site,
+        std::map<int, std::vector<double> >& frequencies,
+        bool alsoForLeaves) throw (Exception)
+{
+  int currentId = tl.getTree().getRootId();
+  vector<double> currentFreqs = tl.getRootFrequencies(tl.getSiteIndex(site));
+  getAncestralFrequencies_(tl, tl.getSiteIndex(site), currentId, currentFreqs, frequencies, alsoForLeaves); 
+}
+
+void TreeLikelihoodTools::getAncestralFrequencies(
+        const TreeLikelihood& tl,
+        std::map<int, std::vector<double> >& frequencies,
+        bool alsoForLeaves) throw (Exception)
+{
+  size_t n = tl.getLikelihoodData()->getNumberOfDistinctSites();
+  size_t ns = tl.getNumberOfStates();
+  double sumw = 0, w;
+  map<int, vector<double> > siteFrequencies;
+  for (size_t i = 0; i < n; ++i)
+  {
+    w = tl.getLikelihoodData()->getWeight(i);
+    sumw += w;
+  }
+  for (size_t i = 0; i < n; ++i)
+  {
+    w = tl.getLikelihoodData()->getWeight(i);
+    getAncestralFrequencies(tl, i, siteFrequencies, alsoForLeaves);
+    //Initialization
+    if (i == 0)
+    {
+      frequencies = siteFrequencies; //Initialize all nodes ids.
+      //Now reset to 0:
+      for (map<int, vector<double> >::iterator it = frequencies.begin(); it != frequencies.end(); it++)
+        VectorTools::fill(it->second, 0.);
+    }
+    map<int, vector<double> >::iterator it = frequencies.begin();
+    map<int, vector<double> >::iterator itSite = siteFrequencies.begin();
+    for (size_t j = 0; j < frequencies.size(); ++j)
+    {
+      for (size_t k = 0; k < ns; ++k)
+        it->second[k] += itSite->second[k] * w / sumw;
+      it++;
+      itSite++;
+    }
+  }
+}
+
+void TreeLikelihoodTools::getAncestralFrequencies_(
+        const TreeLikelihood& tl,
+        size_t siteIndex,
+        int parentId,
+        const std::vector<double>& ancestralFrequencies,
+        std::map<int,std::vector<double> >& frequencies,
+        bool alsoForLeaves) throw (Exception)
+{
+  if (!tl.getTree().isLeaf(parentId) || alsoForLeaves)
+    frequencies[parentId] = ancestralFrequencies;
+  vector<int> sonsId = tl.getTree().getSonsId(parentId);
+  for (size_t i = 0; i < sonsId.size(); i++)
+  {
+    vector<double> sonFrequencies(tl.getNumberOfStates());
+    VVdouble pijt = tl.getTransitionProbabilities(sonsId[i], siteIndex);
+    for (size_t j = 0; j < tl.getNumberOfStates(); j++)
+    {
+      double x = 0;
+      for (size_t k = 0; k < tl.getNumberOfStates(); k++)
+      {
+        x += pijt[k][j] * ancestralFrequencies[k];
+      }
+      sonFrequencies[j] = x;
+    }
+    getAncestralFrequencies_(tl, siteIndex, sonsId[i], sonFrequencies, frequencies, alsoForLeaves);
+  }
+}
+
diff --git a/src/Bpp/Phyl/Likelihood/TreeLikelihoodTools.h b/src/Bpp/Phyl/Likelihood/TreeLikelihoodTools.h
new file mode 100644
index 0000000..277dd4e
--- /dev/null
+++ b/src/Bpp/Phyl/Likelihood/TreeLikelihoodTools.h
@@ -0,0 +1,119 @@
+//
+// File: TreeLikelihoodTools.h
+// Created by: Julien Dutheil
+// Created on: Tue Jun 30 12:25 2009
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _TREELIKELIHOODTOOLS_H_
+#define _TREELIKELIHOODTOOLS_H_
+
+#include "TreeLikelihood.h"
+
+//From the STL:
+#include <vector>
+#include <map>
+
+namespace bpp
+{
+
+/**
+ * @brief Utilitary methods that work with TreeLikelihood objects.
+ */
+class TreeLikelihoodTools
+{
+  public:
+    TreeLikelihoodTools() {}
+    virtual ~TreeLikelihoodTools() {}
+
+  public:
+    /**
+     * @brief Compute the expected ancestral frequencies of all states at all (inner) nodes
+     * according to a Markov process defined by a given substitution model.
+     *
+     * The computation is performed for a given site. If the likelihood object has no
+     * site partition, then the method will return the same result for all positions.
+     *
+     * @param tl          [in] A tree likelihood object.
+     * @param site        [in] The site for which the frequencies should be computed.
+     * @param frequencies [out] A map where to store the results, as a vector of double (the 
+     * size of which being equal to the number of states in the model), and with nodes id as keys.
+     * @param alsoForLeaves [opt] Tell if frequencies should also be estimated for terminal nodes.
+     * @throw Exception In case something bad happens, like an unvalid model set.
+     */
+    static void getAncestralFrequencies(
+        const TreeLikelihood& tl,
+        size_t site,
+        std::map<int, std::vector<double> >& frequencies,
+        bool alsoForLeaves = false) throw (Exception);
+
+    /**
+     * @brief Compute the expected ancestral frequencies of all states at all (inner) nodes
+     * according to a Markov process defined by a given substitution model.
+     *
+     * The computation is averaged over all sites. If the likelihood object has no
+     * site partition, then the method will return the same result as all single site numbers.
+     *
+     * @param tl          [in] A tree likelihood object.
+     * @param frequencies [out] A map where to store the results, as a vector of double (the 
+     * size of which being equal to the number of states in the model), and with nodes id as keys.
+     * @param alsoForLeaves [opt] Tell if frequencies should also be estimated for terminal nodes.
+     * @throw Exception In case something bad happens, like an unvalid model set.
+     */
+    static void getAncestralFrequencies(
+        const TreeLikelihood& tl,
+        std::map<int, std::vector<double> >& frequencies,
+        bool alsoForLeaves = false) throw (Exception);
+
+  private:
+    /**
+     * @brief Recursive method, for internal use only.
+     *
+     * @see getAncestralFrequencies()
+     */
+    static void getAncestralFrequencies_(
+        const TreeLikelihood& tl,
+        size_t siteIndex,
+        int parentId,
+        const std::vector<double>& ancestralFrequencies,
+        std::map<int, std::vector<double> >& frequencies,
+        bool alsoForLeaves) throw (Exception);
+ 
+};
+
+} //end of namespace bpp.
+
+#endif //_TREELIKELIHOODTOOLS_H_
+
diff --git a/src/Bpp/Phyl/Mapping/DecompositionSubstitutionCount.cpp b/src/Bpp/Phyl/Mapping/DecompositionSubstitutionCount.cpp
new file mode 100644
index 0000000..6a4a090
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/DecompositionSubstitutionCount.cpp
@@ -0,0 +1,295 @@
+//
+// File: DecompositionSubstitutionCount.h
+// Created by: Julien Dutheil
+// Created on: Thu Mar 17 16:08 2011
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "DecompositionSubstitutionCount.h"
+
+#include "Bpp/Numeric/Matrix/MatrixTools.h"
+#include <vector>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+DecompositionSubstitutionCount::DecompositionSubstitutionCount(const ReversibleSubstitutionModel* model, SubstitutionRegister* reg, const AlphabetIndex2* weights) :
+  AbstractSubstitutionCount(reg),
+  AbstractWeightedSubstitutionCount(weights, true),
+  model_(model),
+  nbStates_(model->getNumberOfStates()),
+  jMat_(nbStates_, nbStates_),
+  v_(nbStates_, nbStates_),
+  vInv_(nbStates_, nbStates_),
+  lambda_(nbStates_, nbStates_),
+  bMatrices_(reg->getNumberOfSubstitutionTypes()),
+  insideProducts_(reg->getNumberOfSubstitutionTypes()),
+  counts_(reg->getNumberOfSubstitutionTypes()),
+  currentLength_(-1.)
+{
+  //Check compatiblity between model and substitution register:
+  if (model->getAlphabet()->getAlphabetType() != reg->getAlphabet()->getAlphabetType())
+    throw Exception("DecompositionSubstitutionCount (constructor): alphabets do not match between register and model.");
+
+  //Initialize all B matrices according to substitution register. This is done once for all,
+  //unless the number of states changes:
+  initBMatrices_();
+  fillBMatrices_();
+  computeEigen_();
+  computeProducts_();
+}				
+    
+/******************************************************************************/
+
+void DecompositionSubstitutionCount::fillBMatrices_()
+{
+  int n = static_cast<int>(nbStates_); //Note jdutheil 20/01/13: shoudl be generalized in case sattes are not 0:n !
+  for (int j = 0; j < n; ++j) {
+    for (int k = 0; k < n; ++k) {
+      size_t i = register_->getType(j, k);
+      if (i > 0 && k != j) {
+        bMatrices_[i - 1](j, k) = model_->Qij(j, k) * (weights_ ? weights_->getIndex(j, k) : 1);
+      }
+    }
+  }
+}
+
+void DecompositionSubstitutionCount::computeEigen_()
+{
+	v_      = model_->getColumnRightEigenVectors();
+  vInv_   = model_->getRowLeftEigenVectors();
+	lambda_ = model_->getEigenValues();
+}
+
+void DecompositionSubstitutionCount::computeProducts_()
+{
+  for (size_t i = 0; i < register_->getNumberOfSubstitutionTypes(); ++i) {
+    //vInv_ %*% bMatrices_[i] %*% v_;
+    RowMatrix<double> tmp(nbStates_, nbStates_);
+    MatrixTools::mult(vInv_, bMatrices_[i], tmp);
+    MatrixTools::mult(tmp, v_, insideProducts_[i]);
+  }
+}
+
+void DecompositionSubstitutionCount::resetBMatrices_()
+{
+  size_t nbTypes = register_->getNumberOfSubstitutionTypes();
+  bMatrices_.resize(nbTypes);
+  insideProducts_.resize(nbTypes);
+  counts_.resize(nbTypes);
+}
+
+void DecompositionSubstitutionCount::resetStates_()
+{
+  jMat_.resize(nbStates_, nbStates_);
+  v_.resize(nbStates_, nbStates_);
+  vInv_.resize(nbStates_, nbStates_);
+  lambda_.resize(nbStates_);
+}
+
+void DecompositionSubstitutionCount::initBMatrices_()
+{
+  //Re-initialize all B matrices according to substitution register.
+  for (size_t i = 0; i < register_->getNumberOfSubstitutionTypes(); ++i) {
+    bMatrices_[i].resize(nbStates_, nbStates_);
+    insideProducts_[i].resize(nbStates_, nbStates_);
+    counts_[i].resize(nbStates_, nbStates_);
+  }
+}
+
+void DecompositionSubstitutionCount::jFunction_(const std::vector<double>& lambda, double t, RowMatrix<double>& result) const
+{
+	vector<double> expLam = VectorTools::exp(lambda * t);
+	for (unsigned int i = 0; i < nbStates_; ++i) {
+	  for (unsigned int j = 0; j < nbStates_; ++j) {
+      double dd = lambda[i] - lambda[j];
+      if (dd == 0) {
+  		  result(i, j) = t * expLam[i];
+      } else {
+  		  result(i, j) = (expLam[i] - expLam[j]) / dd;
+      }
+    }
+	}
+}
+
+/******************************************************************************/
+
+void DecompositionSubstitutionCount::computeCounts_(double length) const
+{
+  jFunction_(lambda_, length, jMat_);
+  for (size_t i = 0; i < register_->getNumberOfSubstitutionTypes(); ++i) {
+    RowMatrix<double> tmp1(nbStates_, nbStates_), tmp2(nbStates_, nbStates_);
+    MatrixTools::hadamardMult(jMat_, insideProducts_[i], tmp1);
+    MatrixTools::mult(v_, tmp1, tmp2);
+    MatrixTools::mult(tmp2, vInv_, counts_[i]);
+	}
+  // Now we must divide by pijt:
+  RowMatrix<double> P = model_->getPij_t(length);
+  for (size_t i = 0; i < register_->getNumberOfSubstitutionTypes(); i++) {
+    for (size_t j = 0; j < nbStates_; j++) {
+      for (size_t k = 0; k < nbStates_; k++) {
+        counts_[i](j, k) /= P(j, k);
+        if (isnan(counts_[i](j, k)) || counts_[i](j, k) < 0.) {
+          counts_[i](j, k) = 0.;
+        }
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+Matrix<double>* DecompositionSubstitutionCount::getAllNumbersOfSubstitutions(double length, size_t type) const
+{
+  if (length < 0)
+    throw Exception("DecompositionSubstitutionCount::getAllNumbersOfSubstitutions. Negative branch length: " + TextTools::toString(length) + ".");
+  if (length != currentLength_)
+  {
+  //if (length < 0.000001) // Limit case!
+  //{ 
+  //  unsigned int s = model_->getAlphabet()->getSize();
+  //  for (unsigned int i = 0; i < s; i++)
+  //  {
+  //    for (unsigned int j = 0; j < s; j++)
+  //    {
+  //      m_(i, j) = i == j ? 0. : 1.;
+  //    }
+  //  }
+  //}
+  //else
+  //{
+  // Else we need to recompute M:
+    computeCounts_(length);
+  //}
+
+    currentLength_ = length;
+  }
+  return new RowMatrix<double>(counts_[type - 1]);
+}
+
+/******************************************************************************/
+
+double DecompositionSubstitutionCount::getNumberOfSubstitutions(int initialState, int finalState, double length, size_t type) const
+{
+  if (length < 0)
+    throw Exception("DecompositionSubstitutionCount::getNumbersOfSubstitutions. Negative branch length: " + TextTools::toString(length) + ".");
+  if (length != currentLength_)
+  {
+    computeCounts_(length);
+    currentLength_ = length;
+  }
+  return counts_[type - 1](initialState, finalState);
+}
+
+/******************************************************************************/
+
+std::vector<double> DecompositionSubstitutionCount::getNumberOfSubstitutionsForEachType(int initialState, int finalState, double length) const
+{
+  if (length < 0)
+    throw Exception("DecompositionSubstitutionCount::getNumbersOfSubstitutions. Negative branch length: " + TextTools::toString(length) + ".");
+  if (length != currentLength_)
+  {
+    computeCounts_(length);
+    currentLength_ = length;
+  }
+  std::vector<double> v(getNumberOfSubstitutionTypes());
+  for (unsigned int t = 0; t < getNumberOfSubstitutionTypes(); ++t) {
+    v[t] = counts_[t](initialState, finalState);
+  }
+  return v;
+}
+    
+/******************************************************************************/
+
+void DecompositionSubstitutionCount::setSubstitutionModel(const SubstitutionModel* model)
+{
+  const ReversibleSubstitutionModel* rModel = dynamic_cast<const ReversibleSubstitutionModel*>(model);
+  if (!rModel)
+    throw Exception("DecompositionSubstitutionCount::setSubstitutionModel. Only works with reversible models for now.");
+
+  //Check compatiblity between model and substitution register:
+  if (model->getAlphabet()->getAlphabetType() != register_->getAlphabet()->getAlphabetType())
+    throw Exception("DecompositionSubstitutionCount::setSubstitutionModel: alphabets do not match between register and model.");
+  model_ = rModel;
+  unsigned int n = model->getAlphabet()->getSize();
+  if (n != nbStates_) {
+    nbStates_ = n;
+    resetStates_();
+    initBMatrices_();
+  }
+  fillBMatrices_();
+  computeEigen_();
+  computeProducts_();
+
+  //Recompute counts:
+  computeCounts_(currentLength_);
+}
+
+/******************************************************************************/
+
+void DecompositionSubstitutionCount::substitutionRegisterHasChanged() throw (Exception)
+{
+  //Check compatiblity between model and substitution register:
+  if (model_->getAlphabet()->getAlphabetType() != register_->getAlphabet()->getAlphabetType())
+    throw Exception("DecompositionSubstitutionCount::substitutionRegisterHasChanged: alphabets do not match between register and model.");
+
+  resetBMatrices_();
+  initBMatrices_();
+  fillBMatrices_();
+  computeProducts_();
+
+  //Recompute counts:
+  if (currentLength_ > 0)
+   computeCounts_(currentLength_);
+}
+
+/******************************************************************************/
+
+void DecompositionSubstitutionCount::weightsHaveChanged() throw (Exception)
+{
+  if (weights_->getAlphabet()->getAlphabetType() != register_->getAlphabet()->getAlphabetType())
+    throw Exception("DecompositionSubstitutionCount::weightsHaveChanged. Incorrect alphabet type.");
+
+  fillBMatrices_();
+  
+  //Recompute counts:
+  if (currentLength_ > 0)
+    computeCounts_(currentLength_);
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Mapping/DecompositionSubstitutionCount.h b/src/Bpp/Phyl/Mapping/DecompositionSubstitutionCount.h
new file mode 100644
index 0000000..6831349
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/DecompositionSubstitutionCount.h
@@ -0,0 +1,142 @@
+//
+// File: DecompositionSubstitutionCount.h
+// Created by: Julien Dutheil
+// Created on: Thu Mar 17 16:08 2011
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _DECOMPOSITIONSUBSTITUTIONCOUNT_H_
+#define _DECOMPOSITIONSUBSTITUTIONCOUNT_H_
+
+#include "WeightedSubstitutionCount.h"
+
+#include <Bpp/Numeric/Matrix/Matrix.h>
+
+namespace bpp
+{
+
+/**
+ * @brief Analytical substitution count using the eigen decomposition method.
+ *
+ * The codes is adapted from the original R code by Paula Tataru and Asger Hobolth.
+ * Only reversible models are supported for now.
+ *
+ * @author Julien Dutheil
+ */
+class DecompositionSubstitutionCount:
+  public AbstractSubstitutionCount,
+  public AbstractWeightedSubstitutionCount
+{
+	private:
+		const ReversibleSubstitutionModel* model_;
+    size_t nbStates_;
+		mutable RowMatrix<double> jMat_, v_, vInv_;
+    mutable std::vector<double> lambda_;
+    std::vector< RowMatrix<double> > bMatrices_, insideProducts_;
+    mutable std::vector< RowMatrix<double> > counts_;
+    mutable double currentLength_;
+	
+	public:
+		DecompositionSubstitutionCount(const ReversibleSubstitutionModel* model, SubstitutionRegister* reg, const AlphabetIndex2* weights = 0);
+		
+    DecompositionSubstitutionCount(const DecompositionSubstitutionCount& dsc) :
+      AbstractSubstitutionCount(dsc),
+      AbstractWeightedSubstitutionCount(dsc),
+      model_(dsc.model_),
+      nbStates_(dsc.nbStates_),
+      jMat_(dsc.jMat_),
+      v_(dsc.v_),
+      vInv_(dsc.vInv_),
+      lambda_(dsc.lambda_),
+      bMatrices_(dsc.bMatrices_),
+      insideProducts_(dsc.insideProducts_),
+      counts_(dsc.counts_),
+      currentLength_(dsc.currentLength_)
+    {}				
+    
+    DecompositionSubstitutionCount& operator=(const DecompositionSubstitutionCount& dsc)
+    {
+      AbstractSubstitutionCount::operator=(dsc);
+      AbstractWeightedSubstitutionCount::operator=(dsc);
+      model_          = dsc.model_;
+      nbStates_       = dsc.nbStates_;
+      jMat_           = dsc.jMat_;
+      v_              = dsc.v_;
+      vInv_           = dsc.vInv_;
+      lambda_         = dsc.lambda_;
+      bMatrices_      = dsc.bMatrices_;
+      insideProducts_ = dsc.insideProducts_;
+      counts_         = dsc.counts_;
+      currentLength_  = dsc.currentLength_;
+      return *this;
+    }				
+		
+    virtual ~DecompositionSubstitutionCount() {}
+		
+    DecompositionSubstitutionCount* clone() const { return new DecompositionSubstitutionCount(*this); }
+
+	public:
+		double getNumberOfSubstitutions(int initialState, int finalState, double length, size_t type = 1) const;
+
+    Matrix<double>* getAllNumbersOfSubstitutions(double length, size_t type = 1) const;
+    
+    std::vector<double> getNumberOfSubstitutionsForEachType(int initialState, int finalState, double length) const;
+   
+    /**
+     * @brief Set the substitution model.
+     *
+     * @param model A pointer toward the substitution model to use. Only reversible models are currently supported. Setting a non-reversible model will throw an exception.
+     */
+    void setSubstitutionModel(const SubstitutionModel* model);
+
+  protected:
+    void computeCounts_(double length) const;
+    void jFunction_(const std::vector<double>& lambda, double t, RowMatrix<double>& result) const;
+    void substitutionRegisterHasChanged() throw (Exception);
+    void weightsHaveChanged() throw (Exception);
+
+  private:
+    void resetStates_();
+    void resetBMatrices_();
+    void initBMatrices_();
+    void fillBMatrices_();
+    void computeEigen_();
+    void computeProducts_();
+};
+
+} //end of namespace bpp.
+
+#endif // _DECOMPOSITIONSUBSTITUTIONCOUNT_H_
+
diff --git a/src/Bpp/Phyl/Mapping/LaplaceSubstitutionCount.cpp b/src/Bpp/Phyl/Mapping/LaplaceSubstitutionCount.cpp
new file mode 100644
index 0000000..beee183
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/LaplaceSubstitutionCount.cpp
@@ -0,0 +1,148 @@
+//
+// File: LaplaceSubstitutionCount.cpp
+// Created by: Julien Dutheil
+// Created on: Wed Apr 5 11:21 2006
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "LaplaceSubstitutionCount.h"
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+using namespace bpp;
+
+/******************************************************************************/
+
+void LaplaceSubstitutionCount::computeCounts(double length) const
+{
+  RowMatrix<double> Q = model_->getGenerator();
+  // L is the diagonal matrix with all substitution rates.
+  size_t s = Q.getNumberOfRows();
+  RowMatrix<double> QL(s, s);
+  for (size_t i = 0; i < s; i++)
+  {
+    for (size_t j = 0; j < s; j++)
+    {
+      QL(i, j) = ((i == j) ? 0. : Q(i, j));
+    }
+  }
+
+  MatrixTools::fill(m_, 0.);
+  RowMatrix<double> M2(s, s);
+  RowMatrix<double> M3(s, s);
+  RowMatrix<double> M4(s, s);
+  RowMatrix<double> M5(s, s);
+  for (int n = 1; n < cutOff_; n++)
+  {
+    MatrixTools::fill(M2, 0.);
+    for (int p = 0; p < n; p++)
+    {
+      MatrixTools::pow(Q, p, M3);         // Q^p -> M5
+      MatrixTools::mult(M3, QL, M4);      // Q^p . QL -> M4
+      MatrixTools::pow(Q, n - p - 1, M3); // Q^(n-p-1) -> M3
+      MatrixTools::mult(M4, M3, M5);      // Q^p . QL . Q^(n-p-1) -> M5
+      MatrixTools::add(M2, M5);
+    }
+    MatrixTools::scale(M2, pow(length, n) / NumTools::fact(n));
+    MatrixTools::add(m_, M2);
+  }
+
+  // Now we must divide by pijt:
+  RowMatrix<double> P = model_->getPij_t(length);
+  for (size_t i = 0; i < s; i++)
+  {
+    for (size_t j = 0; j < s; j++)
+    {
+      m_(i, j) /= P(i, j);
+    }
+  }
+}
+
+/******************************************************************************/
+
+double LaplaceSubstitutionCount::getNumberOfSubstitutions(int initialState, int finalState, double length, size_t type) const
+{
+  if (length == currentLength_)
+    return m_(initialState, finalState);
+  if (length < 0.000001)
+    return initialState == finalState ? 0. : 1.;  // Limit case!
+  // Else we need to recompute M:
+  computeCounts(length);
+
+  currentLength_ = length;
+  return m_(initialState, finalState);
+}
+
+/******************************************************************************/
+
+Matrix<double>* LaplaceSubstitutionCount::getAllNumbersOfSubstitutions(double length, size_t type) const
+{
+  if (length == currentLength_)
+    return new RowMatrix<double>(m_);
+  if (length < 0.000001) // Limit case!
+  {
+    size_t s = model_->getAlphabet()->getSize();
+    for (size_t i = 0; i < s; i++)
+    {
+      for (size_t j = 0; j < s; j++)
+      {
+        m_(i, j) = i == j ? 0. : 1.;
+      }
+    }
+  }
+  else
+  {
+    // Else we need to recompute M:
+    computeCounts(length);
+  }
+
+  currentLength_ = length;
+
+  return new RowMatrix<double>(m_);
+}
+
+/******************************************************************************/
+
+void LaplaceSubstitutionCount::setSubstitutionModel(const SubstitutionModel* model)
+{
+  model_ = model;
+  size_t n = model->getAlphabet()->getSize();
+  m_.resize(n, n);
+  // Recompute counts:
+  computeCounts(currentLength_);
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Mapping/LaplaceSubstitutionCount.h b/src/Bpp/Phyl/Mapping/LaplaceSubstitutionCount.h
new file mode 100644
index 0000000..e54e1d9
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/LaplaceSubstitutionCount.h
@@ -0,0 +1,129 @@
+//
+// File: LaplaceSubstitutionCount.h
+// Created by: Julien Dutheil
+// Created on: Wed Apr 5 11:21 2006
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _LAPLACESUBSTITUTIONCOUNT_H_
+#define _LAPLACESUBSTITUTIONCOUNT_H_
+
+#include "SubstitutionCount.h"
+#include "../Model/SubstitutionModel.h"
+
+namespace bpp
+{
+
+  /**
+   * @brief Laplace estimate of the substitution count.
+   *
+   * This method uses Laplace transforms, as described in 
+   * Dutheil J, Pupko T, Jean-Marie A, Galtier N.
+   * A model-based approach for detecting coevolving positions in a molecule.
+   * Mol Biol Evol. 2005 Sep;22(9):1919-28.
+   *
+   * @see UniformizationSubstitutionCount
+   * @see DecompositionSubstitutionCount
+   * @author Julien Dutheil
+   */
+  class LaplaceSubstitutionCount:
+    public AbstractSubstitutionCount
+  {
+  private:
+    const SubstitutionModel* model_;
+    int cutOff_;
+    mutable double currentLength_;
+    mutable RowMatrix<double> m_;
+	
+  public:
+    LaplaceSubstitutionCount(const SubstitutionModel* model, int cutOff) :
+      AbstractSubstitutionCount(new TotalSubstitutionRegister(model->getAlphabet())),
+      model_        (model),
+      cutOff_       (cutOff),
+      currentLength_(-1),
+      m_            (model->getNumberOfStates(), model->getNumberOfStates())
+    {}
+	
+    LaplaceSubstitutionCount(const LaplaceSubstitutionCount& asc) :
+    AbstractSubstitutionCount(asc),
+    model_        (asc.model_),
+    cutOff_       (asc.cutOff_),
+    currentLength_(asc.currentLength_),
+    m_            (asc.m_)
+    {}
+				
+    LaplaceSubstitutionCount& operator=(const LaplaceSubstitutionCount& asc)
+    {
+      AbstractSubstitutionCount::operator=(asc);
+      model_         = asc.model_;
+      cutOff_        = asc.cutOff_;
+      currentLength_ = asc.currentLength_;
+      m_             = asc.m_;
+      return *this;
+    }
+				
+    virtual ~LaplaceSubstitutionCount() {}
+		
+    LaplaceSubstitutionCount* clone() const { return new LaplaceSubstitutionCount(*this); }
+	
+  public:
+    double getNumberOfSubstitutions(int initialState, int finalState, double length, size_t type = 1) const;
+    Matrix<double>* getAllNumbersOfSubstitutions(double length, size_t type = 1) const;
+    std::vector<double> getNumberOfSubstitutionsForEachType(int initialState, int finalState, double length) const
+    {
+      std::vector<double> v(0);
+      v[0] = getNumberOfSubstitutions(initialState, finalState, length, 0);
+      return v;
+    }
+
+    void setSubstitutionModel(const SubstitutionModel* model);
+
+    /*
+     *@param reg pointer to a SubstitutionRegister
+     *
+     */
+    void setSubstitutionRegister(SubstitutionRegister* reg) throw (Exception) {
+      throw Exception("LaplaceSubstitutionCount::setSubstitutionRegister. This SubstitutionsCount only works with a TotalSubstitutionRegister.");
+    }
+
+  protected:
+    void computeCounts(double length) const;
+    void substitutionRegisterHasChanged() {}
+  };
+
+} //end of namespace bpp.
+
+#endif //_LAPLACESUBSTITUTIONCOUNT_H_
+
diff --git a/src/Bpp/Phyl/Mapping/NaiveSubstitutionCount.cpp b/src/Bpp/Phyl/Mapping/NaiveSubstitutionCount.cpp
new file mode 100644
index 0000000..d22750c
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/NaiveSubstitutionCount.cpp
@@ -0,0 +1,70 @@
+//
+// File: NaiveSubstitutionCount.h
+// Created by: Julien Dutheil
+// Created on: Wed Apr 5 11:08 2006
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "NaiveSubstitutionCount.h"
+
+using namespace bpp;
+
+Matrix<double>* NaiveSubstitutionCount::getAllNumbersOfSubstitutions(double length, size_t type) const
+{ 
+  int n = static_cast<int>(register_->getAlphabet()->getSize()); //Note jdutheil 20/01/13: shoudl be generalized in case sattes are not 0:n !
+  RowMatrix<double>* mat = new RowMatrix<double>(n, n);
+  for (int i = 0; i < n; ++i)
+  {
+    for (int j = 0; j < n; ++j)
+    {
+      (*mat)(i, j) = (register_->getType(i, j) == type ? (weights_ ? weights_->getIndex(i, j) : 1.) : 0.);
+    }
+  }
+  return mat;
+}
+
+LabelSubstitutionCount::LabelSubstitutionCount(const Alphabet* alphabet) :
+  AbstractSubstitutionCount(new TotalSubstitutionRegister(alphabet)), label_(alphabet->getSize(), alphabet->getSize())
+{
+  int n = static_cast<int>(register_->getAlphabet()->getSize()); //Note jdutheil 20/01/13: shoudl be generalized in case sattes are not 0:n !
+  double count = 0;
+  for (int i = 0; i < n; ++i) {
+    for (int j = 0; j < n; ++j) {
+      if (i == j) label_(i, j) = 0;
+      else label_(i, j) = ++count;
+    }
+  }
+}			
+
diff --git a/src/Bpp/Phyl/Mapping/NaiveSubstitutionCount.h b/src/Bpp/Phyl/Mapping/NaiveSubstitutionCount.h
new file mode 100644
index 0000000..e258655
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/NaiveSubstitutionCount.h
@@ -0,0 +1,169 @@
+//
+// File: NaiveSubstitutionCount.h
+// Created by: Julien Dutheil
+// Created on: Wed Apr 5 11:08 2006
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _NAIVESUBSTITUTIONCOUNT_H_
+#define _NAIVESUBSTITUTIONCOUNT_H_
+
+#include "WeightedSubstitutionCount.h"
+
+#include <Bpp/Numeric/Matrix/Matrix.h>
+
+namespace bpp
+{
+
+  /**
+   * @brief Naive substitution count.
+   *
+   * This substitution count is defined as follow:
+   * - 0 if @f$i = j at f$,
+   * - 1 if @f$i \neq j @f$.
+   *
+   * Reference (for instance):
+   * Tufféry P, Darlu P.
+   * Exploring a phylogenetic approach for the detection of correlated substitutions in proteins.
+   * Mol Biol Evol. 2000 Nov;17(11):1753-9
+   *
+   * @author Julien Dutheil
+   */
+  class NaiveSubstitutionCount:
+    public AbstractSubstitutionCount,
+    public AbstractWeightedSubstitutionCount
+  {
+  private:
+    bool allowSelf_;
+
+  public:
+    /**
+     * @brief Build a new simple substitution count.
+     *
+     * @param reg A pointer toward a substitution register object which discribes the type of substitutions to map.
+     * @param allowSelf Tells if "self" mutations, from X to X should be counted together with the ones of type X to Y where X and Y are in the same category, if relevent.
+     * The default is "no", to be consistent with other types of substitution counts which account for multiple substitutions, in which case it does not make sense to count "X to X".
+     * @param weights the weights of the counts
+     */
+    NaiveSubstitutionCount(SubstitutionRegister* reg, bool allowSelf = false, const AlphabetIndex2* weights = 0) :
+      AbstractSubstitutionCount(reg),
+      AbstractWeightedSubstitutionCount(weights, true),
+      allowSelf_(allowSelf) {}				
+		
+    virtual ~NaiveSubstitutionCount() {}
+	
+    NaiveSubstitutionCount* clone() const { return new NaiveSubstitutionCount(*this); }
+
+  public:
+    double getNumberOfSubstitutions(int initialState, int finalState, double length, size_t type = 1) const
+    {
+      if (initialState == finalState && !allowSelf_)
+        return 0;
+      else
+        return (register_->getType(initialState, finalState) == type ? (weights_ ? weights_->getIndex(initialState, finalState) : 1.) : 0.);
+    }
+
+    Matrix<double>* getAllNumbersOfSubstitutions(double length, size_t type = 1) const;
+    
+    std::vector<double> getNumberOfSubstitutionsForEachType(int initialState, int finalState, double length) const
+    {
+      std::vector<double> v(getNumberOfSubstitutionTypes());
+      for (size_t t = 1; t <= getNumberOfSubstitutionTypes(); ++t) {
+        v[t - 1] = getNumberOfSubstitutions(initialState, finalState, length, t);
+      }
+      return v;
+    }
+    
+    void setSubstitutionModel(const SubstitutionModel* model) {}
+
+  private:
+    void substitutionRegisterHasChanged() {}
+    void weightsHaveChanged() {}
+
+  };
+
+  /**
+   * @brief Labelling substitution count.
+   *
+   * This substitution count return a distinct number for each possible mutation.
+   * - 0 if @f$i = j at f$,
+   * - @f$a(i,j)@f$ if @f$i \neq j @f$, where 'a' is an index giving a unique value for each combination of i and j.
+   */
+  class LabelSubstitutionCount:
+    public AbstractSubstitutionCount
+  {
+  private:
+    LinearMatrix<double> label_;
+    
+  public:
+    LabelSubstitutionCount(const Alphabet* alphabet);
+
+    virtual ~LabelSubstitutionCount() {}
+
+    LabelSubstitutionCount* clone() const { return new LabelSubstitutionCount(*this); }
+			
+  public:
+    double getNumberOfSubstitutions(int initialState, int finalState, double length, size_t type = 1) const
+    {
+      return label_(initialState, finalState);
+    }
+
+    Matrix<double>* getAllNumbersOfSubstitutions(double length, size_t type = 1) const
+    {
+      return dynamic_cast<Matrix<double>*>(label_.clone());
+    }
+    
+    std::vector<double> getNumberOfSubstitutionsForEachType(int initialState, int finalState, double length) const
+    {
+      std::vector<double> v(1);
+      v[0] = label_(initialState, finalState);
+      return v;
+    }
+
+    void setSubstitutionModel(const SubstitutionModel* model) {}
+
+    void setSubstitutionRegister(SubstitutionRegister* reg) throw (Exception) {
+      throw Exception("OneJumpSubstitutionCount::setSubstitutionRegister. This SubstitutionsCount only works with a TotalSubstitutionRegister.");
+    }
+
+  private:
+    void substitutionRegisterHasChanged() {}
+
+  };
+
+} //end of namespace bpp.
+
+#endif // _SIMPLESUBSTITUTIONCOUNT_H_
+
diff --git a/src/Bpp/Phyl/Mapping/OneJumpSubstitutionCount.cpp b/src/Bpp/Phyl/Mapping/OneJumpSubstitutionCount.cpp
new file mode 100644
index 0000000..403c21c
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/OneJumpSubstitutionCount.cpp
@@ -0,0 +1,54 @@
+//
+// File: OneJumpSubstitutionCount.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Nov 24 17:00 2009
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "OneJumpSubstitutionCount.h"
+
+using namespace bpp;
+
+Matrix<double>* OneJumpSubstitutionCount::getAllNumbersOfSubstitutions(double length, size_t type) const
+{
+  tmp_ = model_->getPij_t(length);
+  size_t n = model_->getNumberOfStates();
+  Matrix<double>* probs = new LinearMatrix<double>(n, n);
+  for (size_t i = 0; i < n; i++) 
+    for (size_t j = 0; j < n; j++)
+      (*probs)(i, j) = (i == j ? 1. - tmp_(i, j) : 1.);
+  return probs;
+}
+
diff --git a/src/Bpp/Phyl/Mapping/OneJumpSubstitutionCount.h b/src/Bpp/Phyl/Mapping/OneJumpSubstitutionCount.h
new file mode 100644
index 0000000..2af4c42
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/OneJumpSubstitutionCount.h
@@ -0,0 +1,122 @@
+//
+// File: OneJumpSubstitutionCount.h
+// Created by: Julien Dutheil
+// Created on: Tue Nov 24 17:00 2009
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _ONEJUMPSUBSTITUTIONCOUNT_H_
+#define _ONEJUMPSUBSTITUTIONCOUNT_H_
+
+#include "SubstitutionCount.h"
+#include "../Model/SubstitutionModel.h"
+
+namespace bpp
+{
+
+/**
+ * @brief Computes the probability that at least one jump occured on a branch, given the initial and final state.
+ *
+ * This probability is defined as
+ * @f[
+ * p_{x,y}(l) = \left\{\begin{array}{ll}1 & \mathrm{if} x \neq y \\ 1 - \exp{\left(Q \cdot t\right)}_{x,y} & \mathrm{otherwise.}\end{array}\right.
+ * @f]
+ *
+ * @author Julien Dutheil
+ */
+class OneJumpSubstitutionCount:
+  public AbstractSubstitutionCount
+{
+	private:
+		const SubstitutionModel* model_;
+		mutable RowMatrix<double> tmp_;
+	
+	public:
+		OneJumpSubstitutionCount(const SubstitutionModel* model) :
+      AbstractSubstitutionCount(new TotalSubstitutionRegister(model->getAlphabet())),
+      model_(model), tmp_() {}
+		
+    OneJumpSubstitutionCount(const OneJumpSubstitutionCount& ojsc) :
+      AbstractSubstitutionCount(ojsc),
+      model_(ojsc.model_), tmp_(ojsc.tmp_) {}
+				
+    OneJumpSubstitutionCount& operator=(const OneJumpSubstitutionCount& ojsc)
+    {
+      AbstractSubstitutionCount::operator=(ojsc),
+      model_    = ojsc.model_;
+      tmp_      = ojsc.tmp_;
+      return *this;
+    }
+				
+		virtual ~OneJumpSubstitutionCount() {}
+		
+    virtual OneJumpSubstitutionCount* clone() const { return new OneJumpSubstitutionCount(*this); }
+
+	public:
+		double getNumberOfSubstitutions(int initialState, int finalState, double length, size_t type = 1) const
+    {
+      if (finalState != initialState) return 1.;
+      else return 1. - model_->Pij_t(initialState, finalState, length);
+    }
+
+    Matrix<double>* getAllNumbersOfSubstitutions(double length, size_t type = 1) const;
+    
+    std::vector<double> getNumberOfSubstitutionsForEachType(int initialState, int finalState, double length) const
+    {
+      std::vector<double> v(0);
+      v[0] = getNumberOfSubstitutions(initialState, finalState, length, 0);
+      return v;
+    }
+    
+    void setSubstitutionModel(const SubstitutionModel* model) { model_ = model; }
+
+  /*
+   *@param reg pointer to a SubstitutionRegister
+   *
+   */
+        
+    void setSubstitutionRegister(SubstitutionRegister* reg) throw (Exception) {
+      throw Exception("OneJumpSubstitutionCount::setSubstitutionRegister. This SubstitutionsCount only works with a TotalSubstitutionRegister.");
+    }
+
+  private:
+    void substitutionRegisterHasChanged() {}
+
+};
+
+} //end of namespace bpp.
+
+#endif //_ONEJUMPSUBSTITUTIONCOUNT_H_
+
diff --git a/src/Bpp/Phyl/Mapping/ProbabilisticSubstitutionMapping.cpp b/src/Bpp/Phyl/Mapping/ProbabilisticSubstitutionMapping.cpp
new file mode 100644
index 0000000..5c6144b
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/ProbabilisticSubstitutionMapping.cpp
@@ -0,0 +1,66 @@
+//
+// File: ProbabilisticSubstitutionMapping.cpp
+// Created by: Julien Dutheil
+// Created on: Wed Apr 5 10:47 2006
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "ProbabilisticSubstitutionMapping.h"
+
+using namespace bpp;
+
+void ProbabilisticSubstitutionMapping::setTree(const Tree& tree)
+{
+  AbstractSubstitutionMapping::setTree(tree);
+  for (size_t i = 0; i < getNumberOfSites(); i++) {
+    mapping_[i].resize(getNumberOfBranches());
+    for (size_t j = 0; j < getNumberOfBranches(); j++) {
+      mapping_[i][j].resize(1);
+    }
+  }
+}
+
+void ProbabilisticSubstitutionMapping::setNumberOfSites(size_t numberOfSites)
+{
+  AbstractSubstitutionMapping::setNumberOfSites(numberOfSites);
+  mapping_.resize(numberOfSites);
+  for (size_t i = 0; i < numberOfSites; i++) {
+    mapping_[i].resize(getNumberOfBranches());
+    for (size_t j = 0; j < getNumberOfBranches(); j++) {
+      mapping_[i][j].resize(getNumberOfSubstitutionTypes());
+    }
+  }
+}
+ 
diff --git a/src/Bpp/Phyl/Mapping/ProbabilisticSubstitutionMapping.h b/src/Bpp/Phyl/Mapping/ProbabilisticSubstitutionMapping.h
new file mode 100644
index 0000000..94b85c3
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/ProbabilisticSubstitutionMapping.h
@@ -0,0 +1,189 @@
+//
+// File: ProbabilisticSubstitutionMapping.h
+// Created by: Julien Dutheil
+// Created on: Wed Apr 5 10:47 2006
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _PROBABILISTICSUBSTITUTIONMAPPING_H_
+#define _PROBABILISTICSUBSTITUTIONMAPPING_H_
+
+#include "SubstitutionMapping.h"
+#include "SubstitutionCount.h"
+#include "../TreeExceptions.h"
+
+#include <Bpp/Text/TextTools.h>
+
+// From the STL:
+#include <vector>
+
+namespace bpp
+{
+
+/**
+ * @brief Data storage class for probabilistic substitution mappings.
+ *
+ * A 'probabilistic' mapping contains an single value for each branch and each site.
+ * This number can be an average number of substitutions, optionally waited, or a probability of observing a certain number of substitutions.
+ * Probabilistic was coined there by opposition to the'stochastic' mapping, where a path (number of susbstitutions + there position along the branch)
+ * is available for each branch and site. The probabilistic mapping can however be extended to contain a matrix will all types of substitutions, instead of their total number.
+ */
+class ProbabilisticSubstitutionMapping:
+  public AbstractSubstitutionMapping
+{
+  private:
+    const SubstitutionCount* substitutionCount_;
+    /**
+     * @brief Substitution numbers storage.
+     *
+     * Numbers are stored by sites.
+     */
+    std::vector< std::vector< std::vector<double> > > mapping_;
+  
+  public:
+    
+    /**
+     * @brief Build a new ProbabilisticSubstitutionMapping object.
+     *
+     * @param tree The tree object to use. It will be cloned for internal use.
+     * @param sc A pointer toward the substitution count object that has been used for the mapping, if any.
+     * This object allows to get the substitution types description, if there are several. If set to 0, then
+     * the mapping will be considered as having only one type of substitution mapped.
+     * @param numberOfSites The number of sites to map.
+     */
+    ProbabilisticSubstitutionMapping(const Tree& tree, const SubstitutionCount* sc, size_t numberOfSites) :
+      AbstractSubstitutionMapping(tree), substitutionCount_(sc), mapping_(0)
+    {
+      setNumberOfSites(numberOfSites);
+    }
+
+    /**
+     * @brief Build a new ProbabilisticSubstitutionMapping object.
+     *
+     * @param tree The tree object to use. It will be cloned for internal use.
+     */
+    ProbabilisticSubstitutionMapping(const Tree& tree) :
+      AbstractSubstitutionMapping(tree), substitutionCount_(0), mapping_(0)
+    {}
+    
+
+    ProbabilisticSubstitutionMapping* clone() const { return new ProbabilisticSubstitutionMapping(*this); }
+
+    ProbabilisticSubstitutionMapping(const ProbabilisticSubstitutionMapping& psm):
+      AbstractSubstitutionMapping(psm), substitutionCount_(psm.substitutionCount_), mapping_(psm.mapping_)
+    {}
+
+    ProbabilisticSubstitutionMapping& operator=(const ProbabilisticSubstitutionMapping& psm)
+    {
+      AbstractSubstitutionMapping::operator=(psm);
+      substitutionCount_ = psm.substitutionCount_;
+      mapping_           = psm.mapping_;
+      return *this;
+    }
+
+    virtual ~ProbabilisticSubstitutionMapping() {}
+
+  public:
+
+    size_t getNumberOfSubstitutionTypes() const
+    {
+      if (!substitutionCount_) return 1;
+      return substitutionCount_->getNumberOfSubstitutionTypes();
+    }
+     
+    virtual double getNumberOfSubstitutions(int nodeId, size_t siteIndex, size_t type) const
+    {
+      return mapping_[siteIndex][getNodeIndex(nodeId)][type];
+    }
+    
+    virtual std::vector<double> getNumberOfSubstitutions(int nodeId, size_t siteIndex) const
+    {
+      return mapping_[siteIndex][getNodeIndex(nodeId)];
+    }
+    
+    /**
+     * @brief (Re)-set the phylogenetic tree associated to this mapping.
+     *
+     * @param tree The new tree.
+     */
+    virtual void setTree(const Tree& tree);
+
+    virtual void setNumberOfSites(size_t numberOfSites);
+    
+    /**
+     * @brief Direct access to substitution numbers.
+     *
+     * @warning No index checking is performed, use with care!
+     */
+    virtual double& operator()(size_t nodeIndex, size_t siteIndex, size_t type)
+    {
+      return mapping_[siteIndex][nodeIndex][type];
+    }
+
+    /**
+     * @brief Direct access to substitution numbers.
+     *
+     * @warning No index checking is performed, use with care!
+     */
+    virtual const double& operator()(size_t nodeIndex, size_t siteIndex, size_t type) const
+    {
+      return mapping_[siteIndex][nodeIndex][type];
+    }
+     
+    /**
+     * @brief Direct access to substitution numbers.
+     *
+     * @warning No index checking is performed, use with care!
+     */
+    std::vector< std::vector<double> >& operator[](size_t siteIndex)
+    {
+      return mapping_[siteIndex];
+    }
+
+    /**
+     * @brief Direct access to substitution numbers.
+     *
+     * @warning No index checking is performed, use with care!
+     */
+    const std::vector< std::vector<double> >& operator[](size_t siteIndex) const
+    {
+      return mapping_[siteIndex];
+    }
+};
+
+} //end of namespace bpp.
+
+#endif //_PROBABILISTICSUBSTITUTIONMAPPING_H_
+
diff --git a/src/Bpp/Phyl/Mapping/SubstitutionCount.h b/src/Bpp/Phyl/Mapping/SubstitutionCount.h
new file mode 100644
index 0000000..468ec63
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/SubstitutionCount.h
@@ -0,0 +1,220 @@
+//
+// File: SubstitutionCount.h
+// Created by: Julien Dutheil
+// Created on: Wed Apr 5 11:08 2006
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _SUBSTITUTIONCOUNT_H_
+#define _SUBSTITUTIONCOUNT_H_
+
+#include "SubstitutionRegister.h"
+#include "../Model/SubstitutionModel.h"
+
+#include <Bpp/Numeric/Matrix/Matrix.h>
+
+//From the STL:
+#include <vector>
+
+namespace bpp
+{
+
+  /**
+   * @brief The SubstitutionsCount interface.
+   *
+   * Provide a method to compute the @f$n_{x,y}(t)@f$ function,
+   * namely the number of substitutions on a branch of length @f$t at f$, with initial state @f$x at f$ and final state @f$y at f$.
+   * 
+   * The new implementation offers to perform several counts simultaneously, distinguishing between different types of substitutions. Therefore substitution count object takes as input a SubstitutionRegister, which describes all
+   * types of substitutions and associate them with an index. All counts can be retrieved in one go as a vector, the type serving as an indice.
+   *
+   * @author Julien Dutheil
+   *
+   * See:
+   * Dutheil J, Pupko T, Jean-Marie A, Galtier N.
+   * A model-based approach for detecting coevolving positions in a molecule.
+   * Mol Biol Evol. 2005 Sep;22(9):1919-28. Epub 2005 Jun 8.
+   */
+  class SubstitutionCount:
+    public virtual Clonable
+  {
+  public:
+    SubstitutionCount() {}
+    virtual ~SubstitutionCount() {}
+    virtual SubstitutionCount* clone() const = 0;
+	
+  public:
+    /**
+     * @return Tell if a substitution register has been attached to this class.
+     */
+    virtual bool hasSubstitutionRegister() const = 0;
+
+    /**
+     * @return The SubstitutionRegister object associated to this instance. The register contains the description of the various substitutions types that are mapped.
+     */
+    virtual const SubstitutionRegister* getSubstitutionRegister() const = 0;
+
+    /**
+     * @return The SubstitutionRegister object associated to this instance. The register contains the description of the various substitutions types that are mapped.
+     */
+    virtual SubstitutionRegister* getSubstitutionRegister() = 0;
+
+    /**
+     * @param reg The new SubstitutionRegister object to be associated to this instance.
+     * The register contains the description of the various substitutions types that are mapped.
+     */
+    virtual void setSubstitutionRegister(SubstitutionRegister* reg) = 0;
+
+    /**
+     * @brief Short cut function, equivalent to getSubstitutionRegister().getNumberOfSubstitutionTypes().
+     *
+     * @return The number of substitution types supported by this instance.
+     */
+    virtual size_t getNumberOfSubstitutionTypes() const { return getSubstitutionRegister()->getNumberOfSubstitutionTypes(); }
+
+    /**
+     * @brief Short cut function, equivalent to getSubstitutionRegister()->getAlphabet().
+     *
+     * @return The alphabet associated to this substitution count.
+     */
+    virtual const Alphabet* getAlphabet() const { return getSubstitutionRegister()->getAlphabet(); }
+
+    /**
+     * @brief Short cut function, equivalent to getSubstitutionRegister()->getAlphabet()->getSize().
+     *
+     * @return The number of states in the model/alphabet.
+     */
+    virtual size_t getNumberOfStates() const { return getSubstitutionRegister()->getAlphabet()->getSize(); }
+
+
+    /**
+     * @brief Get the number of susbstitutions on a branch, given the initial and final states, and the branch length.
+     *
+     * @param initialState The initial state.
+     * @param finalState   The final state.
+     * @param length       The length of the branch.
+     * @param type         The type of substitution to count.
+     * @return The number of substitutions on a branch of specified length and
+     * according to initial and final states.
+     */
+    virtual double getNumberOfSubstitutions(int initialState, int finalState, double length, size_t type) const = 0;
+		
+    /**
+     * @brief Get the numbers of susbstitutions on a branch, for each initial and final states, and given the branch length.
+     *
+     * @param length       The length of the branch.
+     * @param type         The type of susbstitution to count.
+     * @return A matrix with all numbers of substitutions for each initial and final states.
+     */
+    virtual Matrix<double>* getAllNumbersOfSubstitutions(double length, size_t type) const = 0;
+
+    /**
+     * @brief Get the numbers of susbstitutions on a branch for all types, for an initial and final states, given the branch length.
+     *
+     * @param initialState The initial state.
+     * @param finalState   The final state.
+     * @param length       The length of the branch.
+     * @return A matrix with all numbers of substitutions for each initial and final states.
+     */
+    virtual std::vector<double> getNumberOfSubstitutionsForEachType(int initialState, int finalState, double length) const = 0;
+
+    /**
+     * @brief Set the substitution model associated with this count, if relevent.
+     *
+     * @param model The substitution model to use with this count.
+     */
+    virtual void setSubstitutionModel(const SubstitutionModel* model) = 0;
+  };
+
+  /**
+   * @brief Basic implementation of the the SubstitutionCount interface.
+   *
+   * This partial implementation deals with the SubstitutionRegister gestion, by maintaining a pointer.
+   */
+  class AbstractSubstitutionCount:
+    public virtual SubstitutionCount
+  {
+  protected:
+    SubstitutionRegister* register_;
+
+  public:
+    AbstractSubstitutionCount(SubstitutionRegister* reg):
+      register_(reg)
+    {}
+
+    AbstractSubstitutionCount(const AbstractSubstitutionCount& asc):
+      register_(dynamic_cast<SubstitutionRegister*>(register_->clone()))
+    {}
+
+    AbstractSubstitutionCount& operator=(const AbstractSubstitutionCount& asc) {
+      if (register_)
+        delete register_;
+      register_ = dynamic_cast<SubstitutionRegister*>(register_->clone());
+      return *this;
+    }
+
+    ~AbstractSubstitutionCount() {
+      if (register_)
+        delete register_;
+    }
+
+  public:
+    bool hasSubstitutionRegister() const { return (register_ != 0); }
+
+    /*
+     *@brief attribution of a SubstitutionRegister
+     *
+     *@param reg pointer to a SubstitutionRegister
+     *
+     */
+    
+    void setSubstitutionRegister(SubstitutionRegister* reg) {
+      if (register_) delete register_;
+      register_ = reg;
+      substitutionRegisterHasChanged();
+    }
+
+    const SubstitutionRegister* getSubstitutionRegister() const { return register_; }
+    
+    SubstitutionRegister* getSubstitutionRegister() { return register_; }
+
+  protected:
+    virtual void substitutionRegisterHasChanged() = 0;
+  };
+
+} //end of namespace bpp.
+
+#endif //_SUBSTITUTIONCOUNT_H_
+
diff --git a/src/Bpp/Phyl/Mapping/SubstitutionMapping.h b/src/Bpp/Phyl/Mapping/SubstitutionMapping.h
new file mode 100644
index 0000000..c983768
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/SubstitutionMapping.h
@@ -0,0 +1,254 @@
+//
+// File: SubstitutionMapping.h
+// Created by: Julien Dutheil
+// Created on: Wed Apr 5 09:51 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _SUBSTITUTIONMAPPING_H_
+#define _SUBSTITUTIONMAPPING_H_
+
+#include "../Tree.h"
+#include "../TreeTemplate.h"
+
+#include <Bpp/Clonable.h>
+
+//From the STL:
+#include <vector>
+#include <memory>
+
+namespace bpp
+{
+
+/**
+ * @brief General interface for storing mapping data.
+ *
+ * There are several kinds of mapping:
+ * - Exact mapping, storing the positions of each substitution onto each branch,
+ * - Probabilistic mapping, storing the number of substitutions onto each branch.
+ *
+ * Since only probabilistic substitution mapping is implemented for now, the basal 
+ * interface only contains a few methods.
+ * More methods are expected to be added later.
+ */
+class SubstitutionMapping:
+  public virtual Clonable
+{
+
+  public:
+    SubstitutionMapping() {}
+    virtual ~SubstitutionMapping() {}
+
+#ifndef NO_VIRTUAL_COV
+    SubstitutionMapping* clone() const = 0;
+#endif
+
+  public:
+    
+    /**
+     * @return Get the phylogenetic tree associated to this mapping.
+     */
+    virtual const Tree& getTree() const = 0;
+    
+    /**
+     * @return True is the map is empty, that is, if no tree is associated to the map yet.
+     */
+    virtual bool isEmpty() const = 0;
+
+    /**
+     * @return The number of sites mapped.
+     */
+    virtual size_t getNumberOfSites() const = 0;
+    
+    /**
+     * @return The number of branches mapped.
+     */
+    virtual size_t getNumberOfBranches() const = 0;
+    
+    /**
+     * @return The number of distinct types of substitutions mapped.
+     */
+    virtual size_t getNumberOfSubstitutionTypes() const = 0;
+    
+    /**
+     * @param index The site index.
+     * @return The site position corresponding to the index.
+     */
+    virtual int getSitePosition(size_t index) const = 0;
+    
+    /**
+     * @return A vector with all tree branch lengths.
+     */
+    virtual std::vector<double> getBranchLengths() const = 0;
+    
+    /**
+     * @param nodeId An id of the node to look for in the map.
+     * @return The mapping index for the specified node id.
+     */
+    virtual size_t getNodeIndex(int nodeId) const throw (NodeNotFoundException) = 0;
+
+    /**
+     * @brief Set the position of a given site.
+     *
+     * @warning No index checking is performed, use with care!
+     * @param index The site index.
+     * @param position The position of the site.
+     */
+    virtual void setSitePosition(size_t index, int position) = 0;
+
+    virtual double& operator()(size_t nodeIndex, size_t siteIndex, size_t type) = 0;
+    virtual const double& operator()(size_t nodeIndex, size_t siteIndex, size_t type) const = 0;
+};
+
+
+
+
+
+
+/**
+ * @brief Partial implementation of the substitution mapping interface.
+ *
+ * This implementation copies the input tree in a TreeTemplate<Node> object.
+ */
+class AbstractSubstitutionMapping:
+  public SubstitutionMapping
+{
+  private:
+    std::auto_ptr<const TreeTemplate<Node> > tree_;
+    std::vector<int> sitesPositions_;
+    std::vector<const Node *> nodes_;
+    size_t nbSites_;
+    size_t nbBranches_;
+
+  public:
+    AbstractSubstitutionMapping() : tree_(0), sitesPositions_(), nodes_(), nbSites_(0), nbBranches_(0) {}
+
+    AbstractSubstitutionMapping(const Tree& tree) : tree_(new TreeTemplate<Node>(tree)), sitesPositions_(), nodes_(), nbSites_(0), nbBranches_(0)
+    {
+      nodes_ = tree_->getNodes();
+      nodes_.pop_back(); // remove root node.
+      nbBranches_ = nodes_.size();
+    }
+
+    AbstractSubstitutionMapping(const AbstractSubstitutionMapping& absm):
+      tree_(dynamic_cast<const TreeTemplate<Node>*>(absm.tree_->clone())),
+      sitesPositions_(absm.sitesPositions_),
+      nodes_(),
+      nbSites_(absm.nbSites_),
+      nbBranches_(absm.nbBranches_)
+    {
+      nodes_ = tree_->getNodes();
+      nodes_.pop_back(); // remove root node.
+    }
+
+    AbstractSubstitutionMapping& operator=(const AbstractSubstitutionMapping& absm)
+    {
+      tree_.reset(dynamic_cast<const TreeTemplate<Node>*>(absm.tree_->clone()));
+      sitesPositions_ = absm.sitesPositions_;
+      nbSites_        = absm.nbSites_;
+      nbBranches_     = absm.nbBranches_;
+      nodes_          = tree_->getNodes();
+      nodes_.pop_back(); // remove root node.
+      return *this;
+    }
+
+    virtual ~AbstractSubstitutionMapping() {}
+
+  public:
+
+    bool isEmpty() const { return tree_.get() == 0; }
+
+		const	TreeTemplate<Node>& getTree() const throw (Exception)
+    {
+      if (isEmpty()) throw Exception("AbstractSubstitutionMapping::getSitePosition. No tree is assigned to this map yet.");
+      return *tree_.get();
+    }
+
+    void setTree(const Tree& tree)
+    {
+      tree_.reset(new TreeTemplate<Node>(tree));
+      nodes_ = tree_->getNodes();
+      nodes_.pop_back(); // remove root node.
+      nbBranches_ = nodes_.size();
+    }
+ 
+    int getSitePosition(size_t index) const throw (Exception)
+    {
+      if (isEmpty()) throw Exception("AbstractSubstitutionMapping::getSitePosition. No tree is assigned to this map yet.");
+      return sitesPositions_[index];
+    }
+    
+    void setSitePosition(size_t index, int position) throw (Exception)
+    {
+      if (isEmpty()) throw Exception("AbstractSubstitutionMapping::setSitePosition. No tree is assigned to this map yet.");
+      sitesPositions_[index] = position;
+    }
+		
+    size_t getNumberOfSites() const { return nbSites_; }
+
+    size_t getNumberOfBranches() const { return nbBranches_; }
+    
+    virtual const Node* getNode(size_t nodeIndex) const { return nodes_[nodeIndex]; }
+
+    virtual void setNumberOfSites(size_t numberOfSites)
+    {
+      nbSites_ = numberOfSites;
+      sitesPositions_.resize(numberOfSites);
+      for (size_t i = 0; i < numberOfSites; i++)
+        sitesPositions_[i] = static_cast<int>(i + 1); //Default: all sizes numbered for 1 to n.
+    }
+
+    virtual std::vector<double> getBranchLengths() const
+    {
+      std::vector<double> brLen(nbBranches_);
+      for (size_t i = 0; i < nbBranches_; i++)
+        brLen[i] = nodes_[i]->getDistanceToFather();
+      return brLen;
+    }
+
+    virtual size_t getNodeIndex(int nodeId) const throw (NodeNotFoundException)
+    {
+      for (size_t i = 0; i < nbBranches_; i++)
+        if(nodes_[i]->getId() == nodeId) return i;
+      throw NodeNotFoundException("ProbabilisticSubstitutionMapping::getNodeIndex(nodeId).", TextTools::toString(nodeId));
+    }
+
+
+};
+
+} //end of namespace bpp.
+
+#endif //_SUBSTITUTIONMAPPING_H_
+
diff --git a/src/Bpp/Phyl/Mapping/SubstitutionMappingTools.cpp b/src/Bpp/Phyl/Mapping/SubstitutionMappingTools.cpp
new file mode 100644
index 0000000..6e5f192
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/SubstitutionMappingTools.cpp
@@ -0,0 +1,1011 @@
+//
+// File: SubstitutionMappingTools.cpp
+// Created by: Julien Dutheil
+// Created on: Wed Apr 5 13:04 2006
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "SubstitutionMappingTools.h"
+#include "../Likelihood/DRTreeLikelihoodTools.h"
+#include "../Likelihood/MarginalAncestralStateReconstruction.h"
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Numeric/DataTable.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iomanip>
+
+using namespace std;
+
+/******************************************************************************/
+
+ProbabilisticSubstitutionMapping* SubstitutionMappingTools::computeSubstitutionVectors(
+  const DRTreeLikelihood& drtl,
+  SubstitutionCount& substitutionCount,
+  bool verbose) throw (Exception)
+{
+  //Preamble:
+  if (!drtl.isInitialized()) throw Exception("SubstitutionMappingTools::computeSubstitutionVectors(). Likelihood object is not initialized.");
+                                   
+  //A few variables we'll need:
+  
+  const TreeTemplate<Node> tree(drtl.getTree());
+  const SiteContainer*    sequences = drtl.getData();
+  const DiscreteDistribution* rDist = drtl.getRateDistribution();
+    
+  size_t nbSites         = sequences->getNumberOfSites();
+  size_t nbDistinctSites = drtl.getLikelihoodData()->getNumberOfDistinctSites();
+  size_t nbStates        = sequences->getAlphabet()->getSize();
+  size_t nbClasses       = rDist->getNumberOfCategories();
+  size_t nbTypes         = substitutionCount.getNumberOfSubstitutionTypes();
+  vector<const Node*> nodes    = tree.getNodes();
+  const vector<size_t>* rootPatternLinks
+                               = &drtl.getLikelihoodData()->getRootArrayPositions();
+  nodes.pop_back(); // Remove root node.
+  size_t nbNodes         = nodes.size();
+  
+  // We create a new ProbabilisticSubstitutionMapping object:
+  ProbabilisticSubstitutionMapping* substitutions = new ProbabilisticSubstitutionMapping(tree, &substitutionCount, nbSites);
+                                   
+  // Store likelihood for each rate for each site:
+  VVVdouble lik;
+  drtl.computeLikelihoodAtNode(tree.getRootId(), lik);
+  Vdouble Lr(nbDistinctSites, 0);
+  Vdouble rcProbs = rDist->getProbabilities();
+  Vdouble rcRates = rDist->getCategories();
+  for (size_t i = 0; i < nbDistinctSites; i++)
+  {
+    VVdouble* lik_i = &lik[i];
+    for (size_t c = 0; c < nbClasses; c++)
+    {
+      Vdouble* lik_i_c = &(*lik_i)[c];
+      double rc = rDist->getProbability(c);
+      for (size_t s = 0; s < nbStates; s++)
+      {
+        Lr[i] += (*lik_i_c)[s] * rc;
+      }
+    }
+  }
+
+  // Compute the number of substitutions for each class and each branch in the tree:
+  if (verbose) ApplicationTools::displayTask("Compute joint node-pairs likelihood", true);
+  
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    //For each node,
+    const Node* currentNode = nodes[l];
+
+    const Node* father = currentNode->getFather();
+
+    double d = currentNode->getDistanceToFather();
+ 
+    if (verbose) ApplicationTools::displayGauge(l, nbNodes-1, '>');
+    VVdouble substitutionsForCurrentNode(nbDistinctSites);
+    for (size_t i = 0; i < nbDistinctSites; ++i)
+      substitutionsForCurrentNode[i].resize(nbTypes);
+
+    // Now we've got to compute likelihoods in a smart manner... ;)
+    VVVdouble likelihoodsFatherConstantPart(nbDistinctSites);
+    for (size_t i = 0; i < nbDistinctSites; i++)
+    {
+      VVdouble* likelihoodsFatherConstantPart_i = &likelihoodsFatherConstantPart[i];
+      likelihoodsFatherConstantPart_i->resize(nbClasses);
+      for (size_t c = 0; c < nbClasses; c++)
+      {
+        Vdouble* likelihoodsFatherConstantPart_i_c = &(*likelihoodsFatherConstantPart_i)[c];
+        likelihoodsFatherConstantPart_i_c->resize(nbStates);
+        double rc = rDist->getProbability(c);
+        for (size_t s = 0; s < nbStates; s++)
+        {
+          //(* likelihoodsFatherConstantPart_i_c)[s] = rc * model->freq(s);
+          //freq is already accounted in the array
+          (* likelihoodsFatherConstantPart_i_c)[s] = rc;
+        }
+      }
+    }
+    
+    // First, what will remain constant:
+    size_t nbSons =  father->getNumberOfSons();
+    for (size_t n = 0; n < nbSons; n++)
+    {
+      const Node* currentSon = father->getSon(n);
+      if (currentSon->getId() != currentNode->getId())
+      {
+        const VVVdouble* likelihoodsFather_son = &drtl.getLikelihoodData()->getLikelihoodArray(father->getId(), currentSon->getId());
+
+        //Now iterate over all site partitions:
+        auto_ptr<TreeLikelihood::ConstBranchModelIterator> mit(drtl.getNewBranchModelIterator(currentSon->getId()));
+        VVVdouble pxy;
+        bool first;
+        while (mit->hasNext())
+        {
+          TreeLikelihood::ConstBranchModelDescription* bmd = mit->next();
+          auto_ptr<TreeLikelihood::SiteIterator> sit(bmd->getNewSiteIterator());
+          first = true;
+          while (sit->hasNext())
+          {
+            size_t i = sit->next();
+            //We retrieve the transition probabilities for this site partition:
+            if (first)
+            {
+              pxy = drtl.getTransitionProbabilitiesPerRateClass(currentSon->getId(), i);
+              first = false;
+            }
+            const VVdouble* likelihoodsFather_son_i = &(*likelihoodsFather_son)[i];
+            VVdouble* likelihoodsFatherConstantPart_i = &likelihoodsFatherConstantPart[i];
+            for (size_t c = 0; c < nbClasses; c++)
+            {
+              const Vdouble* likelihoodsFather_son_i_c = &(*likelihoodsFather_son_i)[c];
+              Vdouble* likelihoodsFatherConstantPart_i_c = &(*likelihoodsFatherConstantPart_i)[c];
+              VVdouble* pxy_c = &pxy[c];
+              for (size_t x = 0; x < nbStates; x++)
+              {
+                Vdouble* pxy_c_x = &(*pxy_c)[x];
+                double likelihood = 0.;
+                for (size_t y = 0; y < nbStates; y++)
+                {
+                  likelihood += (*pxy_c_x)[y] * (*likelihoodsFather_son_i_c)[y];
+                }
+                (*likelihoodsFatherConstantPart_i_c)[x] *= likelihood;
+              }
+            }
+          }
+        }      
+      }
+    }
+    if (father->hasFather())
+    {
+      const Node* currentSon = father->getFather();
+      const VVVdouble* likelihoodsFather_son = &drtl.getLikelihoodData()->getLikelihoodArray(father->getId(), currentSon->getId());
+      //Now iterate over all site partitions:
+      auto_ptr<TreeLikelihood::ConstBranchModelIterator> mit(drtl.getNewBranchModelIterator(father->getId()));
+      VVVdouble pxy;
+      bool first;
+      while (mit->hasNext())
+      {
+        TreeLikelihood::ConstBranchModelDescription* bmd = mit->next();
+        auto_ptr<TreeLikelihood::SiteIterator> sit(bmd->getNewSiteIterator());
+        first = true;
+        while (sit->hasNext())
+        {
+          size_t i = sit->next();
+          //We retrieve the transition probabilities for this site partition:
+          if (first)
+          {
+            pxy = drtl.getTransitionProbabilitiesPerRateClass(father->getId(), i);
+            first = false;
+          }
+          const VVdouble* likelihoodsFather_son_i = &(*likelihoodsFather_son)[i];
+          VVdouble* likelihoodsFatherConstantPart_i = &likelihoodsFatherConstantPart[i];
+          for (size_t c = 0; c < nbClasses; c++)
+          {
+            const Vdouble* likelihoodsFather_son_i_c = &(*likelihoodsFather_son_i)[c];
+            Vdouble* likelihoodsFatherConstantPart_i_c = &(*likelihoodsFatherConstantPart_i)[c];
+            VVdouble* pxy_c = &pxy[c]; 
+            for (size_t x = 0; x < nbStates; x++)
+            {
+              double likelihood = 0.;
+              for (size_t y = 0; y < nbStates; y++)
+              {
+                Vdouble* pxy_c_x = &(*pxy_c)[y];
+                likelihood += (*pxy_c_x)[x] * (*likelihoodsFather_son_i_c)[y];
+              }
+              (*likelihoodsFatherConstantPart_i_c)[x] *= likelihood;
+            }
+          }
+        }
+      }      
+    }
+    else
+    {
+      //Account for root frequencies:
+      for (size_t i = 0; i < nbDistinctSites; i++)
+      {
+        vector<double> freqs = drtl.getRootFrequencies(i);
+        VVdouble* likelihoodsFatherConstantPart_i = &likelihoodsFatherConstantPart[i];
+        for (size_t c = 0; c < nbClasses; c++)
+        {
+          Vdouble* likelihoodsFatherConstantPart_i_c = &(*likelihoodsFatherConstantPart_i)[c];
+          for (size_t x = 0; x < nbStates; x++)
+          {
+            (*likelihoodsFatherConstantPart_i_c)[x] *= freqs[x];
+          }
+        }
+      }      
+    }
+
+    // Then, we deal with the node of interest.
+    // We first average uppon 'y' to save computations, and then uppon 'x'.
+    // ('y' is the state at 'node' and 'x' the state at 'father'.)
+
+    //Iterate over all site partitions:
+		const VVVdouble* likelihoodsFather_node = &(drtl.getLikelihoodData()->getLikelihoodArray(father->getId(), currentNode->getId()));
+    auto_ptr<TreeLikelihood::ConstBranchModelIterator> mit(drtl.getNewBranchModelIterator(currentNode->getId()));
+    VVVdouble pxy;
+    bool first;
+    while (mit->hasNext())
+    {
+      TreeLikelihood::ConstBranchModelDescription* bmd = mit->next();
+      substitutionCount.setSubstitutionModel(bmd->getModel());
+      //compute all nxy first:
+      VVVVdouble nxy(nbClasses);
+      for (size_t c = 0; c < nbClasses; ++c)
+      {
+        VVVdouble* nxy_c = &nxy[c];
+        double rc = rcRates[c];
+        nxy_c->resize(nbTypes);
+        for (size_t t = 0; t < nbTypes; ++t)
+        {
+          VVdouble* nxy_c_t = &(*nxy_c)[t];
+          Matrix<double>* nijt = substitutionCount.getAllNumbersOfSubstitutions(d * rc, t + 1);
+          nxy_c_t->resize(nbStates);
+          for (size_t x = 0; x < nbStates; ++x)
+          {
+            Vdouble* nxy_c_t_x = &(*nxy_c_t)[x];
+            nxy_c_t_x->resize(nbStates);
+            for (size_t y = 0; y < nbStates; ++y)
+              (*nxy_c_t_x)[y] = (*nijt)(x, y);
+          }
+          delete nijt;
+        }
+      }
+
+      //Now loop over sites:
+      auto_ptr<TreeLikelihood::SiteIterator> sit(bmd->getNewSiteIterator());
+      first = true;
+      while (sit->hasNext())
+      {
+        size_t i = sit->next();
+        //We retrieve the transition probabilities and substitution counts for this site partition:
+        if (first)
+        {
+          pxy = drtl.getTransitionProbabilitiesPerRateClass(currentNode->getId(), i);  
+          first = false;
+        }
+        const VVdouble* likelihoodsFather_node_i = &(*likelihoodsFather_node)[i];
+        VVdouble* likelihoodsFatherConstantPart_i = &likelihoodsFatherConstantPart[i];
+        for (size_t c = 0; c < nbClasses; ++c)
+        {
+          const Vdouble* likelihoodsFather_node_i_c = &(*likelihoodsFather_node_i)[c];
+          Vdouble* likelihoodsFatherConstantPart_i_c = &(*likelihoodsFatherConstantPart_i)[c];
+          const VVdouble* pxy_c = &pxy[c];
+          VVVdouble* nxy_c = &nxy[c];
+          for (size_t x = 0; x < nbStates; ++x)
+          {
+            double* likelihoodsFatherConstantPart_i_c_x = &(*likelihoodsFatherConstantPart_i_c)[x];
+            const Vdouble* pxy_c_x = &(*pxy_c)[x];
+            for (size_t y = 0; y < nbStates; ++y)
+            {
+              double likelihood_cxy = (*likelihoodsFatherConstantPart_i_c_x)
+                 *(*pxy_c_x)[y]
+                 *(*likelihoodsFather_node_i_c)[y];
+
+              for (size_t t = 0; t < nbTypes; ++t) {
+                // Now the vector computation:
+                substitutionsForCurrentNode[i][t] += likelihood_cxy * (*nxy_c)[t][x][y];
+                //                                   <------------>   <--------------->
+                // Posterior probability                   |                 | 
+                // for site i and rate class c *           |                 |
+                // likelihood for this site----------------+                 |
+                //                                                           |
+                //Substitution function for site i and rate class c----------+
+              }
+            }          
+          }
+        }
+      }
+    }
+    
+    //Now we just have to copy the substitutions into the result vector:
+    for (size_t i = 0; i < nbSites; ++i)
+      for (size_t t = 0; t < nbTypes; ++t)
+        (*substitutions)(l, i, t) = substitutionsForCurrentNode[(* rootPatternLinks)[i]][t] / Lr[(* rootPatternLinks)[i]];
+  }
+  if (verbose)
+  {
+    if (ApplicationTools::message) *ApplicationTools::message << " ";
+    ApplicationTools::displayTaskDone();
+  }
+  return substitutions;
+}
+
+/**************************************************************************************************/
+
+ProbabilisticSubstitutionMapping* SubstitutionMappingTools::computeSubstitutionVectorsNoAveraging(
+  const DRTreeLikelihood& drtl,
+  SubstitutionCount& substitutionCount,
+  bool verbose) throw (Exception)
+{
+  //Preamble:
+  if (!drtl.isInitialized()) throw Exception("SubstitutionMappingTools::computeSubstitutionVectorsNoAveraging(). Likelihood object is not initialized.");
+                                   
+  //A few variables we'll need:
+  const TreeTemplate<Node> tree(drtl.getTree());
+  const SiteContainer*    sequences = drtl.getData();
+  const DiscreteDistribution* rDist = drtl.getRateDistribution();
+    
+  size_t nbSites         = sequences->getNumberOfSites();
+  size_t nbDistinctSites = drtl.getLikelihoodData()->getNumberOfDistinctSites();
+  size_t nbStates        = sequences->getAlphabet()->getSize();
+  size_t nbClasses       = rDist->getNumberOfCategories();
+  size_t nbTypes         = substitutionCount.getNumberOfSubstitutionTypes();
+  vector<const Node *> nodes   = tree.getNodes();
+  const vector<size_t> * rootPatternLinks
+                               = &drtl.getLikelihoodData()->getRootArrayPositions();
+  nodes.pop_back(); // Remove root node.
+  size_t nbNodes = nodes.size();
+  
+  // We create a new ProbabilisticSubstitutionMapping object:
+  ProbabilisticSubstitutionMapping* substitutions = new ProbabilisticSubstitutionMapping(tree, &substitutionCount, nbSites);
+                                   
+  Vdouble rcRates = rDist->getCategories();
+
+  // Compute the number of substitutions for each class and each branch in the tree:
+  if (verbose) ApplicationTools::displayTask("Compute joint node-pairs likelihood", true);
+  
+  for (size_t l = 0; l < nbNodes; ++l)
+  {
+    // For each node,
+    const Node* currentNode = nodes[l];
+
+    const Node* father = currentNode->getFather();
+
+    double d = currentNode->getDistanceToFather();
+    
+    if (verbose) ApplicationTools::displayGauge(l, nbNodes-1, '>');
+    VVdouble substitutionsForCurrentNode(nbDistinctSites);
+    for (size_t i = 0; i < nbDistinctSites; ++i)
+      substitutionsForCurrentNode[i].resize(nbTypes);
+
+    // Now we've got to compute likelihoods in a smart manner... ;)
+    VVVdouble likelihoodsFatherConstantPart(nbDistinctSites);
+    for (size_t i = 0; i < nbDistinctSites; ++i)
+    {
+      VVdouble* likelihoodsFatherConstantPart_i = &likelihoodsFatherConstantPart[i];
+      likelihoodsFatherConstantPart_i->resize(nbClasses);
+      for (size_t c = 0; c < nbClasses; ++c)
+      {
+        Vdouble* likelihoodsFatherConstantPart_i_c = &(*likelihoodsFatherConstantPart_i)[c];
+        likelihoodsFatherConstantPart_i_c->resize(nbStates);
+        double rc = rDist->getProbability(c);
+        for (size_t s = 0; s < nbStates; ++s)
+        {
+          //(* likelihoodsFatherConstantPart_i_c)[s] = rc * model->freq(s);
+          //freq is already accounted in the array
+          (* likelihoodsFatherConstantPart_i_c)[s] = rc;
+        }
+      }
+    }
+    
+    // First, what will remain constant:
+    size_t nbSons =  father->getNumberOfSons();
+    for (size_t n = 0; n < nbSons; ++n)
+    {
+      const Node* currentSon = father->getSon(n);    
+      if (currentSon->getId() != currentNode->getId())
+      {
+        const VVVdouble* likelihoodsFather_son = &drtl.getLikelihoodData()->getLikelihoodArray(father->getId(), currentSon->getId());
+
+        //Now iterate over all site partitions:
+        auto_ptr<TreeLikelihood::ConstBranchModelIterator> mit(drtl.getNewBranchModelIterator(currentSon->getId()));
+        VVVdouble pxy;
+        bool first;
+        while (mit->hasNext())
+        {
+          TreeLikelihood::ConstBranchModelDescription* bmd = mit->next();
+          auto_ptr<TreeLikelihood::SiteIterator> sit(bmd->getNewSiteIterator());
+          first = true;
+          while (sit->hasNext())
+          {
+            size_t i = sit->next();
+            //We retrieve the transition probabilities for this site partition:
+            if (first)
+            {
+              pxy = drtl.getTransitionProbabilitiesPerRateClass(currentSon->getId(), i);
+              first = false;
+            }
+            const VVdouble* likelihoodsFather_son_i = &(*likelihoodsFather_son)[i];
+            VVdouble* likelihoodsFatherConstantPart_i = &likelihoodsFatherConstantPart[i];
+            for (size_t c = 0; c < nbClasses; ++c)
+            {
+              const Vdouble* likelihoodsFather_son_i_c = &(*likelihoodsFather_son_i)[c];
+              Vdouble* likelihoodsFatherConstantPart_i_c = &(*likelihoodsFatherConstantPart_i)[c];
+              VVdouble* pxy_c = & pxy[c]; 
+              for (size_t x = 0; x < nbStates; ++x)
+              {
+                Vdouble* pxy_c_x = &(*pxy_c)[x];
+                double likelihood = 0.;
+                for (size_t y = 0; y < nbStates; ++y)
+                {
+                  likelihood += (*pxy_c_x)[y] * (*likelihoodsFather_son_i_c)[y];
+                }
+                (*likelihoodsFatherConstantPart_i_c)[x] *= likelihood;
+              }
+            }
+          }
+        }      
+      }
+    }
+    if (father->hasFather())
+    {
+      const Node* currentSon = father->getFather();
+      const VVVdouble* likelihoodsFather_son = &drtl.getLikelihoodData()->getLikelihoodArray(father->getId(), currentSon->getId());
+      //Now iterate over all site partitions:
+      auto_ptr<TreeLikelihood::ConstBranchModelIterator> mit(drtl.getNewBranchModelIterator(father->getId()));
+      VVVdouble pxy;
+      bool first;
+      while (mit->hasNext())
+      {
+        TreeLikelihood::ConstBranchModelDescription* bmd = mit->next();
+        auto_ptr<TreeLikelihood::SiteIterator> sit(bmd->getNewSiteIterator());
+        first = true;
+        while (sit->hasNext())
+        {
+          size_t i = sit->next();
+          //We retrieve the transition probabilities for this site partition:
+          if (first)
+          {
+            pxy = drtl.getTransitionProbabilitiesPerRateClass(father->getId(), i);
+            first = false;
+          }
+          const VVdouble* likelihoodsFather_son_i = &(*likelihoodsFather_son)[i];
+          VVdouble* likelihoodsFatherConstantPart_i = &likelihoodsFatherConstantPart[i];
+          for (size_t c = 0; c < nbClasses; ++c)
+          {
+            const Vdouble* likelihoodsFather_son_i_c = &(*likelihoodsFather_son_i)[c];
+            Vdouble* likelihoodsFatherConstantPart_i_c = &(*likelihoodsFatherConstantPart_i)[c];
+            VVdouble* pxy_c = &pxy[c]; 
+            for (size_t x = 0; x < nbStates; ++x)
+            {
+              double likelihood = 0.;
+              for (size_t y = 0; y < nbStates; ++y)
+              {
+                Vdouble* pxy_c_x = &(*pxy_c)[y];
+                likelihood += (*pxy_c_x)[x] * (*likelihoodsFather_son_i_c)[y];
+              }
+              (*likelihoodsFatherConstantPart_i_c)[x] *= likelihood;
+            }
+          }
+        }
+      }      
+    }
+    else
+    {
+      //Account for root frequencies:
+      for (size_t i = 0; i < nbDistinctSites; ++i)
+      {
+        vector<double> freqs = drtl.getRootFrequencies(i);
+        VVdouble* likelihoodsFatherConstantPart_i = &likelihoodsFatherConstantPart[i];
+        for (size_t c = 0; c < nbClasses; ++c)
+        {
+          Vdouble* likelihoodsFatherConstantPart_i_c = &(*likelihoodsFatherConstantPart_i)[c];
+          for (size_t x = 0; x < nbStates; ++x)
+          {
+            (*likelihoodsFatherConstantPart_i_c)[x] *= freqs[x]; 
+          }
+        }
+      }      
+    }
+
+    // Then, we deal with the node of interest.
+    // We first average uppon 'y' to save computations, and then uppon 'x'.
+    // ('y' is the state at 'node' and 'x' the state at 'father'.)
+
+    //Iterate over all site partitions:
+		const VVVdouble* likelihoodsFather_node = &drtl.getLikelihoodData()->getLikelihoodArray(father->getId(), currentNode->getId());
+    auto_ptr<TreeLikelihood::ConstBranchModelIterator> mit(drtl.getNewBranchModelIterator(currentNode->getId()));
+    VVVdouble pxy;
+    bool first;
+    while (mit->hasNext())
+    {
+      TreeLikelihood::ConstBranchModelDescription* bmd = mit->next();
+      substitutionCount.setSubstitutionModel(bmd->getModel());
+      //compute all nxy first:
+      VVVVdouble nxy(nbClasses);
+      for (size_t c = 0; c < nbClasses; ++c)
+      {
+        double rc = rcRates[c];
+        VVVdouble* nxy_c = &nxy[c];
+        nxy_c->resize(nbTypes);
+        for (size_t t = 0; t < nbTypes; ++t)
+        {
+          VVdouble* nxy_c_t = &(*nxy_c)[t];
+          nxy_c_t->resize(nbStates);
+          Matrix<double>* nijt = substitutionCount.getAllNumbersOfSubstitutions(d * rc, t + 1);
+          for (size_t x = 0; x < nbStates; ++x)
+          {
+            Vdouble* nxy_c_t_x = &(*nxy_c_t)[x];
+            nxy_c_t_x->resize(nbStates);
+            for (size_t y = 0; y < nbStates; ++y)
+            {
+              (*nxy_c_t_x)[y] = (*nijt)(x, y);
+            }
+          }
+          delete nijt;
+        }
+      }
+
+      //Now loop over sites:
+      auto_ptr<TreeLikelihood::SiteIterator> sit(bmd->getNewSiteIterator());
+      first = true;
+      while (sit->hasNext())
+      {
+        size_t i = sit->next();
+        //We retrieve the transition probabilities and substitution counts for this site partition:
+        if (first)
+        {
+          pxy = drtl.getTransitionProbabilitiesPerRateClass(currentNode->getId(), i);  
+          first = false;
+        }
+        const VVdouble* likelihoodsFather_node_i = &(*likelihoodsFather_node)[i];
+        VVdouble* likelihoodsFatherConstantPart_i = &likelihoodsFatherConstantPart[i];
+        RowMatrix<double> pairProbabilities(nbStates, nbStates);
+        MatrixTools::fill(pairProbabilities, 0.);
+        VVVdouble subsCounts(nbStates);
+        for (size_t j = 0; j < nbStates; ++j) {
+          subsCounts[j].resize(nbStates);
+          for (size_t k = 0; k < nbStates; ++k) {
+            subsCounts[j][k].resize(nbTypes);
+          }
+        }
+        for (size_t c = 0; c < nbClasses; ++c)
+        {
+          const Vdouble* likelihoodsFather_node_i_c = &(*likelihoodsFather_node_i)[c];
+          Vdouble* likelihoodsFatherConstantPart_i_c = &(*likelihoodsFatherConstantPart_i)[c];
+          const VVdouble* pxy_c = &pxy[c];
+          VVVdouble* nxy_c = &nxy[c];
+          for (size_t x = 0; x < nbStates; ++x)
+          {
+            double* likelihoodsFatherConstantPart_i_c_x = &(*likelihoodsFatherConstantPart_i_c)[x];
+            const Vdouble* pxy_c_x = &(*pxy_c)[x];
+            for (size_t y = 0; y < nbStates; ++y)
+            {
+              double likelihood_cxy = (*likelihoodsFatherConstantPart_i_c_x)
+                 *(*pxy_c_x)[y]
+                 *(*likelihoodsFather_node_i_c)[y];
+              pairProbabilities(x, y) += likelihood_cxy; // Sum over all rate classes.
+              for (size_t t = 0; t < nbTypes; ++t) {
+                subsCounts[x][y][t] += likelihood_cxy * (* nxy_c)[t][x][y];
+              }
+            }
+          }
+        }
+        // Now the vector computation:
+        // Here we do not average over all possible pair of ancestral states,
+        // We only consider the one with max likelihood:
+        vector<size_t> xy = MatrixTools::whichMax(pairProbabilities);
+        for (size_t t = 0; t < nbTypes; ++t) {
+          substitutionsForCurrentNode[i][t] += subsCounts[xy[0]][xy[1]][t] / pairProbabilities(xy[0], xy[1]);
+        }
+      }
+    }
+    //Now we just have to copy the substitutions into the result vector:
+    for (size_t i = 0; i < nbSites; i++)
+      for (size_t t = 0; t < nbTypes; t++)
+        (*substitutions)(l, i, t) = substitutionsForCurrentNode[(*rootPatternLinks)[i]][t];
+  }
+  if (verbose)
+  {
+    if (ApplicationTools::message) *ApplicationTools::message << " ";
+    ApplicationTools::displayTaskDone();
+  }
+  return substitutions;
+}
+
+/**************************************************************************************************/
+
+ProbabilisticSubstitutionMapping* SubstitutionMappingTools::computeSubstitutionVectorsNoAveragingMarginal(
+  const DRTreeLikelihood& drtl,
+  SubstitutionCount& substitutionCount,
+  bool verbose) throw (Exception)
+{
+  //Preamble:
+  if (!drtl.isInitialized()) throw Exception("SubstitutionMappingTools::computeSubstitutionVectorsNoAveragingMarginal(). Likelihood object is not initialized.");
+                                   
+  //A few variables we'll need:
+  
+  const TreeTemplate<Node> tree(drtl.getTree());
+  const SiteContainer*    sequences = drtl.getData();
+  const DiscreteDistribution* rDist = drtl.getRateDistribution();
+  const Alphabet*             alpha = sequences->getAlphabet();
+    
+  size_t nbSites         = sequences->getNumberOfSites();
+  size_t nbDistinctSites = drtl.getLikelihoodData()->getNumberOfDistinctSites();
+  size_t nbStates        = alpha->getSize();
+  size_t nbTypes         = substitutionCount.getNumberOfSubstitutionTypes();
+  vector<const Node*> nodes    = tree.getNodes();
+  const vector<size_t>* rootPatternLinks
+                               = &drtl.getLikelihoodData()->getRootArrayPositions();
+  nodes.pop_back(); // Remove root node.
+  size_t nbNodes = nodes.size();
+  
+  // We create a new ProbabilisticSubstitutionMapping object:
+  ProbabilisticSubstitutionMapping* substitutions = new ProbabilisticSubstitutionMapping(tree, &substitutionCount, nbSites);
+  
+  // Compute the whole likelihood of the tree according to the specified model:
+  
+  Vdouble rcRates = rDist->getCategories();
+
+  // Compute the number of substitutions for each class and each branch in the tree:
+  if (verbose) ApplicationTools::displayTask("Compute marginal ancestral states");
+  MarginalAncestralStateReconstruction masr(&drtl);
+  map<int, vector<size_t> > ancestors = masr.getAllAncestralStates();
+  if (verbose) ApplicationTools::displayTaskDone();
+
+  // Now we just have to compute the substitution vectors:
+  if (verbose) ApplicationTools::displayTask("Compute substitution vectors", true);
+  
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    const Node* currentNode = nodes[l];
+    
+    const Node* father = currentNode->getFather();
+
+    double d = currentNode->getDistanceToFather();
+
+    vector<size_t> nodeStates = ancestors[currentNode->getId()]; //These are not 'true' ancestors ;)
+    vector<size_t> fatherStates = ancestors[father->getId()];
+    
+    //For each node,
+    if (verbose) ApplicationTools::displayGauge(l, nbNodes-1, '>');
+    VVdouble substitutionsForCurrentNode(nbDistinctSites);
+    for (size_t i = 0; i < nbDistinctSites; ++i)
+      substitutionsForCurrentNode[i].resize(nbTypes);
+    
+    // Here, we have no likelihood computation to do!
+
+    // Then, we deal with the node of interest.
+    // ('y' is the state at 'node' and 'x' the state at 'father'.)
+    // Iterate over all site partitions:
+    auto_ptr<TreeLikelihood::ConstBranchModelIterator> mit(drtl.getNewBranchModelIterator(currentNode->getId()));
+    while (mit->hasNext())
+    {
+      TreeLikelihood::ConstBranchModelDescription* bmd = mit->next();
+      substitutionCount.setSubstitutionModel(bmd->getModel());
+      //compute all nxy first:
+      VVVdouble nxyt(nbTypes);
+      for (size_t t = 0; t < nbTypes; ++t)
+      {
+        nxyt[t].resize(nbStates);
+        Matrix<double>* nxy = substitutionCount.getAllNumbersOfSubstitutions(d, t + 1);
+        for (size_t x = 0; x < nbStates; ++x) {
+          nxyt[t][x].resize(nbStates);
+          for (size_t y = 0; y < nbStates; ++y) {
+            nxyt[t][x][y] = (*nxy)(x, y);
+          }
+        }
+        delete nxy;
+      }
+      //Now loop over sites:
+      auto_ptr<TreeLikelihood::SiteIterator> sit(bmd->getNewSiteIterator());
+      while (sit->hasNext())
+      {
+        size_t i = sit->next();
+        size_t fatherState = fatherStates[i];
+        size_t nodeState   = nodeStates[i];
+        if (fatherState >= nbStates || nodeState >= nbStates)
+          for (size_t t = 0; t < nbTypes; ++t)
+            substitutionsForCurrentNode[i][t] = 0; // To be conservative! Only in case there are generic characters.
+        else
+          for (size_t t = 0; t < nbTypes; ++t)
+            substitutionsForCurrentNode[i][t] = nxyt[t][fatherState][nodeState];
+      }
+    }
+    
+    //Now we just have to copy the substitutions into the result vector:
+    for (size_t i = 0; i < nbSites; i++)
+      for (size_t t = 0; t < nbTypes; t++)
+        (*substitutions)(l, i, t) = substitutionsForCurrentNode[(*rootPatternLinks)[i]][t];
+  }
+  if (verbose)
+  {
+    if (ApplicationTools::message) *ApplicationTools::message << " ";
+    ApplicationTools::displayTaskDone();
+  }
+  return substitutions;
+}
+
+/**************************************************************************************************/
+
+ProbabilisticSubstitutionMapping* SubstitutionMappingTools::computeSubstitutionVectorsMarginal(
+  const DRTreeLikelihood& drtl,
+  SubstitutionCount& substitutionCount,
+  bool verbose) throw (Exception)
+{
+  //Preamble:
+  if (!drtl.isInitialized()) throw Exception("SubstitutionMappingTools::computeSubstitutionVectorsMarginal(). Likelihood object is not initialized.");
+                                   
+  //A few variables we'll need:
+  
+  const TreeTemplate<Node>tree(drtl.getTree());
+  const SiteContainer*    sequences = drtl.getData();
+  const DiscreteDistribution* rDist = drtl.getRateDistribution();
+    
+  size_t nbSites         = sequences->getNumberOfSites();
+  size_t nbDistinctSites = drtl.getLikelihoodData()->getNumberOfDistinctSites();
+  size_t nbStates        = sequences->getAlphabet()->getSize();
+  size_t nbClasses       = rDist->getNumberOfCategories();
+  size_t nbTypes         = substitutionCount.getNumberOfSubstitutionTypes();
+  vector<const Node*> nodes    = tree.getNodes();
+  const vector<size_t>* rootPatternLinks
+                               = &drtl.getLikelihoodData()->getRootArrayPositions();
+  nodes.pop_back(); // Remove root node.
+  size_t nbNodes = nodes.size();
+  
+  // We create a new ProbabilisticSubstitutionMapping object:
+  ProbabilisticSubstitutionMapping* substitutions = new ProbabilisticSubstitutionMapping(tree, &substitutionCount, nbSites);
+                                     
+  // Compute the whole likelihood of the tree according to the specified model:
+  
+  Vdouble rcProbs = rDist->getProbabilities();
+  Vdouble rcRates = rDist->getCategories();
+
+  //II) Compute the number of substitutions for each class and each branch in the tree:
+  if (verbose) ApplicationTools::displayTask("Compute marginal node-pairs likelihoods", true);
+  
+  for (size_t l = 0; l < nbNodes; l++)
+  {
+    const Node* currentNode = nodes[l];
+    
+    const Node* father = currentNode->getFather();
+
+    double d = currentNode->getDistanceToFather();
+    
+    //For each node,
+    if (verbose) ApplicationTools::displayGauge(l, nbNodes-1, '>');
+    VVdouble substitutionsForCurrentNode(nbDistinctSites);
+    for (size_t i = 0; i < nbDistinctSites; ++i)
+      substitutionsForCurrentNode[i].resize(nbTypes);
+
+    // Then, we deal with the node of interest.
+    // ('y' is the state at 'node' and 'x' the state at 'father'.)
+    VVVdouble probsNode   = DRTreeLikelihoodTools::getPosteriorProbabilitiesForEachStateForEachRate(drtl, currentNode->getId());
+    VVVdouble probsFather = DRTreeLikelihoodTools::getPosteriorProbabilitiesForEachStateForEachRate(drtl, father->getId());
+
+    //Iterate over all site partitions:
+    auto_ptr<TreeLikelihood::ConstBranchModelIterator> mit(drtl.getNewBranchModelIterator(currentNode->getId()));
+    while (mit->hasNext())
+    {
+      TreeLikelihood::ConstBranchModelDescription* bmd = mit->next();
+      substitutionCount.setSubstitutionModel(bmd->getModel());
+      //compute all nxy first:
+      VVVVdouble nxy(nbClasses);
+      for (size_t c = 0; c < nbClasses; ++c)
+      {
+        VVVdouble* nxy_c = &nxy[c];
+        double rc = rcRates[c];
+        nxy_c->resize(nbTypes);
+        for (size_t t = 0; t < nbTypes; ++t)
+        {
+          VVdouble* nxy_c_t = &(*nxy_c)[t];
+          Matrix<double>* nijt = substitutionCount.getAllNumbersOfSubstitutions(d * rc, t + 1);
+          nxy_c_t->resize(nbStates);
+          for (size_t x = 0; x < nbStates; ++x)
+          {
+            Vdouble* nxy_c_t_x = &(*nxy_c_t)[x];
+            nxy_c_t_x->resize(nbStates);
+            for (size_t y = 0; y < nbStates; ++y)
+            {
+              (*nxy_c_t_x)[y] = (*nijt)(x, y);
+            }
+          }
+          delete nijt;
+        }
+      }
+
+      //Now loop over sites:
+      auto_ptr<TreeLikelihood::SiteIterator> sit(bmd->getNewSiteIterator());
+      while (sit->hasNext())
+      {
+        size_t i = sit->next();
+        VVdouble* probsNode_i   = & probsNode[i];
+        VVdouble* probsFather_i = & probsFather[i];
+        for (size_t c = 0; c < nbClasses; ++c)
+        {
+          Vdouble* probsNode_i_c   = &(*probsNode_i)[c];
+          Vdouble* probsFather_i_c = &(*probsFather_i)[c];
+          VVVdouble* nxy_c = &nxy[c];
+          for (size_t x = 0; x < nbStates; ++x)
+          {
+            for (size_t y = 0; y < nbStates; ++y)
+            {
+              double prob_cxy = (*probsFather_i_c)[x] * (*probsNode_i_c)[y];
+              // Now the vector computation:
+              for (size_t t = 0; t < nbTypes; ++t) {
+                substitutionsForCurrentNode[i][t] += prob_cxy * (*nxy_c)[t][x][y];
+                //                                   <------>   <--------------->
+                // Posterior probability                 |                | 
+                // for site i and rate class c *         |                |
+                // likelihood for this site--------------+                |
+                //                                                        |
+                //Substitution function for site i and rate class c-------+
+              }
+            }
+          }
+        }
+      }
+    }
+    
+    //Now we just have to copy the substitutions into the result vector:
+    for (size_t i = 0; i < nbSites; ++i)
+      for (size_t t = 0; t < nbTypes; ++t)
+        (*substitutions)(l, i, t) = substitutionsForCurrentNode[(* rootPatternLinks)[i]][t];
+  }
+  if (verbose)
+  {
+    if (ApplicationTools::message) *ApplicationTools::message << " ";
+    ApplicationTools::displayTaskDone();
+  }
+  return substitutions;
+}
+
+/**************************************************************************************************/
+
+void SubstitutionMappingTools::writeToStream(
+  const ProbabilisticSubstitutionMapping& substitutions,
+  const SiteContainer& sites,
+  size_t type,
+  ostream& out)
+  throw (IOException) 
+{
+  if (!out) throw IOException("SubstitutionMappingTools::writeToFile. Can't write to stream.");
+  out << "Branches";
+  out << "\tMean";
+  for (size_t i = 0; i < substitutions.getNumberOfSites(); i++)
+  {
+    out << "\tSite" << sites.getSite(i).getPosition();
+  }
+  out << endl;
+  
+  for (size_t j = 0; j < substitutions.getNumberOfBranches(); j++)
+  {
+    out << substitutions.getNode(j)->getId() << "\t" << substitutions.getNode(j)->getDistanceToFather();
+    for (size_t i = 0; i < substitutions.getNumberOfSites(); i++)
+    {
+      out << "\t" << substitutions(j, i, type);
+    }
+    out << endl;
+  }
+}
+
+/**************************************************************************************************/
+
+void SubstitutionMappingTools::readFromStream(istream& in, ProbabilisticSubstitutionMapping& substitutions, size_t type)
+  throw (IOException)
+{
+  try
+  {
+    DataTable* data = DataTable::read(in, "\t", true, -1);
+    vector<string> ids = data->getColumn(0);
+    data->deleteColumn(0);//Remove ids
+    data->deleteColumn(0);//Remove means
+    //Now parse the table:
+    size_t nbSites = data->getNumberOfColumns();
+    substitutions.setNumberOfSites(nbSites);
+    size_t nbBranches = data->getNumberOfRows();
+    for (size_t i = 0; i < nbBranches; i++)
+    {
+      int id = TextTools::toInt(ids[i]);
+      size_t br = substitutions.getNodeIndex(id);
+      for (size_t j = 0; j < nbSites; j++)
+      {
+        substitutions(br, j, type) = TextTools::toDouble((*data)(i, j));
+      }
+    }
+    //Parse the header:
+    for (size_t i = 0; i < nbSites; i++)
+    {
+      string siteTxt = data->getColumnName(i);
+      int site = 0;
+      if (siteTxt.substr(0,4) == "Site") site = TextTools::to<int>(siteTxt.substr(4));
+      else site = TextTools::to<int>(siteTxt);
+      substitutions.setSitePosition(i, site);
+    }
+    
+    delete data;
+  }
+  catch (Exception& e)
+  {
+    throw IOException(string("Bad input file. ") + e.what());
+  }
+}
+
+/**************************************************************************************************/
+    
+vector<double> SubstitutionMappingTools::computeTotalSubstitutionVectorForSite(const SubstitutionMapping& smap, size_t siteIndex)
+{
+  size_t nbBranches = smap.getNumberOfBranches();
+  size_t nbTypes    = smap.getNumberOfSubstitutionTypes();
+  Vdouble v(nbBranches);
+  for (size_t l = 0; l < nbBranches; ++l) {
+    v[l] = 0;
+    for (size_t t = 0; t < nbTypes; ++t) {
+      v[l] += smap(l, siteIndex, t);
+    }
+  }
+  return v;
+}
+
+/**************************************************************************************************/
+
+double SubstitutionMappingTools::computeNormForSite(const SubstitutionMapping& smap, size_t siteIndex)
+{
+  double sumSquare = 0;
+  for (size_t l = 0; l < smap.getNumberOfBranches(); ++l) {
+    double sum = 0;
+    for (size_t t = 0; t < smap.getNumberOfSubstitutionTypes(); ++t) {
+      sum += smap(l, siteIndex, t);
+    }
+    sumSquare += sum * sum;
+  }
+  return sqrt(sumSquare);
+}
+
+/**************************************************************************************************/
+    
+vector<double> SubstitutionMappingTools::computeSumForBranch(const SubstitutionMapping& smap, size_t branchIndex)
+{
+  size_t nbSites = smap.getNumberOfSites();
+  size_t nbTypes = smap.getNumberOfSubstitutionTypes();
+  Vdouble v(nbTypes, 0);
+  for (size_t i = 0; i < nbSites; ++i) {
+    for (size_t t = 0; t < nbTypes; ++t) {
+      v[t] += smap(branchIndex, i, t);
+    }
+  }
+  return v;
+}
+
+/**************************************************************************************************/
+
+vector<double> SubstitutionMappingTools::computeSumForSite(const SubstitutionMapping& smap, size_t siteIndex)
+{
+  size_t nbBranches = smap.getNumberOfBranches();
+  size_t nbTypes = smap.getNumberOfSubstitutionTypes();
+  Vdouble v(nbTypes, 0);
+  for (size_t i = 0; i < nbBranches; ++i) {
+    for (size_t t = 0; t < nbTypes; ++t) {
+      v[t] += smap(i, siteIndex, t);
+    }
+  }
+  return v;
+}
+
+/**************************************************************************************************/
+
diff --git a/src/Bpp/Phyl/Mapping/SubstitutionMappingTools.h b/src/Bpp/Phyl/Mapping/SubstitutionMappingTools.h
new file mode 100644
index 0000000..9234cf0
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/SubstitutionMappingTools.h
@@ -0,0 +1,243 @@
+//
+// File: SubstitutionMappingTools.h
+// Created by: Julien Dutheil
+// Created on: Wed Apr 5 13:04 2006
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _SUBSTITUTIONMAPPINGTOOLS_H_
+#define _SUBSTITUTIONMAPPINGTOOLS_H_
+
+#include "ProbabilisticSubstitutionMapping.h"
+#include "SubstitutionCount.h"
+#include "OneJumpSubstitutionCount.h"
+#include "../Likelihood/DRTreeLikelihood.h"
+
+namespace bpp
+{
+
+/**
+ * @brief Provide methods to compute substitution mappings.
+ *
+ * For now, only 4 methods are implemented, and provide probabilistic substitution mappings.
+ *
+ * See:
+ * Dutheil J, Pupko T, Jean-Marie A, Galtier N.
+ * A model-based approach for detecting coevolving positions in a molecule.
+ * Mol Biol Evol. 2005 Sep;22(9):1919-28. Epub 2005 Jun 8.
+ *
+ * @author Julien Dutheil
+ */
+class SubstitutionMappingTools
+{
+  public:
+    SubstitutionMappingTools() {}
+    virtual ~SubstitutionMappingTools() {}
+    
+	public:
+		
+		/**
+		 * @brief Compute the substitutions vectors for a particular dataset using the
+		 * double-recursive likelihood computation.
+		 *
+		 * @param drtl              A DRTreeLikelihood object.
+		 * @param substitutionCount The SubstitutionCount to use.
+		 * @param verbose           Print info to screen.
+		 * @return A vector of substitutions vectors (one for each site).
+     * @throw Exception If the likelihood object is not initialized.
+		 */
+		static ProbabilisticSubstitutionMapping* computeSubstitutionVectors(
+			const DRTreeLikelihood& drtl,
+			SubstitutionCount& substitutionCount,
+			bool verbose = true) throw (Exception);
+		
+		/**
+		 * @brief Compute the substitutions vectors for a particular dataset using the
+		 * double-recursive likelihood computation.
+		 *
+		 * In this method, substitution counts are computed using the pair of ancestral
+		 * states with maximum likelihood.
+		 * This is a kind of joint-pair ancestral reconstruction, as in Galtier and Boursot (1998).
+		 * This reconstruction possibly takes into account several rate classes, and
+		 * substitution counts are averaged over all rate classes, weighted by their conditional
+		 * likelihood.
+		 *
+		 * This function is mainly for testing purpose (see Dutheil et al. 2005).
+		 * For practical use, consider using the 'getSubstitutionVectors' method instead.
+		 *
+		 * @param drtl              A DRTreeLikelihood object.
+		 * @param substitutionCount The substitutionsCount to use.
+		 * @param verbose           Print info to screen.
+		 * @return A vector of substitutions vectors (one for each site).
+     * @throw Exception If the likelihood object is not initialized.
+		 */
+		static ProbabilisticSubstitutionMapping* computeSubstitutionVectorsNoAveraging(
+			const DRTreeLikelihood& drtl,
+			SubstitutionCount& substitutionCount,
+			bool verbose = true) throw (Exception);
+		
+		/**
+		 * @brief Compute the substitutions vectors for a particular dataset using the
+		 * double-recursive likelihood computation.
+		 *
+		 * In this method, all ancestral states are estimated using marginal likelihoods,
+		 * putatively intregated over several rate classes.
+		 * For each branch, the number of substitution given marginal states is used.
+		 * This method, used with a SimpleSubstitutionCount objet is equivalent to
+		 * Tufféry and Darlu's (2000) computation of substitution vectors.
+		 *
+		 * Use with another substitution count objet is in most cases irrelevent.
+		 * 
+		 * @param drtl              A DRTreeLikelihood object.
+		 * @param substitutionCount The substitutionsCount to use.
+		 * @param verbose           Print info to screen.
+		 * @return A vector of substitutions vectors (one for each site).
+     * @throw Exception If the likelihood object is not initialized.
+		 */
+		static ProbabilisticSubstitutionMapping* computeSubstitutionVectorsNoAveragingMarginal(
+			const DRTreeLikelihood& drtl,
+			SubstitutionCount& substitutionCount,
+			bool verbose = true) throw (Exception);
+		
+		/**
+		 * @brief Compute the substitutions vectors for a particular dataset using the
+		 * double-recursive likelihood computation.
+		 *
+		 * The marginal probability is used for weighting, i.e. the product of probabilities for the pair.
+		 *
+		 * This function is mainly for testing purpose (see Dutheil et al. 2005).
+		 * For practical use, consider using the 'getSubstitutionVectors' method instead.
+		 *
+		 * @param drtl              A DRTreeLikelihood object.
+		 * @param substitutionCount The substitutionsCount to use.
+		 * @param verbose           Print info to screen.
+		 * @return A vector of substitutions vectors (one for each site).
+     * @throw Exception If the likelihood object is not initialized.
+		 */
+		static ProbabilisticSubstitutionMapping* computeSubstitutionVectorsMarginal(
+			const DRTreeLikelihood& drtl,
+			SubstitutionCount& substitutionCount,
+			bool verbose = true) throw (Exception);
+	
+
+    /**
+     * @brief This method computes for each site and for each branch the probability that
+     * at least one jump occurred.
+     *
+     * Here 'jump' refer to a change in the model state. Depending on the model, this might
+     * not be the same as a substitution (an alphabet state change).
+     */
+		static ProbabilisticSubstitutionMapping* computeOneJumpProbabilityVectors(
+			const DRTreeLikelihood& drtl,
+			bool verbose = true) throw (Exception)
+    {
+      OneJumpSubstitutionCount ojsm(0);
+      return computeSubstitutionVectors(drtl, ojsm, 0);
+    }
+
+		/**
+		 * @brief Write the substitutions vectors to a stream.
+		 *
+		 * @param substitutions The substitutions vectors to write.
+		 * @param sites         The dataset associated to the vectors
+		 * (needed to know the position of each site in the dataset).
+     * @param type          The type of substitutions to be output. See SubstitutionCount class.
+     * Only one type of substitution can be output at a time.
+		 * @param out           The output stream where to write the vectors.
+		 * @throw IOException If an output error happens.
+		 */
+		static void writeToStream(
+			const ProbabilisticSubstitutionMapping& substitutions,
+			const SiteContainer& sites,
+      size_t type,
+			std::ostream& out)
+			throw (IOException);
+	
+		/**
+		 * @brief Read the substitutions vectors from a stream.
+		 *
+		 * @param in            The input stream where to read the vectors.
+		 * @param substitutions The mapping object to fill.
+     * @param type          The type of substitutions that are read. Should be in supported by the substittuion count obect assiciated to the mapping, if any.
+		 * @throw IOException If an input error happens.
+		 */
+		static void readFromStream(std::istream& in, ProbabilisticSubstitutionMapping& substitutions, size_t type)
+			throw (IOException);
+
+    /**
+     * @brief Sum all type of substitutions for each branch of a given position (specified by its index).
+     *
+     * @param smap The substitution map to use.
+     * @param siteIndex The index of the substitution vector for which the counts should be computed.
+     * @return A vector will all counts for all types of substitutions summed. 
+     */
+    static std::vector<double> computeTotalSubstitutionVectorForSite(const SubstitutionMapping& smap, size_t siteIndex);
+
+    /**
+     * @brief Compute the norm of a substitution vector for a given position (specified by its index).
+     *
+     * The norm is computed as:
+     * @f$ N_i = \sqrt{\left(\sum_l {\left(\sum_t n_{l, i, t}\right)}^2\right)}@f$,
+     * where @f$n_{l, i, t}@f$ is the number of substitutions of type t on site i on branch l, obtained using the () operator for the SubstitutionMapping object.
+     *
+     * @param smap The substitution map to use.
+     * @param siteIndex The index of the substitution vector for which the norm should be computed.
+     * @return The norm of the substitution vector.
+     */
+    static double computeNormForSite(const SubstitutionMapping& smap, size_t siteIndex);
+    
+    /**
+     * @brief Sum all substitutions for each type of a given branch (specified by its index).
+     *
+     * @param smap The substitution map to use.
+     * @param branchIndex The index of the substitution vector for which the counts should be computed.
+     * @return A vector will all counts summed for each types of substitutions. 
+     */
+    static std::vector<double> computeSumForBranch(const SubstitutionMapping& smap, size_t branchIndex);
+ 
+    /**
+     * @brief Sum all substitutions for each type of a given site (specified by its index).
+     *
+     * @param smap The substitution map to use.
+     * @param siteIndex The index of the substitution vector for which the counts should be computed.
+     * @return A vector will all counts summed for each types of substitutions. 
+     */
+    static std::vector<double> computeSumForSite(const SubstitutionMapping& smap, size_t siteIndex);
+ };
+
+} //end of namespace bpp.
+
+#endif //_SUBSTITUTIONMAPPINGTOOLS_H_
+
diff --git a/src/Bpp/Phyl/Mapping/SubstitutionRegister.h b/src/Bpp/Phyl/Mapping/SubstitutionRegister.h
new file mode 100644
index 0000000..e1f85b0
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/SubstitutionRegister.h
@@ -0,0 +1,634 @@
+//
+// File: SubstitutionRegister.h
+// Created by: Julien Dutheil
+// Created on: Mon Dec 6 16:32 2010
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _SUBSTITUTIONREGISTER_H_
+#define _SUBSTITUTIONREGISTER_H_
+
+// From bpp-core:
+#include <Bpp/Clonable.h>
+
+// From bpp-seq:
+#include <Bpp/Seq/Alphabet/Alphabet.h>
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+#include <Bpp/Seq/GeneticCode/GeneticCode.h>
+
+// From the STL:
+#include <vector>
+
+namespace bpp
+{
+/**
+ * @brief The SubstitutionRegister interface.
+ *
+ * Substitution registers are simple classes that define categories of substitutions, and assign them an index.
+ *
+ * @author Julien Dutheil
+ */
+class SubstitutionRegister :
+  public virtual Clonable
+{
+public:
+  SubstitutionRegister() {}
+  virtual ~SubstitutionRegister() {}
+
+#ifndef NO_VIRTUAL_COV
+  virtual SubstitutionRegister* clone() const = 0;
+#endif
+
+public:
+  /**
+   * @return The alphabet associated to this instance.
+   */
+  virtual const Alphabet* getAlphabet() const = 0;
+
+  /**
+   * @return The number of substitution types supported by this class.
+   */
+  virtual size_t getNumberOfSubstitutionTypes() const = 0;
+
+  /**
+   * @brief Get the substitution type far a given pair of states.
+   *
+   * @param fromState Initial state (should be a state supported by the specified alphabet).
+   * @param toState   Final state (should be a state supported by the specified alphabet).
+   * @return The index of the corresponding substitution type, ranging from 0 to 'getNumberOfSubstitutionTypes' + 1,
+   * as non-substitution (that is when fromState == toState) will always return 0.
+   */
+  virtual size_t getType(int fromState, int toState) const = 0;
+
+  /**
+   * @brief Get the name of a given substitution type.
+   *
+   * This method is only used for user-friendlyness purposes, not computational goal.
+   * I can therefore be left unimplemented in some cases.
+   *
+   * @param type Index of the substitution (should be an size_t contained in the register).
+   * @return A string describing the substitution type.
+   */
+  virtual std::string getTypeName(size_t type) const = 0;
+};
+
+class AbstractSubstitutionRegister :
+  public virtual SubstitutionRegister
+{
+protected:
+  const Alphabet* alphabet_;
+
+public:
+  AbstractSubstitutionRegister(const Alphabet* alphabet) :
+    alphabet_(alphabet)
+  {}
+
+  AbstractSubstitutionRegister(const AbstractSubstitutionRegister& asr) :
+    alphabet_(asr.alphabet_)
+  {}
+
+  AbstractSubstitutionRegister& operator=(const AbstractSubstitutionRegister& asr)
+  {
+    alphabet_ = asr.alphabet_;
+    return *this;
+  }
+
+  virtual ~AbstractSubstitutionRegister() {}
+
+public:
+  const Alphabet* getAlphabet() const { return alphabet_; }
+};
+
+/**
+ * @brief Gather states into defined categories, and count the changes between categories.
+ *
+ * Optionally allows for within categories substitutions.
+ */
+class CategorySubstitutionRegister :
+  public AbstractSubstitutionRegister
+{
+protected:
+  bool within_;
+  size_t nbCategories_;
+  mutable std::map<int, size_t> categories_;
+  std::vector<std::string> categoryNames_;
+  std::vector< std::vector<size_t> > index_;
+  std::vector< std::vector<size_t> > revIndex_;
+
+public:
+  /**
+   * @brief Build a new substitution register with categories. This class is mean to be inherited.
+   *
+   * @param alphabet The input alphabet.
+   * @param within Specifies if within categories substitutions should be counted as well.
+   */
+  CategorySubstitutionRegister(const Alphabet* alphabet, bool within = false) :
+    AbstractSubstitutionRegister(alphabet),
+    within_(within),
+    nbCategories_(0),
+    categories_(),
+    categoryNames_(),
+    index_(),
+    revIndex_()
+  {}
+
+protected:
+  template<class T>
+  void setCategories(const std::map<int, T>& categories)
+  {
+    // First index categories:
+    nbCategories_ = 0;
+    std::map<T, size_t> cats;
+    for (typename std::map<int, T>::const_iterator it = categories.begin(); it != categories.end(); ++it)
+    {
+      if (cats.find(it->second) == cats.end())
+      {
+        ++nbCategories_;
+        cats[it->second] = nbCategories_;
+      }
+    }
+
+    // Now creates categories:
+    categories_.clear();
+    categoryNames_.resize(nbCategories_);
+    std::vector<int> types = alphabet_->getSupportedInts();
+    for (size_t i = 0; i < types.size(); ++i)
+    {
+      typename std::map<int, T>::const_iterator it = categories.find(types[i]);
+      if (it != categories.end())
+      {
+        categories_[types[i]] = cats[it->second];
+        categoryNames_[cats[it->second] - 1] += alphabet_->intToChar(types[i]);
+      }
+      else
+      {
+        categories_[types[i]] = 0;
+      }
+    }
+
+    size_t count = 1;
+    index_.resize(nbCategories_);
+    for (size_t i = 0; i < index_.size(); ++i)
+    {
+      index_[i].resize(nbCategories_);
+      for (size_t j = 0; j < index_.size(); ++j)
+      {
+        if (j != i)
+        {
+          index_[i][j] = count++;
+          std::vector<size_t> pos(2);
+          pos[0] = i;
+          pos[1] = j;
+          revIndex_.push_back(pos);
+        }
+      }
+    }
+    if (within_)
+    {
+      for (size_t i = 0; i < index_.size(); ++i)
+      {
+        index_[i][i] = count++;
+        std::vector<size_t> pos(2);
+        pos[0] = i;
+        pos[1] = i;
+        revIndex_.push_back(pos);
+      }
+    }
+  }
+
+public:
+  virtual size_t getCategory(int state) const
+  {
+    if (!alphabet_->isIntInAlphabet(state))
+      throw Exception("CategorySubstitutionRegister::getCategory(). State is not supported by alphabet.");
+    return categories_[state];
+  }
+
+  virtual size_t getCategoryFrom(size_t type) const
+  {
+    if (type <= nbCategories_ * (nbCategories_ - 1))
+    {
+      return revIndex_[type - 1][0] + 1;
+    }
+    else
+    {
+      if (within_)
+        return revIndex_[type - 1][0] + 1;
+      else
+        throw Exception("CategorySubstitutionRegister::getCategoryFrom. Bad substitution type.");
+    }
+  }
+
+  virtual size_t getCategoryTo(size_t type) const
+  {
+    if (type <= nbCategories_ * (nbCategories_ - 1))
+    {
+      return revIndex_[type - 1][1] + 1;
+    }
+    else
+    {
+      if (within_)
+        return revIndex_[type - 1][1] + 1;
+      else
+        throw Exception("CategorySubstitutionRegister::getCategoryTo. Bad substitution type.");
+    }
+  }
+
+  virtual std::string getCategoryName(size_t category) const
+  {
+    return categoryNames_[category - 1];
+  }
+
+  virtual bool allowWithin() const { return within_; }
+
+  size_t getNumberOfCategories() const { return nbCategories_; }
+
+  size_t getNumberOfSubstitutionTypes() const { return nbCategories_ * (nbCategories_ - 1) + (within_ ? nbCategories_ : 0); }
+
+  virtual size_t getType(int fromState, int toState) const
+  {
+    size_t fromCat = categories_[fromState];
+    size_t toCat   = categories_[toState];
+    if (fromCat > 0 && toCat > 0)
+      return index_[fromCat - 1][toCat - 1];
+    else
+      return 0;
+  }
+
+  std::string getTypeName(size_t type) const
+  {
+    return getCategoryName(getCategoryFrom(type)) + "->" +  getCategoryName(getCategoryTo(type));
+  }
+};
+
+
+/**
+ * @brief Count all substitutions.
+ *
+ * This register has only 1 substitution type, mapped as:
+ * - 0 not a substitution
+ * - 1 a substitution
+ */
+class TotalSubstitutionRegister :
+  public AbstractSubstitutionRegister
+{
+public:
+  TotalSubstitutionRegister(const Alphabet* alphabet) :
+    AbstractSubstitutionRegister(alphabet)
+  {}
+
+  TotalSubstitutionRegister* clone() const { return new TotalSubstitutionRegister(*this); }
+
+public:
+  size_t getNumberOfSubstitutionTypes() const { return 1; }
+
+  size_t getType(int fromState, int toState) const
+  {
+    return fromState == toState ? 0 : 1;
+  }
+
+  std::string getTypeName(size_t type) const
+  {
+    if (type == 0)
+    {
+      return "no substitution";
+    }
+    else if (type == 1)
+    {
+      return "substitution";
+    }
+    else
+    {
+      throw Exception("TotalSubstitutionRegister::getTypeName. Bad substitution type.");
+    }
+  }
+};
+
+/**
+ * @brief Distinguishes all types of substitutions.
+ *
+ * This register has only n * (n-1) substitution type, where n is the size of the alphabet, mapped as:
+ * - 0 not a substitution
+ * - x in [1, n(n-1)] a substitution
+ */
+class ComprehensiveSubstitutionRegister :
+  public CategorySubstitutionRegister
+{
+public:
+  ComprehensiveSubstitutionRegister(const Alphabet* alphabet, bool within = false) :
+    CategorySubstitutionRegister(alphabet, within)
+  {
+    std::map<int, int> categories;
+    for (int i = 0; i < static_cast<int>(alphabet->getSize()); ++i)
+    {
+      categories[i] = i;
+    }
+    setCategories<int>(categories);
+  }
+
+  ComprehensiveSubstitutionRegister* clone() const { return new ComprehensiveSubstitutionRegister(*this); }
+};
+
+/**
+ * @brief Distinguishes AT<->GC from GC<->AT.
+ *
+ * This register has two substitution types, mapped as:
+ * - 0 not a substitution
+ * - 1 a AT->GC substitution
+ * - 2 a GC->AT substitution
+ */
+class GCSubstitutionRegister :
+  public CategorySubstitutionRegister
+{
+public:
+  GCSubstitutionRegister(const NucleicAlphabet* alphabet, bool within = false) :
+    CategorySubstitutionRegister(alphabet, within)
+  {
+    std::map<int, int> categories;
+    categories[0] = 1;
+    categories[1] = 2;
+    categories[2] = 2;
+    categories[3] = 1;
+    setCategories<int>(categories);
+  }
+
+  GCSubstitutionRegister* clone() const { return new GCSubstitutionRegister(*this); }
+};
+
+/**
+ * @brief Distinguishes transitions from transversions.
+ *
+ * This register has two substitution types, mapped as:
+ * - 0 not a substitution
+ * - 1 a transition
+ * - 2 a transversion
+ */
+class TsTvSubstitutionRegister :
+  public AbstractSubstitutionRegister
+{
+public:
+  TsTvSubstitutionRegister(const NucleicAlphabet* alphabet) :
+    AbstractSubstitutionRegister(alphabet)
+  {}
+
+  TsTvSubstitutionRegister* clone() const { return new TsTvSubstitutionRegister(*this); }
+
+public:
+  size_t getNumberOfSubstitutionTypes() const { return 2; }
+
+  size_t getType(int fromState, int toState) const
+  {
+    if (fromState == toState)
+      return 0;  // nothing happens
+    if ((fromState == 0 && toState == 2)
+        || (fromState == 2 && toState == 0)
+        || (fromState == 1 && toState == 3)
+        || (fromState == 3 && toState == 1))
+      return 1;  // This is a transition
+    return 2; // This is a transversion
+  }
+
+  std::string getTypeName(size_t type) const
+  {
+    if (type == 0)
+    {
+      return "no substitution";
+    }
+    else if (type == 1)
+    {
+      return "transition";
+    }
+    else if (type == 2)
+    {
+      return "transversion";
+    }
+    else
+    {
+      throw Exception("TsTvSubstitutionRegister::getTypeName. Bad substitution type.");
+    }
+  }
+};
+
+/**
+ * @brief Distinguishes synonymous from non-synonymous substitutions.
+ *
+ * This register has two substitution types, mapped as:
+ * - 0 not a substitution
+ * - 1 a synonymous substitution
+ * - 2 a non-synonymous substitution
+ */
+class DnDsSubstitutionRegister :
+  public AbstractSubstitutionRegister
+{
+private:
+  const GeneticCode* code_;
+  bool countMultiple_;
+
+public:
+  DnDsSubstitutionRegister(const GeneticCode* gc, bool countMultiple = false) :
+    AbstractSubstitutionRegister(gc->getSourceAlphabet()),
+    code_(gc),
+    countMultiple_(countMultiple)
+  {}
+
+  DnDsSubstitutionRegister(const DnDsSubstitutionRegister& reg) :
+    AbstractSubstitutionRegister(reg),
+    code_(reg.code_),
+    countMultiple_(reg.countMultiple_)
+  {}
+
+  DnDsSubstitutionRegister& operator=(const DnDsSubstitutionRegister& reg)
+  {
+    AbstractSubstitutionRegister::operator=(reg);
+    code_ = reg.code_;
+    countMultiple_ = reg.countMultiple_;
+    return *this;
+  }
+
+  DnDsSubstitutionRegister* clone() const { return new DnDsSubstitutionRegister(*this); }
+
+public:
+  size_t getNumberOfSubstitutionTypes() const { return 2; }
+
+  size_t getType(int fromState, int toState) const
+  {
+    const CodonAlphabet* cAlpha = dynamic_cast<const CodonAlphabet*>(alphabet_);
+    if (cAlpha->isStop(fromState) || cAlpha->isStop(toState))
+      return 0;
+    if (fromState == toState)
+      return 0;  // nothing happens
+    if (!countMultiple_)
+    {
+      size_t countPos = 0;
+      if (cAlpha->getFirstPosition(fromState) != cAlpha->getFirstPosition(toState))
+        countPos++;
+      if (cAlpha->getSecondPosition(fromState) != cAlpha->getSecondPosition(toState))
+        countPos++;
+      if (cAlpha->getThirdPosition(fromState) != cAlpha->getThirdPosition(toState))
+        countPos++;
+      if (countPos > 1)
+        return 0;
+    }
+    return code_->areSynonymous(fromState, toState) ? 1 : 2;
+  }
+
+  std::string getTypeName (size_t type) const
+  {
+    if (type == 0)
+    {
+      return "no substitution";
+    }
+    else if (type == 1)
+    {
+      return "synonymous";
+    }
+    else if (type == 2)
+    {
+      return "non synonymous";
+    }
+    else
+    {
+      throw Exception("DnDsSubstitutionRegister::getTypeName. Bad substitution type.");
+    }
+  }
+};
+
+/**
+ * @brief Distinguishes AT->GC vs GC->AT inside synonymous
+ * substitutions on third codon position.
+ *
+ * This register has two substitution types, mapped as:
+ * - 0 not a counted substitution
+ * - 1 a AT->GC synonymous substitution
+ * - 2 a GC->AT synonymous substitution
+ *
+ * Multiple substitutions are forbidden.
+ *
+ */
+
+class GCSynonymousSubstitutionRegister :
+  public CategorySubstitutionRegister
+{
+private:
+  const GeneticCode* code_;
+
+public:
+  GCSynonymousSubstitutionRegister(const GeneticCode* gc, bool within = false) :
+    CategorySubstitutionRegister(gc->getSourceAlphabet(), within),
+    code_(gc)
+  {
+    const CodonAlphabet* pCA = dynamic_cast<const CodonAlphabet*>(gc->getSourceAlphabet());
+
+    std::map<int, int> categories;
+    for (int i = 0; i < static_cast<int>(pCA->getSize()); i++)
+    {
+      int n = pCA->getThirdPosition(i);
+      switch (n)
+      {
+      case 0:
+      case 3:
+        categories[i] = 1;
+        break;
+      case 1:
+      case 2:
+        categories[i] = 2;
+        break;
+      }
+    }
+    setCategories<int>(categories);
+  }
+
+  GCSynonymousSubstitutionRegister(const GCSynonymousSubstitutionRegister& reg) :
+    CategorySubstitutionRegister(reg),
+    code_(reg.code_)
+  {}
+
+  GCSynonymousSubstitutionRegister& operator=(const GCSynonymousSubstitutionRegister& reg)
+  {
+    CategorySubstitutionRegister::operator=(reg);
+    code_ = reg.code_;
+    return *this;
+  }
+
+  GCSynonymousSubstitutionRegister* clone() const { return new GCSynonymousSubstitutionRegister(*this); }
+
+public:
+  size_t getNumberOfSubstitutionTypes() const { return 2; }
+
+  size_t getType(int fromState, int toState) const
+  {
+    const CodonAlphabet* pCA = dynamic_cast<const CodonAlphabet*>(code_->getSourceAlphabet());
+    if (pCA->isStop(fromState) || pCA->isStop(toState) || !code_->areSynonymous(fromState, toState))
+      return 0;
+
+    // only substitutions between 3rd positions
+
+    if ((pCA->getFirstPosition(fromState) != pCA->getFirstPosition(toState)) ||
+        (pCA->getSecondPosition(fromState) != pCA->getSecondPosition(toState)))
+      return 0;
+
+    size_t fromCat = categories_[fromState];
+    size_t toCat   = categories_[toState];
+
+    if (fromCat > 0 && toCat > 0)
+      return index_[fromCat - 1][toCat - 1];
+    else
+      return 0;
+  }
+
+  std::string getTypeName (size_t type) const
+  {
+    if (type == 0)
+    {
+      return "no AT<->GC substitution or non-synonymous substitution";
+    }
+    else if (type == 1)
+    {
+      return "AT->GC synonymous";
+    }
+    else if (type == 2)
+    {
+      return "GC->AT synonymous";
+    }
+    else
+    {
+      throw Exception("GCSynonymousSubstitutionRegister::getTypeName. Bad substitution type.");
+    }
+  }
+};
+} // end of namespace bpp.
+
+#endif // _SUBSTITUTIONREGISTER_H_
+
diff --git a/src/Bpp/Phyl/Mapping/UniformizationSubstitutionCount.cpp b/src/Bpp/Phyl/Mapping/UniformizationSubstitutionCount.cpp
new file mode 100644
index 0000000..95fec35
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/UniformizationSubstitutionCount.cpp
@@ -0,0 +1,273 @@
+//
+// File: UniformizationSubstitutionCount.cpp
+// Created by: Julien Dutheil
+// Created on: Sat Mar 19 13:54 2011
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "UniformizationSubstitutionCount.h"
+
+#include "Bpp/Numeric/Matrix/MatrixTools.h"
+#include "Bpp/Numeric/NumTools.h"
+#include <vector>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+UniformizationSubstitutionCount::UniformizationSubstitutionCount(const SubstitutionModel* model, SubstitutionRegister* reg, const AlphabetIndex2* weights) :
+  AbstractSubstitutionCount(reg),
+  AbstractWeightedSubstitutionCount(weights, true),
+  model_(model),
+  nbStates_(model->getNumberOfStates()),
+  bMatrices_(reg->getNumberOfSubstitutionTypes()),
+  power_(),
+  s_(reg->getNumberOfSubstitutionTypes()),
+  miu_(0),
+  counts_(reg->getNumberOfSubstitutionTypes()),
+  currentLength_(1.)
+{
+  //Check compatiblity between model and substitution register:
+  if (model->getAlphabet()->getAlphabetType() != reg->getAlphabet()->getAlphabetType())
+    throw Exception("UniformizationSubstitutionCount (constructor): alphabets do not match between register and model.");
+
+  //Initialize all B matrices according to substitution register. This is done once for all,
+  //unless the number of states changes:
+  initBMatrices_();
+  fillBMatrices_();
+
+  for (unsigned int i = 0; i < nbStates_; ++i) {
+    double diagQ = abs(model_->Qij(i, i));
+    if (diagQ > miu_)
+      miu_ = diagQ;
+  }
+}				
+
+/******************************************************************************/
+
+void UniformizationSubstitutionCount::resetBMatrices_()
+{
+  size_t nbTypes = register_->getNumberOfSubstitutionTypes();
+  bMatrices_.resize(nbTypes);
+  counts_.resize(nbTypes);
+  s_.resize(nbTypes);
+}
+
+
+void UniformizationSubstitutionCount::initBMatrices_()
+{
+  //Re-initialize all B matrices according to substitution register.
+  for (unsigned int i = 0; i < register_->getNumberOfSubstitutionTypes(); ++i) {
+    bMatrices_[i].resize(nbStates_, nbStates_);
+    counts_[i].resize(nbStates_, nbStates_);
+  }
+}
+
+void UniformizationSubstitutionCount::fillBMatrices_()
+{
+  int n = static_cast<int>(nbStates_); //Note jdutheil 20/01/13: shoudl be generalized in case sattes are not 0:n !
+  for (int j = 0; j < n; ++j) {
+    for (int k = 0; k < n; ++k) {
+      size_t i = register_->getType(j, k);
+      if (i > 0 && k != j) {
+        bMatrices_[i - 1](j, k) = model_->Qij(j, k) * (weights_ ? weights_->getIndex(j, k) : 1);
+      }
+    }
+  }
+}
+
+
+/******************************************************************************/
+
+void UniformizationSubstitutionCount::computeCounts_(double length) const
+{
+	double lam = miu_ * length;
+	RowMatrix<double> I;
+  MatrixTools::getId(nbStates_, I);
+  RowMatrix<double> R(model_->getGenerator());
+  MatrixTools::scale(R, 1. / miu_);
+  MatrixTools::add(R, I);
+	
+	//compute the stopping point
+	//use the tail of Poisson distribution
+	//can be approximated by 4 + 6 * sqrt(lam) + lam
+	size_t nMax = static_cast<size_t>(ceil(4 + 6 * sqrt(lam) + lam));
+
+	//compute the powers of R
+	power_.resize(nMax + 1);
+	power_[0] = I;
+	for (unsigned int i = 1; i < nMax + 1; ++i)
+		MatrixTools::mult(power_[i - 1], R, power_[i]);
+
+  for (unsigned int i = 0; i < register_->getNumberOfSubstitutionTypes(); ++i) {
+    s_[i].resize(nMax + 1);
+    MatrixTools::mult(bMatrices_[i], power_[0], s_[i][0]);
+    RowMatrix<double> tmp(nbStates_, nbStates_);
+	  for (unsigned int l = 1; l < nMax + 1; ++l) {
+      MatrixTools::mult(R, s_[i][l - 1], s_[i][l]);
+      MatrixTools::mult(bMatrices_[i], power_[l], tmp);
+      MatrixTools::add(s_[i][l], tmp);
+    }
+    MatrixTools::fill(counts_[i], 0);
+	  for (unsigned int l = 0; l < nMax + 1; ++l) {
+      tmp = s_[i][l];
+      //double f = (pow(lam, static_cast<double>(l + 1)) * exp(-lam) / static_cast<double>(NumTools::fact(l + 1))) / miu_;
+      double logF = static_cast<double>(l + 1) * log(lam) - lam - log(miu_) - NumTools::logFact(static_cast<double>(l + 1));
+      MatrixTools::scale(tmp, exp(logF));
+      MatrixTools::add(counts_[i], tmp);
+    }
+  }
+
+  // Now we must divide by pijt:
+  RowMatrix<double> P = model_->getPij_t(length);
+  for (unsigned int i = 0; i < register_->getNumberOfSubstitutionTypes(); i++) {
+    for (unsigned int j = 0; j < nbStates_; j++) {
+      for(unsigned int k = 0; k < nbStates_; k++) {
+        counts_[i](j, k) /= P(j, k);
+        if (isnan(counts_[i](j, k)) || counts_[i](j, k) < 0.)
+          counts_[i](j, k) = 0;
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+Matrix<double>* UniformizationSubstitutionCount::getAllNumbersOfSubstitutions(double length, size_t type) const
+{
+  if (length < 0)
+    throw Exception("UniformizationSubstitutionCount::getAllNumbersOfSubstitutions. Negative branch length: " + TextTools::toString(length) + ".");
+  if (length != currentLength_)
+  {
+    computeCounts_(length);
+    currentLength_ = length;
+  }
+  return new RowMatrix<double>(counts_[type - 1]);
+}
+
+/******************************************************************************/
+
+double UniformizationSubstitutionCount::getNumberOfSubstitutions(int initialState, int finalState, double length, size_t type) const
+{
+  if (length < 0)
+    throw Exception("UniformizationSubstitutionCount::getNumbersOfSubstitutions. Negative branch length: " + TextTools::toString(length) + ".");
+  if (length != currentLength_)
+  {
+    computeCounts_(length);
+    currentLength_ = length;
+  }
+  return counts_[type - 1](initialState, finalState);
+}
+
+/******************************************************************************/
+
+std::vector<double> UniformizationSubstitutionCount::getNumberOfSubstitutionsForEachType(int initialState, int finalState, double length) const
+{
+  if (length < 0)
+    throw Exception("UniformizationSubstitutionCount::getNumbersOfSubstitutions. Negative branch length: " + TextTools::toString(length) + ".");
+  if (length != currentLength_)
+  {
+    computeCounts_(length);
+    currentLength_ = length;
+  }
+  std::vector<double> v(getNumberOfSubstitutionTypes());
+  for (unsigned int t = 0; t < getNumberOfSubstitutionTypes(); ++t) {
+    v[t] = counts_[t](initialState, finalState);
+  }
+  return v;
+}
+    
+/******************************************************************************/
+
+void UniformizationSubstitutionCount::setSubstitutionModel(const SubstitutionModel* model)
+{
+  //Check compatiblity between model and substitution register:
+  if (model->getAlphabet()->getAlphabetType() != register_->getAlphabet()->getAlphabetType())
+    throw Exception("UniformizationSubstitutionCount::setSubstitutionModel: alphabets do not match between register and model.");
+
+  model_ = model;
+  unsigned int n = model->getAlphabet()->getSize();
+  if (n != nbStates_) {
+    nbStates_ = n;
+    //Re-initialize all B matrices according to substitution register.
+    initBMatrices_();
+  }
+  fillBMatrices_();
+	
+  miu_ = 0;
+  for (unsigned int i = 0; i < nbStates_; ++i) {
+    double diagQ = abs(model_->Qij(i, i));
+    if (diagQ > miu_)
+      miu_ = diagQ;
+  }
+
+  //Recompute counts:
+  computeCounts_(currentLength_);
+}
+
+/******************************************************************************/
+
+void UniformizationSubstitutionCount::substitutionRegisterHasChanged() throw (Exception)
+{
+  //Check compatiblity between model and substitution register:
+  if (model_->getAlphabet()->getAlphabetType() != register_->getAlphabet()->getAlphabetType())
+    throw Exception("UniformizationSubstitutionCount::substitutionRegisterHasChanged: alphabets do not match between register and model.");
+
+  resetBMatrices_();
+  initBMatrices_();
+  fillBMatrices_();
+  
+  //Recompute counts:
+  if (currentLength_ > 0)
+    computeCounts_(currentLength_);
+}
+
+/******************************************************************************/
+
+void UniformizationSubstitutionCount::weightsHaveChanged() throw (Exception)
+{
+  if (weights_->getAlphabet()->getAlphabetType() != register_->getAlphabet()->getAlphabetType())
+    throw Exception("UniformizationSubstitutionCount::weightsHaveChanged. Incorrect alphabet type.");
+
+  fillBMatrices_();
+  
+  //Recompute counts:
+  if (currentLength_ > 0)
+    computeCounts_(currentLength_);
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Mapping/UniformizationSubstitutionCount.h b/src/Bpp/Phyl/Mapping/UniformizationSubstitutionCount.h
new file mode 100644
index 0000000..fb26901
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/UniformizationSubstitutionCount.h
@@ -0,0 +1,130 @@
+//
+// File: UniformizationSubstitutionCount.h
+// Created by: Julien Dutheil
+// Created on: Sat Mar 19 13:54 2011
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _UNIFORMIZATIONSUBSTITUTIONCOUNT_H_
+#define _UNIFORMIZATIONSUBSTITUTIONCOUNT_H_
+
+#include "WeightedSubstitutionCount.h"
+
+#include <Bpp/Numeric/Matrix/Matrix.h>
+
+namespace bpp
+{
+
+/**
+ * @brief Analytical (weighted) substitution count using the uniformization method.
+ *
+ * The code is adapted from the original R code by Paula Tataru and Asger Hobolth.
+ *
+ * @author Julien Dutheil
+ */
+class UniformizationSubstitutionCount:
+  public AbstractSubstitutionCount,
+  public AbstractWeightedSubstitutionCount
+{
+	private:
+		const SubstitutionModel* model_;
+    size_t nbStates_;
+    std::vector< RowMatrix<double> > bMatrices_;
+    mutable std::vector< RowMatrix<double> > power_;
+    mutable std::vector < std::vector< RowMatrix<double> > > s_;
+    double miu_;
+    mutable std::vector< RowMatrix<double> > counts_;
+    mutable double currentLength_;
+	
+	public:
+		UniformizationSubstitutionCount(const SubstitutionModel* model, SubstitutionRegister* reg, const AlphabetIndex2* weights = 0);
+		
+    UniformizationSubstitutionCount(const UniformizationSubstitutionCount& usc) :
+      AbstractSubstitutionCount(usc), 
+      AbstractWeightedSubstitutionCount(usc),
+      model_(usc.model_),
+      nbStates_(usc.nbStates_),
+      bMatrices_(usc.bMatrices_),
+      power_(usc.power_),
+      s_(usc.s_),
+      miu_(usc.miu_),
+      counts_(usc.counts_),
+      currentLength_(usc.currentLength_)
+    {}				
+    
+    UniformizationSubstitutionCount& operator=(const UniformizationSubstitutionCount& usc)
+    {
+      AbstractSubstitutionCount::operator=(usc);
+      AbstractWeightedSubstitutionCount::operator=(usc);
+      model_          = usc.model_;
+      nbStates_       = usc.nbStates_;
+      bMatrices_      = usc.bMatrices_;
+      power_          = usc.power_;
+      s_              = usc.s_;
+      miu_            = usc.miu_;
+      counts_         = usc.counts_;
+      currentLength_  = usc.currentLength_;
+      return *this;
+    }				
+		
+    virtual ~UniformizationSubstitutionCount() {}
+		
+    UniformizationSubstitutionCount* clone() const { return new UniformizationSubstitutionCount(*this); }
+
+	public:
+		double getNumberOfSubstitutions(int initialState, int finalState, double length, size_t type = 1) const;
+
+    Matrix<double>* getAllNumbersOfSubstitutions(double length, size_t type = 1) const;
+    
+    std::vector<double> getNumberOfSubstitutionsForEachType(int initialState, int finalState, double length) const;
+   
+    void setSubstitutionModel(const SubstitutionModel* model);
+
+  protected:
+    void computeCounts_(double length) const;
+    void substitutionRegisterHasChanged() throw (Exception);
+    void weightsHaveChanged() throw (Exception);
+
+  private:
+    void resetBMatrices_();
+    void initBMatrices_();
+    void fillBMatrices_();
+
+};
+
+} //end of namespace bpp.
+
+#endif // _UNIFORMIZATIONSUBSTITUTIONCOUNT_H_
+
diff --git a/src/Bpp/Phyl/Mapping/WeightedSubstitutionCount.cpp b/src/Bpp/Phyl/Mapping/WeightedSubstitutionCount.cpp
new file mode 100644
index 0000000..ff44beb
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/WeightedSubstitutionCount.cpp
@@ -0,0 +1,51 @@
+//
+// File: WeightedSubstitutionCount.cpp
+// Created by: Julien Dutheil
+// Created on: Mon Dec 6 21:35 2010
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "WeightedSubstitutionCount.h"
+
+using namespace bpp;
+      
+void AbstractWeightedSubstitutionCount::setWeights(const AlphabetIndex2* weights, bool ownWeights) {
+  if (ownWeights_)
+    delete weights_;
+  weights_ = weights;
+  ownWeights_ = ownWeights;
+  weightsHaveChanged();
+}
+
diff --git a/src/Bpp/Phyl/Mapping/WeightedSubstitutionCount.h b/src/Bpp/Phyl/Mapping/WeightedSubstitutionCount.h
new file mode 100644
index 0000000..8297dbb
--- /dev/null
+++ b/src/Bpp/Phyl/Mapping/WeightedSubstitutionCount.h
@@ -0,0 +1,117 @@
+//
+// File: WeightedSubstitutionCount.h
+// Created by: Julien Dutheil
+// Created on: Wed Apr 5 15:12 2006
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _WEIGHTEDSUBSTITUTIONCOUNT_H_
+#define _WEIGHTEDSUBSTITUTIONCOUNT_H_
+
+#include "SubstitutionCount.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/Alphabet.h>
+#include <Bpp/Seq/AlphabetIndex/AlphabetIndex2.h>
+
+namespace bpp
+{
+
+/**
+ * @brief Interface allowing for weighting of  substitution counts according to state properties.
+ */
+class WeightedSubstitutionCount:
+  public virtual SubstitutionCount
+{
+  public:
+    virtual void setWeights(const AlphabetIndex2* index, bool ownWeights) = 0;
+    virtual bool hasWeights() const = 0;
+    virtual const AlphabetIndex2* getWeights() const = 0;
+};
+
+/**
+ * @brief Partial implementation of the WeightedSubstitutionCount interface.
+ */
+class AbstractWeightedSubstitutionCount:
+  public virtual WeightedSubstitutionCount
+{
+	protected:
+		const AlphabetIndex2* weights_;
+		bool ownWeights_;
+	
+	public:
+		AbstractWeightedSubstitutionCount(const AlphabetIndex2* weights, bool ownWeights) :
+      weights_(weights),
+      ownWeights_(ownWeights)
+    {
+    }
+
+    AbstractWeightedSubstitutionCount(const AbstractWeightedSubstitutionCount& index) :
+      weights_(index.weights_),
+      ownWeights_(index.ownWeights_)
+    {
+      if (ownWeights_)
+        weights_ = dynamic_cast<AlphabetIndex2*>(index.weights_->clone());
+    }
+
+    AbstractWeightedSubstitutionCount& operator=(const AbstractWeightedSubstitutionCount& index)
+    {
+      ownWeights_ = index.ownWeights_;
+      if (ownWeights_) weights_ = dynamic_cast<AlphabetIndex2*>(index.weights_->clone());
+      else weights_ = index.weights_;
+      
+      return *this;
+    }
+		
+		virtual ~AbstractWeightedSubstitutionCount()
+    {
+			if (ownWeights_)
+        delete weights_;
+		}
+		
+  public:
+    void setWeights(const AlphabetIndex2* weights, bool ownWeights);
+    bool hasWeights() const { return weights_ != 0; }
+    const AlphabetIndex2* getWeights() const { return weights_; }
+
+  protected:
+    virtual void weightsHaveChanged() = 0;
+
+};
+
+} //end of namespace bpp.
+
+#endif //_WEIGHTEDSUBSTITUTIONCOUNT_H_
+
diff --git a/src/Bpp/Phyl/Model/AbstractBiblioMixedSubstitutionModel.cpp b/src/Bpp/Phyl/Model/AbstractBiblioMixedSubstitutionModel.cpp
new file mode 100644
index 0000000..0606b4a
--- /dev/null
+++ b/src/Bpp/Phyl/Model/AbstractBiblioMixedSubstitutionModel.cpp
@@ -0,0 +1,76 @@
+//
+// File: AbstractBiblioMixedSubstitutionModel.cpp
+// Created by:  Laurent Gueguen
+// Created on: lundi 18 juillet 2011, à 15h 27
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "AbstractBiblioMixedSubstitutionModel.h"
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+AbstractBiblioMixedSubstitutionModel::AbstractBiblioMixedSubstitutionModel(const std::string& prefix):
+  AbstractBiblioSubstitutionModel(prefix)
+{}
+  
+AbstractBiblioMixedSubstitutionModel::AbstractBiblioMixedSubstitutionModel(const AbstractBiblioMixedSubstitutionModel& mod2) : AbstractBiblioSubstitutionModel(mod2)
+{}
+
+AbstractBiblioMixedSubstitutionModel& AbstractBiblioMixedSubstitutionModel::operator=(const AbstractBiblioMixedSubstitutionModel& mod2)
+{
+  AbstractBiblioSubstitutionModel::operator=(mod2);
+  return *this;
+}
+
+AbstractBiblioMixedSubstitutionModel::~AbstractBiblioMixedSubstitutionModel()
+{}
+
+Vint AbstractBiblioMixedSubstitutionModel::getSubmodelNumbers(std::string& desc) const
+{
+  std::string desc2;
+
+  StringTokenizer st(desc, ",");
+  while (st.hasMoreToken()) {
+    string param = st.nextToken();
+
+    desc2 += getParameterNameWithoutNamespace(param);
+    if (st.hasMoreToken())
+      desc2 += ",";
+  }
+
+  return getMixedModel().getSubmodelNumbers(desc2);
+}
diff --git a/src/Bpp/Phyl/Model/AbstractBiblioMixedSubstitutionModel.h b/src/Bpp/Phyl/Model/AbstractBiblioMixedSubstitutionModel.h
new file mode 100644
index 0000000..cf12ede
--- /dev/null
+++ b/src/Bpp/Phyl/Model/AbstractBiblioMixedSubstitutionModel.h
@@ -0,0 +1,173 @@
+//
+// File: AbstractBiblioMixedSubstitutionModel.h
+// Created by: Laurent Gueguen
+// Created on: lundi 18 juillet 2011, à 15h 17
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _ABSTRACTBIBLIOMIXEDSUBSTITUTIONMODEL_H_
+#define _ABSTRACTBIBLIOMIXEDSUBSTITUTIONMODEL_H_
+
+#include "AbstractBiblioSubstitutionModel.h"
+#include "MixedSubstitutionModel.h"
+
+namespace bpp
+{
+/**
+ * @brief Abstract class for mixture models based on the bibliography.
+ * @author Laurent Guéguen
+ */
+
+class AbstractBiblioMixedSubstitutionModel :
+  public virtual MixedSubstitutionModel,
+  public AbstractBiblioSubstitutionModel
+{
+public:
+  AbstractBiblioMixedSubstitutionModel(const std::string& prefix);
+
+  AbstractBiblioMixedSubstitutionModel(const AbstractBiblioMixedSubstitutionModel& model);
+
+  AbstractBiblioMixedSubstitutionModel& operator=(const AbstractBiblioMixedSubstitutionModel& model);
+
+  virtual ~AbstractBiblioMixedSubstitutionModel();
+
+#ifndef NO_VIRTUAL_COV
+  virtual AbstractBiblioMixedSubstitutionModel* clone() const = 0;
+#endif
+
+public:
+  virtual const MixedSubstitutionModel& getMixedModel() const = 0;
+
+  /*
+     *@brief Returns the submodel from the mixture.
+   *
+   */
+  const SubstitutionModel* getNModel(size_t i) const
+  {
+    return getMixedModel().getNModel(i);
+  }
+
+  SubstitutionModel* getNModel(size_t i)
+  {
+    return getMixedModel().getNModel(i);
+  }
+
+  /**
+   * @brief Returns the  probability of a specific model from the mixture
+   */
+  double getNProbability(size_t i) const
+  {
+    return getMixedModel().getNProbability(i);
+  }
+
+  /**
+   * @brief Returns the vector of the probabilities of the
+   * submodels of the mixture.
+   *
+   */
+
+  const std::vector<double>& getProbabilities() const
+  {
+    return getMixedModel().getProbabilities();
+  }
+
+  /**
+   * @brief Sets the probabilities of the submodels of the mixture.
+   *
+   */
+  void setNProbability(size_t i, double prob)
+  {
+    getMixedModel().setNProbability(i, prob);
+  }
+
+  /**
+   * @brief Returns the number of submodels
+   *
+   */
+  size_t getNumberOfModels() const
+  {
+    return getMixedModel().getNumberOfModels();
+  }
+
+  /**
+   * @brief sets the rates of the submodels.
+   *
+   **/
+  void setVRates(const Vdouble& vd)
+  {
+    getMixedModel().setVRates(vd);
+  }
+
+  /**
+   * @brief normalizes the rates of the submodels.
+   *
+   **/
+  void normalizeVRates()
+  {
+    getMixedModel().normalizeVRates();
+  }
+
+  /**
+   * @brief Returns the vector of all the rates of the mixture
+   */
+
+  const std::vector<double>& getVRates() const
+  {
+    return getMixedModel().getVRates();
+  }
+
+  /**
+   * @brief Returns the rate of a specific model from the mixture
+   */
+  double getNRate(size_t i) const
+  {
+    return getMixedModel().getNRate(i);
+  }
+
+  /*
+     *@brief Returns the vector of numbers of the submodels in the
+     *mixture that match a description.
+   *
+   */
+  Vint getSubmodelNumbers(std::string& desc) const;
+  
+private:
+  virtual MixedSubstitutionModel& getMixedModel() = 0;
+
+};
+} // end of namespace bpp.
+
+#endif  // _AbstractBiblioMixedSubstitutionModel_H_
+
diff --git a/src/Bpp/Phyl/Model/AbstractBiblioSubstitutionModel.cpp b/src/Bpp/Phyl/Model/AbstractBiblioSubstitutionModel.cpp
new file mode 100644
index 0000000..090d054
--- /dev/null
+++ b/src/Bpp/Phyl/Model/AbstractBiblioSubstitutionModel.cpp
@@ -0,0 +1,122 @@
+//
+// File: AbstractBiblioSubstitutionModel.cpp
+// Created by: Laurent Guéguen
+// Created on: lundi 11 juillet 2011, à 21h 12
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "AbstractBiblioSubstitutionModel.h"
+
+using namespace bpp;
+using namespace std;
+
+AbstractBiblioSubstitutionModel::AbstractBiblioSubstitutionModel(const std::string& prefix) : AbstractParameterAliasable(prefix),
+  mapParNamesFromPmodel_(),
+  lParPmodel_()
+{}
+
+/******************************************************************************/
+
+AbstractBiblioSubstitutionModel::AbstractBiblioSubstitutionModel(const AbstractBiblioSubstitutionModel& model) :
+  AbstractParameterAliasable(model),
+  mapParNamesFromPmodel_(model.mapParNamesFromPmodel_),
+  lParPmodel_(model.lParPmodel_)
+{}
+
+/******************************************************************************/
+
+AbstractBiblioSubstitutionModel& AbstractBiblioSubstitutionModel::operator=(const AbstractBiblioSubstitutionModel& model)
+{
+  AbstractParameterAliasable::operator=(model);
+  mapParNamesFromPmodel_ = model.mapParNamesFromPmodel_;
+  lParPmodel_            = model.lParPmodel_;
+  return *this;
+}
+
+/******************************************************************************/
+
+void AbstractBiblioSubstitutionModel::updateMatrices()
+{
+  for (size_t i = 0; i < lParPmodel_.size(); i++)
+  {
+    if (mapParNamesFromPmodel_.find(lParPmodel_[i].getName()) != mapParNamesFromPmodel_.end()) {
+      lParPmodel_[i].setValue(getParameter(getParameterNameWithoutNamespace(mapParNamesFromPmodel_[lParPmodel_[i].getName()])).getValue());
+    }
+  }
+
+  getModel().matchParametersValues(lParPmodel_);
+}
+
+/******************************************************************************/
+
+void AbstractBiblioSubstitutionModel::addRateParameter()
+{
+  getModel().addRateParameter();
+  addParameter_(new Parameter(getNamespace() + "rate", getModel().getRate(), &Parameter::R_PLUS_STAR));
+  mapParNamesFromPmodel_[getNamespace() + "rate"] = "rate";
+  lParPmodel_.reset();
+  lParPmodel_.addParameters(getModel().getParameters());
+}
+
+/******************************************************************************/
+
+void AbstractBiblioSubstitutionModel::setFreq(std::map<int, double>& m)
+{
+  getModel().setFreq(m);
+
+  map<string, string>::iterator it;
+  ParameterList pl;
+  for (it = mapParNamesFromPmodel_.begin(); it != mapParNamesFromPmodel_.end(); it++)
+  {
+    pl.addParameter(Parameter(getNamespace() + it->second, getModel().getParameterValue(getModel().getParameterNameWithoutNamespace(it->first))));
+  }
+
+  matchParametersValues(pl);
+}
+
+
+void AbstractBiblioSubstitutionModel::setFreqFromData(const SequenceContainer& data, double pseudoCount)
+{
+  getModel().setFreqFromData(data, pseudoCount);
+  map<string, string>::iterator it;
+  ParameterList pl;
+  for (it = mapParNamesFromPmodel_.begin(); it != mapParNamesFromPmodel_.end(); it++)
+  {
+    pl.addParameter(Parameter(getNamespace() + it->second, getModel().getParameterValue(getModel().getParameterNameWithoutNamespace(it->first))));
+  }
+
+  matchParametersValues(pl);
+}
+
diff --git a/src/Bpp/Phyl/Model/AbstractBiblioSubstitutionModel.h b/src/Bpp/Phyl/Model/AbstractBiblioSubstitutionModel.h
new file mode 100644
index 0000000..e9cb428
--- /dev/null
+++ b/src/Bpp/Phyl/Model/AbstractBiblioSubstitutionModel.h
@@ -0,0 +1,196 @@
+//
+// File: AbstractBiblioSubstitutionModel.h
+// Created by: Laurent Guéguen
+// Created on: vendredi 8 juillet 2011, à 20h 17
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _ABSTRACTBIBLIOSUBSTITUTIONMODEL_H_
+#define _ABSTRACTBIBLIOSUBSTITUTIONMODEL_H_
+
+#include "SubstitutionModel.h"
+#include "AbstractSubstitutionModel.h"
+
+#include <Bpp/Numeric/AbstractParameterAliasable.h>
+
+namespace bpp
+{
+/**
+ * @brief Partial implementation of the SubstitutionModel interface
+ *   for models that are set for matching the bibliography, and are
+ *   only defined through a link to a "real" model.
+ *
+ */
+
+class AbstractBiblioSubstitutionModel :
+  public virtual SubstitutionModel,
+  public AbstractParameterAliasable
+{
+protected:
+  /**
+   * @brief Tools to make the link between the Parameters of the
+   * object and those of pmixmodel_.
+   *
+   */
+
+  std::map<std::string, std::string> mapParNamesFromPmodel_;
+
+  ParameterList lParPmodel_;
+
+public:
+  AbstractBiblioSubstitutionModel(const std::string& prefix);
+
+  AbstractBiblioSubstitutionModel(const AbstractBiblioSubstitutionModel& model);
+
+  AbstractBiblioSubstitutionModel& operator=(const AbstractBiblioSubstitutionModel& model);
+
+  virtual ~AbstractBiblioSubstitutionModel() {}
+
+#ifndef NO_VIRTUAL_COV
+  virtual AbstractBiblioSubstitutionModel* clone() const = 0;
+#endif
+
+public:
+  virtual const SubstitutionModel& getModel() const = 0;
+
+  /*
+     *@ brief Methods to supersede SubstitutionModel methods.
+   *
+   * @{
+   */
+
+  const std::vector<int>& getAlphabetChars() const { return getModel().getAlphabetChars(); }
+
+  int getAlphabetChar(size_t i) const { return getModel().getAlphabetChar(i); }
+
+  std::vector<size_t> getModelStates(int i) const { return getModel().getModelStates(i); }
+
+  virtual double freq(size_t i) const { return getModel().freq(i); }
+
+  virtual double Qij(size_t i, size_t j) const { return getModel().Qij(i, j); }
+
+  virtual double Pij_t    (size_t i, size_t j, double t) const { return getModel().Pij_t(i, j, t); }
+  virtual double dPij_dt  (size_t i, size_t j, double t) const { return getModel().dPij_dt (i, j, t); }
+  virtual double d2Pij_dt2(size_t i, size_t j, double t) const { return getModel().d2Pij_dt2(i, j, t); }
+
+  virtual const Vdouble& getFrequencies() const { return getModel().getFrequencies(); }
+
+  const Matrix<double>& getGenerator() const { return getModel().getGenerator(); }
+
+  const Matrix<double>& getExchangeabilityMatrix() const { return getModel().getExchangeabilityMatrix(); }
+
+  double Sij(size_t i, size_t j) const { return getModel().Sij(i, j); }
+
+  const Matrix<double>& getPij_t(double t) const { return getModel().getPij_t(t); }
+
+  const Matrix<double>& getdPij_dt(double t) const { return getModel().getdPij_dt(t); }
+
+  const Matrix<double>& getd2Pij_dt2(double t) const { return getModel().getd2Pij_dt2(t); }
+
+  void enableEigenDecomposition(bool yn) { getModel().enableEigenDecomposition(yn); }
+
+  bool enableEigenDecomposition() { return getModel().enableEigenDecomposition(); }
+
+  bool isDiagonalizable() const { return getModel().isDiagonalizable(); }
+
+  bool isNonSingular() const { return getModel().isNonSingular(); }
+
+  const Vdouble& getEigenValues() const { return getModel().getEigenValues(); }
+
+  const Vdouble& getIEigenValues() const { return getModel().getIEigenValues(); }
+
+  const Matrix<double>& getRowLeftEigenVectors() const { return getModel().getRowLeftEigenVectors(); }
+  const Matrix<double>& getColumnRightEigenVectors() const { return getModel().getColumnRightEigenVectors(); }
+
+  double getRate() const { return getModel().getRate(); }
+
+  void setRate(double rate) { return getModel().setRate(rate); }
+
+  void addRateParameter();
+
+  void setFreqFromData(const SequenceContainer& data, double pseudoCount = 0);
+
+  void setFreq(std::map<int, double>& frequ);
+
+  const Alphabet* getAlphabet() const { return getModel().getAlphabet(); }
+
+  size_t getNumberOfStates() const { return getModel().getNumberOfStates(); }
+
+  double getInitValue(size_t i, int state) const throw (BadIntException) { return getModel().getInitValue(i, state); }
+
+  const FrequenciesSet* getFrequenciesSet() const {return getModel().getFrequenciesSet(); }
+
+  /*
+   * @}
+   *
+   */
+
+  /*
+     *@ brief Methods to supersede AbstractSubstitutionModel methods.
+   *
+   * @{
+   */
+
+  /**
+   * @brief Tells the model that a parameter value has changed.
+   *
+   * This updates the matrices consequently.
+   */
+  virtual void fireParameterChanged(const ParameterList& parameters)
+  {
+    AbstractParameterAliasable::fireParameterChanged(parameters);
+    if (parameters.size() > 1 || (parameters.size() == 1 && parameters[0].getName() != getNamespace() + "rate")) {
+      updateMatrices();
+    }
+  }
+
+protected:
+  virtual void updateMatrices();
+  virtual SubstitutionModel& getModel() = 0;
+
+public:
+  double getScale() const { return getModel().getScale(); }
+
+  void setScale(double scale) { getModel().setScale(scale); }
+
+  /*
+   * @}
+   */
+};
+} // end of namespace bpp.
+
+
+#endif  // _ABSTRACTBIBLIOSUBSTITUTIONMODEL_H_
+
diff --git a/src/Bpp/Phyl/Model/AbstractMixedSubstitutionModel.cpp b/src/Bpp/Phyl/Model/AbstractMixedSubstitutionModel.cpp
new file mode 100644
index 0000000..2bcc2dd
--- /dev/null
+++ b/src/Bpp/Phyl/Model/AbstractMixedSubstitutionModel.cpp
@@ -0,0 +1,216 @@
+//
+// File: AbstractMixedSubstitutionModel
+// Created by: Laurent Gueguen
+// On: vendredi 19 novembre 2010, à 15h 55
+//
+
+/*
+  Copyright or © or Copr. CNRS, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "AbstractMixedSubstitutionModel.h"
+
+#include <string>
+
+using namespace bpp;
+using namespace std;
+
+
+AbstractMixedSubstitutionModel::AbstractMixedSubstitutionModel(const Alphabet* alpha,
+                                                               const std::string& prefix): AbstractParameterAliasable(prefix),
+AbstractSubstitutionModel(alpha, prefix),
+                                                                                           modelsContainer_(),
+                                                                                           vProbas_(),
+                                                                                           vRates_()
+{
+  for (unsigned int i=0;i<size_;i++){
+    for (unsigned int j=0; j<size_;j++){
+      generator_(i,j)=0;
+      exchangeability_(i,j)=0;
+      leftEigenVectors_(i,j)=0;
+      rightEigenVectors_(i,j)=0;
+    }
+    eigenValues_[i]=0;
+  }
+  eigenDecompose_=false;
+}
+
+AbstractMixedSubstitutionModel::AbstractMixedSubstitutionModel(const AbstractMixedSubstitutionModel& msm) :
+  AbstractParameterAliasable(msm),
+  AbstractSubstitutionModel(msm),
+  modelsContainer_(),
+  vProbas_(),
+  vRates_()
+{
+  for (unsigned int i = 0; i < msm.modelsContainer_.size(); i++)
+    {
+      modelsContainer_.push_back(msm.modelsContainer_[i]->clone());
+      vProbas_.push_back(msm.vProbas_[i]);
+      vRates_.push_back(msm.vRates_[i]);
+    }
+}
+
+AbstractMixedSubstitutionModel& AbstractMixedSubstitutionModel::operator=(const AbstractMixedSubstitutionModel& model)
+{
+  AbstractParameterAliasable::operator=(model);
+  AbstractSubstitutionModel::operator=(model);
+  
+  //Clear existing containers:
+  modelsContainer_.clear();
+  vProbas_.clear();
+  vRates_.clear();
+  
+  for (unsigned int i = 0; i < model.modelsContainer_.size(); i++)
+    {
+      modelsContainer_.push_back(model.modelsContainer_[i]->clone());
+      vProbas_.push_back(model.vProbas_[i]);
+      vRates_.push_back(model.vRates_[i]);
+    }
+  
+  return *this;
+}
+
+AbstractMixedSubstitutionModel::~AbstractMixedSubstitutionModel()
+{
+  for (unsigned int i = 0; i < modelsContainer_.size(); i++)
+      delete modelsContainer_[i];
+}
+
+size_t AbstractMixedSubstitutionModel::getNumberOfStates() const
+{
+  return modelsContainer_[0]->getNumberOfStates();
+}
+
+const Matrix<double>& AbstractMixedSubstitutionModel::getPij_t(double t) const
+{
+  vector<const Matrix<double>* > vM;
+  double sP=0;
+  for (unsigned int n = 0; n < modelsContainer_.size(); n++){
+    vM.push_back(&modelsContainer_[n]->getPij_t(t));
+    sP+=vProbas_[n];
+  }
+  
+  for (unsigned int i=0; i< getNumberOfStates(); i++)
+    for (unsigned int j=0; j< getNumberOfStates(); j++){
+      double x=0;
+      for (unsigned int n = 0; n < modelsContainer_.size(); n++)
+        x+= (*vM[n])(i,j)*vProbas_[n];
+      pijt_(i,j)=x/sP;
+    }
+  return pijt_;
+}
+
+
+const Matrix<double>& AbstractMixedSubstitutionModel::getdPij_dt(double t) const
+{
+  vector<const Matrix<double>* > vM;
+  double sP=0;
+  for (unsigned int n = 0; n < modelsContainer_.size(); n++){
+    vM.push_back(&modelsContainer_[n]->getdPij_dt(t));
+    sP+=vProbas_[n];
+  }
+  
+  for (unsigned int i=0; i< getNumberOfStates(); i++)
+    for (unsigned int j=0; j< getNumberOfStates(); j++){
+      double x=0;
+      for (unsigned int n = 0; n < modelsContainer_.size(); n++)
+        x+= (*vM[n])(i,j)*vProbas_[n];
+      dpijt_(i,j)=x/sP;
+    }
+  return dpijt_;
+}
+
+
+const Matrix<double>& AbstractMixedSubstitutionModel::getd2Pij_dt2(double t) const
+{
+  vector<const Matrix<double>* > vM;
+  double sP=0;
+  for (unsigned int n = 0; n < modelsContainer_.size(); n++){
+    vM.push_back(&modelsContainer_[n]->getd2Pij_dt2(t));
+    sP+=vProbas_[n];
+  }
+  
+  for (unsigned int i=0; i< getNumberOfStates(); i++)
+    for (unsigned int j=0; j< getNumberOfStates(); j++){
+      double x=0;
+      for (unsigned int n = 0; n < modelsContainer_.size(); n++)
+        x+= (*vM[n])(i,j)*vProbas_[n];
+      d2pijt_(i,j)=x/sP;
+    }
+  return d2pijt_;
+}
+
+
+void AbstractMixedSubstitutionModel::setRate(double rate)
+{
+  AbstractSubstitutionModel::setRate(rate);
+
+  double sum=0;
+  double sP=0;
+  for (unsigned int n = 0; n < modelsContainer_.size(); n++){
+    sum+=vRates_[n]*vProbas_[n];
+    sP+=vProbas_[n];
+  }
+  sum/=sP;
+  
+  for (unsigned int n = 0; n < modelsContainer_.size(); n++){
+    vRates_[n]*=rate_/sum;
+    modelsContainer_[n]->setRate(vRates_[n]);
+  }
+}
+
+void AbstractMixedSubstitutionModel::setVRates(const Vdouble& vd)
+{
+  if (vd.size()!=modelsContainer_.size())
+    throw Exception("AbstractMixedSubstitutionModel::setVRates  bad size of Vdouble argument.");
+
+  for (unsigned int i=0;i<vd.size();i++)
+    vRates_[i]=vd[i];
+ 
+  normalizeVRates();
+}
+
+void AbstractMixedSubstitutionModel::normalizeVRates()
+{
+  double sum=0;
+  double sP=0;
+  for (unsigned int i=0;i<vRates_.size();i++){
+    sum+=vRates_[i]*vProbas_[i];
+    sP+=vProbas_[i];
+  }
+  sum/=sP;
+  
+  for (unsigned int i=0;i<vRates_.size();i++){
+    vRates_[i]*=rate_/sum;
+    modelsContainer_[i]->setRate(vRates_[i]);
+  }
+}
diff --git a/src/Bpp/Phyl/Model/AbstractMixedSubstitutionModel.h b/src/Bpp/Phyl/Model/AbstractMixedSubstitutionModel.h
new file mode 100644
index 0000000..0ab8867
--- /dev/null
+++ b/src/Bpp/Phyl/Model/AbstractMixedSubstitutionModel.h
@@ -0,0 +1,236 @@
+//
+// File: MixedSubstitutionModel.h
+// Created by: Laurent Gueguen
+// On: vendredi 19 novembre 2010, à 15h 48
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _ABSTRACTMIXEDSUBSTITUTIONMODEL_H_
+#define _ABSTRACTMIXEDSUBSTITUTIONMODEL_H_
+
+#include "MixedSubstitutionModel.h"
+#include "AbstractSubstitutionModel.h"
+// #include <Bpp/Seq/Alphabet.all>
+
+#include <vector>
+#include <string>
+#include <map>
+#include <cstring> // C lib for string copy
+
+namespace bpp
+{
+  /**
+   * @brief Partial implementation for Mixed Substitution models,
+   * defined as a mixture of "simple" substitution models. Each model
+   * has a specific probability and rate, with the constraint that the
+   * expectation (on the distribution of the models) of the rate of
+   * all the models equals one.
+   *
+   * In this kind of model, there is no generator.
+   *
+   * @author Laurent Guéguen
+   *
+   */
+
+  class AbstractMixedSubstitutionModel :
+    public virtual MixedSubstitutionModel,
+    public AbstractSubstitutionModel
+  {
+  protected:
+
+    /*
+     * @brief vector of pointers to SubstitutionModels.
+     *
+     * Beware: these SubstitutionModels are owned by the object, so
+     * will be deleted at destruction
+     *
+     */
+    
+    std::vector<SubstitutionModel*> modelsContainer_;
+
+    /*
+     *@brief vector of the probabilities of the models
+     *
+     */
+    
+    std::vector<double> vProbas_;
+
+    /*
+     *@brief vector of the rates of the models.
+     *
+     * For the computation of the transition probabilities, the rates
+     * are included in the submodels while updating the mixture, so
+     * there is no need to multiply here the transition times with the
+     * rates.
+     *
+     * The mean (on the distribution of the models) of the elements of
+     * this vector equals the overall rate of the mixture model, that
+     * is rate_;
+     */
+    
+    std::vector<double> vRates_;
+
+  public:
+
+    AbstractMixedSubstitutionModel(const Alphabet*, const std::string& prefix);
+    
+    AbstractMixedSubstitutionModel(const AbstractMixedSubstitutionModel&);
+  
+    AbstractMixedSubstitutionModel& operator=(const AbstractMixedSubstitutionModel&);
+
+    virtual ~AbstractMixedSubstitutionModel();
+
+    virtual AbstractMixedSubstitutionModel* clone() const = 0;
+
+  public:
+
+    /**
+     * @brief returns the number of models in the mixture
+     */
+    
+    virtual size_t getNumberOfModels() const
+    {
+      return modelsContainer_.size();
+    }
+ 
+    /**
+     * @brief Returns a specific model from the mixture
+     */
+    virtual const SubstitutionModel* getNModel(size_t i) const
+    {
+      return modelsContainer_[i];
+    }
+    
+    virtual SubstitutionModel* getNModel(size_t i)
+    {
+      return modelsContainer_[i];
+    }
+
+    /**
+     * @brief Returns the rate of a specific model from the mixture
+     */
+  
+    double getNRate(size_t i) const
+    {
+      return vRates_[i];
+    }
+  
+    /**
+     * @brief Set the rate of the model and the submodels.
+     * @param rate must be positive.
+     */
+  
+    virtual void setRate(double rate);
+
+    /**
+     * @brief Sets the rates of the submodels to be proportional to a
+     * given vector, with the constraint that the mean rate of the
+     * mixture equals rate_.
+     
+     * @param vd a vector of positive values such that the rates of
+     * the respective submodels are in the same proportions (ie this
+     * vector does not need to be normalized).
+     */
+
+    virtual void setVRates(const Vdouble& vd);
+
+    /**
+     * @brief Normalizes the rates of the submodels so that the mean
+     * rate of the mixture equals rate_.
+     */
+
+    virtual void normalizeVRates();
+
+    /**
+     * @brief Returns the vector of all the rates of the mixture
+     */
+
+    const std::vector<double>& getVRates() const
+    {
+      return vRates_;
+    }
+  
+    /**
+     * @brief Returns the probability of a specific model from the
+     * mixture
+     */
+  
+    virtual double getNProbability(size_t i) const
+    {
+      return vProbas_[i];
+    }
+
+    /**
+     * @brief Returns the vector of probabilities
+     *
+     */
+  
+    virtual const std::vector<double>& getProbabilities() const
+    {
+      return vProbas_;
+    }
+
+    /**
+     * @brief Sets the  probability of a specific model from the mixture
+     */
+  
+    virtual void setNProbability(size_t i, double prob)
+    {
+      if ((prob>=0) && (prob<=1))
+        vProbas_[i]=prob;
+    }
+
+    /**
+     * @brief This function can not be applied here, so it is defined
+     * to prevent wrong usage.
+     */
+    
+    double Qij(size_t i, size_t j) const {return 0;}
+
+    /**
+     * @brief From SubstitutionModel interface
+     *
+     */
+
+    virtual size_t getNumberOfStates() const;
+    
+    virtual const Matrix<double>& getPij_t(double t) const;
+    virtual const Matrix<double>& getdPij_dt(double t) const;
+    virtual const Matrix<double>& getd2Pij_dt2(double t) const;
+
+  };
+} // end of namespace bpp.
+
+#endif  // _ABSTRACTMIXEDSUBSTITUTIONMODEL_H_
diff --git a/src/Bpp/Phyl/Model/AbstractSubstitutionModel.cpp b/src/Bpp/Phyl/Model/AbstractSubstitutionModel.cpp
new file mode 100644
index 0000000..d1c89bd
--- /dev/null
+++ b/src/Bpp/Phyl/Model/AbstractSubstitutionModel.cpp
@@ -0,0 +1,472 @@
+//
+// File: AbstractSubstitutionModel.cpp
+// Created by: Julien Dutheil
+// Created on: Tue May 27 10:31:49 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "AbstractSubstitutionModel.h"
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Numeric/Matrix/EigenValue.h>
+#include <Bpp/Numeric/NumConstants.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+AbstractSubstitutionModel::AbstractSubstitutionModel(const Alphabet* alpha, const std::string& prefix) :
+  AbstractParameterAliasable(prefix),
+  alphabet_(alpha),
+  size_(alpha->getSize()),
+  rate_(1),
+  chars_(size_),
+  generator_(size_, size_),
+  freq_(size_),
+  exchangeability_(size_, size_),
+  pijt_(size_, size_),
+  dpijt_(size_, size_),
+  d2pijt_(size_, size_),
+  eigenDecompose_(true),
+  eigenValues_(size_),
+  iEigenValues_(size_),
+  isDiagonalizable_(false),
+  rightEigenVectors_(size_, size_),
+  isNonSingular_(false),
+  leftEigenVectors_(size_, size_),
+  vPowGen_(),
+  tmpMat_(size_, size_)
+{
+  for (size_t i = 0; i < size_; i++)
+  {
+    freq_[i] = 1.0 / static_cast<double>(size_);
+    chars_[i] = static_cast<int>(i);
+  }
+}
+
+/******************************************************************************/
+
+void AbstractSubstitutionModel::updateMatrices()
+{
+  // if the object is not an AbstractReversibleSubstitutionModel,
+  // computes the exchangeability_ Matrix (otherwise the generator_
+  // has been computed from the exchangeability_)
+
+  if (!dynamic_cast<AbstractReversibleSubstitutionModel*>(this)) {
+    for (size_t i = 0; i < size_; i++)
+    {
+      for (size_t j = 0; j < size_; j++)
+      {
+        exchangeability_(i, j) = generator_(i, j) / freq_[j];
+      }
+    }
+  }
+
+  // Compute eigen values and vectors:
+  if (enableEigenDecomposition())
+  {
+    EigenValue<double> ev(generator_);
+    rightEigenVectors_ = ev.getV();
+    eigenValues_ = ev.getRealEigenValues();
+    iEigenValues_ = ev.getImagEigenValues();
+    try
+    {
+      MatrixTools::inv(rightEigenVectors_, leftEigenVectors_);
+      isNonSingular_ = true;
+      isDiagonalizable_ = true;
+      for (size_t i = 0; i < size_ && isDiagonalizable_; i++)
+      {
+        if (abs(iEigenValues_[i]) > NumConstants::TINY())
+          isDiagonalizable_ = false;
+      }
+    }
+    catch (ZeroDivisionException& e)
+    {
+      ApplicationTools::displayMessage("Singularity during diagonalization. Taylor series used instead.");
+
+      isNonSingular_ = false;
+      isDiagonalizable_ = false;
+      MatrixTools::Taylor(generator_, 30, vPowGen_);
+    }
+  }
+}
+
+
+/******************************************************************************/
+
+const Matrix<double>& AbstractSubstitutionModel::getPij_t(double t) const
+{
+  if (t == 0)
+  {
+    MatrixTools::getId(size_, pijt_);
+  }
+  else if (isNonSingular_)
+  {
+    if (isDiagonalizable_)
+    {
+      MatrixTools::mult<double>(rightEigenVectors_, VectorTools::exp(eigenValues_ * (rate_ * t)), leftEigenVectors_, pijt_);
+    }
+    else
+    {
+      std::vector<double> vdia(size_);
+      std::vector<double> vup(size_ - 1);
+      std::vector<double> vlo(size_ - 1);
+      double c = 0, s = 0;
+      double l = rate_ * t;
+      for (size_t i = 0; i < size_; i++)
+      {
+        vdia[i] = std::exp(eigenValues_[i] * l);
+        if (iEigenValues_[i] != 0)
+        {
+          s = std::sin(iEigenValues_[i] * l);
+          c = std::cos(iEigenValues_[i] * l);
+          vdia[i] *= c;
+          vup[i] = vdia[i] * s;
+          vlo[i] = -vup[i];
+          vdia[i + 1] = vdia[i]; // trick to avoid computation
+          i++;
+        }
+        else
+        {
+          if (i < size_ - 1)
+          {
+            vup[i] = 0;
+            vlo[i] = 0;
+          }
+        }
+      }
+      MatrixTools::mult<double>(rightEigenVectors_, vdia, vup, vlo, leftEigenVectors_, pijt_);
+    }
+  }
+  else
+  {
+    MatrixTools::getId(size_, pijt_);
+    double s = 1.0;
+    double v = rate_ * t;
+    size_t m = 0;
+    while (v > 0.5)    // exp(r*t*A)=(exp(r*t/(2^m) A))^(2^m)
+    {
+      m += 1;
+      v /= 2;
+    }
+    for (size_t i = 1; i < vPowGen_.size(); i++)
+    {
+      s *= v / static_cast<double>(i);
+      MatrixTools::add(pijt_, s, vPowGen_[i]);
+    }
+    while (m > 0)  // recover the 2^m
+    {
+      MatrixTools::mult(pijt_, pijt_, tmpMat_);
+      MatrixTools::copy(tmpMat_, pijt_);
+      m--;
+    }
+  }
+  //MatrixTools::print(pijt_);
+  return pijt_;
+}
+
+const Matrix<double>& AbstractSubstitutionModel::getdPij_dt(double t) const
+{
+  if (isNonSingular_)
+  {
+    if (isDiagonalizable_)
+    {
+      MatrixTools::mult(rightEigenVectors_, rate_ * eigenValues_ * VectorTools::exp(eigenValues_ * (rate_ * t)), leftEigenVectors_, dpijt_);
+    }
+    else
+    {
+      std::vector<double> vdia(size_);
+      std::vector<double> vup(size_ - 1);
+      std::vector<double> vlo(size_ - 1);
+      double c, s, e;
+      double l = rate_ * t;
+      for (size_t i = 0; i < size_; i++)
+      {
+        e = std::exp(eigenValues_[i] * l);
+        if (iEigenValues_[i] != 0)
+        {
+          s = std::sin(iEigenValues_[i] * l);
+          c = std::cos(iEigenValues_[i] * l);
+          vdia[i] = rate_ * (eigenValues_[i] * c - iEigenValues_[i] * s) * e;
+          vup[i] = rate_ * (eigenValues_[i] * s + iEigenValues_[i] * c) * e;
+          vlo[i] = -vup[i];
+          vdia[i + 1] = vdia[i]; // trick to avoid computation
+          i++;
+        }
+        else
+        {
+          if (i < size_ - 1)
+          {
+            vup[i] = 0;
+            vlo[i] = 0;
+          }
+        }
+      }
+      MatrixTools::mult<double>(rightEigenVectors_, vdia, vup, vlo, leftEigenVectors_, dpijt_);
+    }
+  }
+  else
+  {
+    MatrixTools::getId(size_, dpijt_);
+    double s = 1.0;
+    double v = rate_ * t;
+    size_t m = 0;
+    while (v > 0.5)    // r*A*exp(t*r*A)=r*A*(exp(r*t/(2^m) A))^(2^m)
+    {
+      m += 1;
+      v /= 2;
+    }
+    for (size_t i = 1; i < vPowGen_.size(); i++)
+    {
+      s *= v / static_cast<double>(i);
+      MatrixTools::add(dpijt_, s, vPowGen_[i]);
+    }
+    while (m > 0)  // recover the 2^m
+    {
+      MatrixTools::mult(dpijt_, dpijt_, tmpMat_);
+      MatrixTools::copy(tmpMat_, dpijt_);
+      m--;
+    }
+    MatrixTools::scale(dpijt_, rate_);
+    MatrixTools::mult(vPowGen_[1], dpijt_, tmpMat_);
+    MatrixTools::copy(tmpMat_, dpijt_);
+  }
+  return dpijt_;
+}
+
+const Matrix<double>& AbstractSubstitutionModel::getd2Pij_dt2(double t) const
+{
+  if (isNonSingular_)
+  {
+    if (isDiagonalizable_)
+    {
+      MatrixTools::mult(rightEigenVectors_, NumTools::sqr(rate_ * eigenValues_) * VectorTools::exp(eigenValues_ * (rate_ * t)), leftEigenVectors_, d2pijt_);
+    }
+    else
+    {
+      std::vector<double> vdia(size_);
+      std::vector<double> vup(size_ - 1);
+      std::vector<double> vlo(size_ - 1);
+      double c, s, e;
+      double l = rate_ * t;
+      for (size_t i = 0; i < size_; i++)
+      {
+        e = std::exp(eigenValues_[i] * l);
+        if (iEigenValues_[i] != 0)
+        {
+          s = std::sin(iEigenValues_[i] * l);
+          c = std::cos(iEigenValues_[i] * l);
+          vdia[i] = NumTools::sqr(rate_)
+                    * ((NumTools::sqr(eigenValues_[i]) - NumTools::sqr(iEigenValues_[i])) * c
+                       - 2 * eigenValues_[i] * iEigenValues_[i] * s) * e;
+          vup[i] = NumTools::sqr(rate_)
+                   * ((NumTools::sqr(eigenValues_[i]) - NumTools::sqr(iEigenValues_[i])) * s
+                      - 2 * eigenValues_[i] * iEigenValues_[i] * c) * e;
+          vlo[i] = -vup[i];
+          vdia[i + 1] = vdia[i]; // trick to avoid computation
+          i++;
+        }
+        else
+        {
+          if (i < size_ - 1)
+          {
+            vup[i] = 0;
+            vlo[i] = 0;
+          }
+        }
+      }
+      MatrixTools::mult<double>(rightEigenVectors_, vdia, vup, vlo, leftEigenVectors_, d2pijt_);
+    }
+  }
+  else
+  {
+    MatrixTools::getId(size_, d2pijt_);
+    double s = 1.0;
+    double v = rate_ * t;
+    size_t m = 0;
+    while (v > 0.5)    // r^2*A^2*exp(t*r*A)=r^2*A^2*(exp(r*t/(2^m) A))^(2^m)
+    {
+      m += 1;
+      v /= 2;
+    }
+    for (size_t i = 1; i < vPowGen_.size(); i++)
+    {
+      s *= v / static_cast<double>(i);
+      MatrixTools::add(d2pijt_, s, vPowGen_[i]);
+    }
+    while (m > 0)  // recover the 2^m
+    {
+      MatrixTools::mult(d2pijt_, d2pijt_, tmpMat_);
+      MatrixTools::copy(tmpMat_, d2pijt_);
+      m--;
+    }
+    MatrixTools::scale(d2pijt_, rate_ * rate_);
+    MatrixTools::mult(vPowGen_[2], d2pijt_, tmpMat_);
+    MatrixTools::copy(tmpMat_, d2pijt_);
+  }
+  return d2pijt_;
+}
+
+/******************************************************************************/
+
+double AbstractSubstitutionModel::getInitValue(size_t i, int state) const throw (IndexOutOfBoundsException, BadIntException)
+{
+  if (i >= size_)
+    throw IndexOutOfBoundsException("AbstractSubstitutionModel::getInitValue", i, 0, size_ - 1);
+  if (state < 0 || !alphabet_->isIntInAlphabet(state))
+    throw BadIntException(state, "AbstractSubstitutionModel::getInitValue. Character " + alphabet_->intToChar(state) + " is not allowed in model.");
+  vector<int> states = alphabet_->getAlias(state);
+  for (size_t j = 0; j < states.size(); j++)
+  {
+    if (getAlphabetChar(i) == states[j])
+      return 1.;
+  }
+  return 0.;
+}
+
+/******************************************************************************/
+
+void AbstractSubstitutionModel::setFreqFromData(const SequenceContainer& data, double pseudoCount)
+{
+  map<int, int> counts;
+  SequenceContainerTools::getCounts(data, counts);
+  double t = 0;
+  map<int, double> freqs;
+
+  for (int i = 0; i < static_cast<int>(size_); i++)
+  {
+    t += counts[i] + pseudoCount;
+  }
+  for (int i = 0; i < static_cast<int>(size_); i++)
+  {
+    freqs[i] = (static_cast<double>(counts[i]) + pseudoCount) / t;
+  }
+
+  // Re-compute generator and eigen values:
+  setFreq(freqs);
+}
+
+/******************************************************************************/
+
+void AbstractSubstitutionModel::setFreq(map<int, double>& freqs)
+{
+  for (int i = 0; i < static_cast<int>(size_); i++)
+  {
+    freq_[i] = freqs[i];
+  }
+  // Re-compute generator and eigen values:
+  updateMatrices();
+}
+
+/******************************************************************************/
+
+double AbstractSubstitutionModel::getScale() const
+{
+  vector<double> v;
+  MatrixTools::diag(generator_, v);
+  return -VectorTools::scalar<double, double>(v, freq_);
+}
+
+/******************************************************************************/
+
+void AbstractSubstitutionModel::setScale(double scale) {
+  MatrixTools::scale(generator_, scale);
+}
+
+/******************************************************************************/
+
+double AbstractSubstitutionModel::getRate() const
+{
+  return rate_;
+}
+
+/******************************************************************************/
+
+void AbstractSubstitutionModel::setRate(double rate)
+{
+  if (rate <= 0)
+    throw Exception("Bad value for rate: " + TextTools::toString(rate));
+
+  if (hasParameter("rate"))
+    setParameterValue("rate", rate_);
+
+  rate_ = rate;
+}
+
+void AbstractSubstitutionModel::addRateParameter()
+{
+  addParameter_(new Parameter(getNamespace() + "rate", rate_, &Parameter::R_PLUS_STAR));
+}
+
+/******************************************************************************/
+
+void AbstractReversibleSubstitutionModel::updateMatrices()
+{
+  RowMatrix<double> Pi;
+  MatrixTools::diag(freq_, Pi);
+  MatrixTools::mult(exchangeability_, Pi, generator_); // Diagonal elements of the exchangability matrix will be ignored.
+  // Compute diagonal elements of the generator:
+  for (size_t i = 0; i < size_; i++)
+  {
+    double lambda = 0;
+    for (size_t j = 0; j < size_; j++)
+    {
+      if (j != i)
+        lambda += generator_(i, j);
+    }
+    generator_(i, i) = -lambda;
+  }
+  // Normalization:
+  double scale = getScale();
+  MatrixTools::scale(generator_, 1. / scale);
+
+  // Normalize exchangeability matrix too:
+  MatrixTools::scale(exchangeability_, 1. / scale);
+  // Compute diagonal elements of the exchangeability matrix:
+  for (size_t i = 0; i < size_; i++)
+  {
+    exchangeability_(i, i) = generator_(i, i) / freq_[i];
+  }
+  AbstractSubstitutionModel::updateMatrices();
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/AbstractSubstitutionModel.h b/src/Bpp/Phyl/Model/AbstractSubstitutionModel.h
new file mode 100755
index 0000000..a684e74
--- /dev/null
+++ b/src/Bpp/Phyl/Model/AbstractSubstitutionModel.h
@@ -0,0 +1,412 @@
+//
+// File: AbstractSubstitutionModel.h
+// Created by: Julien Dutheil
+// Created on: Tue May 27 10:31:49 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _ABSTRACTSUBSTITUTIONMODEL_H_
+#define _ABSTRACTSUBSTITUTIONMODEL_H_
+
+#include "SubstitutionModel.h"
+
+#include <Bpp/Numeric/AbstractParameterAliasable.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+namespace bpp
+{
+/**
+ * @brief Partial implementation of the SubstitutionModel interface.
+ *
+ * This abstract class provides some fields, namely:
+ * - alphabet_: a pointer toward the alphabet,
+ * - size_: the size of the alphabet, a parameter frequently called during various computations,
+ * - rate_: the rate of the model
+ * - generator_, leftEigenVectors_, rightEigenVectors_: useful matrices,
+ * - eigenValues_, iEigenValues_, freq_: useful vectors.
+ * - isDiagonalizable_ : boolean value useful for computation of the exponential
+ *
+ * Access methods for these fields are implemented.
+ *
+ * This class also provides the updateMatrices() method, which computes eigen values and vectors and fills the corresponding vector (eigenValues_)
+ * and matrices (leftEigenVectors_ and rightEigenVectors_) from the generator.
+ *
+ * The freq_ vector and generator_ matrices are hence the only things to provide to
+ * create a substitution model.
+ * It is also possible to redefine one of these methods for better efficiency.
+ * The Pij_t, dPij_dt and d2Pij_dt2 are particularly inefficient since the matrix formula
+ * is used to compute all probabilities, and then the result for the initial and final state
+ * of interest is retrieved.
+ *
+ * @note This class is dedicated to "simple" substitution models, for which the number of states is equivalent to the number of characters in the alphabet.
+ * Consider using the MarkovModulatedSubstitutionModel for more complexe cases.
+ */
+class AbstractSubstitutionModel :
+  public virtual SubstitutionModel,
+  public virtual AbstractParameterAliasable
+{
+protected:
+  /**
+   * @brief The alphabet relevant to this model.
+   */
+  const Alphabet* alphabet_;
+
+  /**
+   * @brief The size of the generator, i.e. the number of states.
+   */
+  size_t size_;
+
+  /**
+   * @brief The rate of the model (default: 1). The generator (and all
+   * its vectorial components) is independent of the rate, since it
+   * should be normalized.
+   */
+  
+  double rate_;
+
+  /**
+   * @brief The list of supported chars.
+   */
+  std::vector<int> chars_;
+
+  /**
+   * @brief The generator matrix \f$Q\f$ of the model.
+   */
+  RowMatrix<double> generator_;
+
+  /**
+   * @brief The vector \f$\pi_e\f$ of equilibrium frequencies.
+   */
+
+  Vdouble freq_;
+
+  /**
+   * @brief The exchangeability matrix \f$S\f$ of the model, defined
+   * as \f$ S_{ij}=\frac{Q_{ij}}{\pi_j}\f$. When the model is
+   * reversible, this matrix is symetric.
+   *
+   */
+  
+  RowMatrix<double> exchangeability_;
+
+  /**
+   * @brief These ones are for bookkeeping:
+   */
+  mutable RowMatrix<double> pijt_;
+  mutable RowMatrix<double> dpijt_;
+  mutable RowMatrix<double> d2pijt_;
+
+  /**
+   * @brief Tell if the eigen decomposition should be performed.
+   */
+  bool eigenDecompose_;
+
+  /**
+   * @brief The vector of eigen values.
+   */
+  Vdouble eigenValues_;
+
+  /**
+   * @brief The vector of the imaginary part of the eigen values.
+   */
+  Vdouble iEigenValues_;
+
+  /**
+   * @brief boolean value for diagonalizability in R of the generator_
+   */
+  
+  bool isDiagonalizable_;
+
+  /**
+   * @brief The \f$U^-1\f$ matrix made of right eigen vectors (by column).
+   */
+  RowMatrix<double> rightEigenVectors_;
+
+  /**
+   * @brief boolean value for non-singularity of rightEigenVectors_
+   */
+  
+  bool isNonSingular_;
+
+  /**
+   * @brief The \f$U\f$ matrix made of left eigen vectors (by row) if
+   * rightEigenVectors_ is non-singular.
+   */
+  
+  RowMatrix<double> leftEigenVectors_;
+
+  /**
+   * @brief vector of the powers of generator_ for Taylor development (if
+   * rightEigenVectors_ is singular).
+   */
+
+  std::vector< RowMatrix<double> > vPowGen_;
+
+  /**
+   * @brief For computational issues
+   *
+   */
+
+  mutable RowMatrix<double> tmpMat_;
+  
+public:
+  AbstractSubstitutionModel(const Alphabet* alpha, const std::string& prefix);
+
+  AbstractSubstitutionModel(const AbstractSubstitutionModel& model) :
+    AbstractParameterAliasable(model),
+    alphabet_(model.alphabet_),
+    size_(model.size_),
+    rate_(model.rate_),
+    chars_(model.chars_),
+    generator_(model.generator_),
+    freq_(model.freq_),
+    exchangeability_(model.exchangeability_),
+    pijt_(model.pijt_),
+    dpijt_(model.dpijt_),
+    d2pijt_(model.d2pijt_),
+    eigenDecompose_(model.eigenDecompose_),
+    eigenValues_(model.eigenValues_),
+    iEigenValues_(model.iEigenValues_),
+    isDiagonalizable_(model.isDiagonalizable_),
+    rightEigenVectors_(model.rightEigenVectors_),
+    isNonSingular_(model.isNonSingular_),
+    leftEigenVectors_(model.leftEigenVectors_),
+    vPowGen_(model.vPowGen_),
+    tmpMat_(model.tmpMat_)
+  {}
+
+  AbstractSubstitutionModel& operator=(const AbstractSubstitutionModel& model)
+  {
+    AbstractParameterAliasable::operator=(model);
+    alphabet_          = model.alphabet_;
+    size_              = model.size_;
+    rate_              = model.rate_;
+    chars_             = model.chars_;
+    generator_         = model.generator_;
+    freq_              = model.freq_;
+    exchangeability_   = model.exchangeability_;
+    pijt_              = model.pijt_;
+    dpijt_             = model.dpijt_;
+    d2pijt_            = model.d2pijt_;
+    eigenDecompose_    = model.eigenDecompose_;
+    eigenValues_       = model.eigenValues_;
+    iEigenValues_      = model.iEigenValues_;
+    isDiagonalizable_  = model.isDiagonalizable_;
+    rightEigenVectors_ = model.rightEigenVectors_;
+    isNonSingular_     = model.isNonSingular_;
+    leftEigenVectors_  = model.leftEigenVectors_;
+    vPowGen_           = model.vPowGen_;
+    tmpMat_            = model.tmpMat_;
+    return *this;
+  }
+  
+  virtual ~AbstractSubstitutionModel() {}
+
+#ifndef NO_VIRTUAL_COV
+  virtual AbstractSubstitutionModel* clone() const = 0;
+#endif
+
+public:
+  const Alphabet* getAlphabet() const { return alphabet_; }
+
+  const std::vector<int>& getAlphabetChars() const { return chars_; }
+
+  int getAlphabetChar(size_t i) const { return chars_[i]; }
+
+  std::vector<size_t> getModelStates(int i) const { return VectorTools::whichAll(chars_, i); }
+
+  virtual const Vdouble& getFrequencies() const { return freq_; }
+
+  const Matrix<double>& getGenerator() const { return generator_; }
+
+  const Matrix<double>& getExchangeabilityMatrix() const { return exchangeability_; }
+
+  double Sij(size_t i, size_t j) const { return exchangeability_(i, j); }
+
+  virtual const Matrix<double>& getPij_t(double t) const;
+  virtual const Matrix<double>& getdPij_dt(double t) const;
+  virtual const Matrix<double>& getd2Pij_dt2(double t) const;
+
+  const Vdouble& getEigenValues() const { return eigenValues_; }
+
+  const Vdouble& getIEigenValues() const { return iEigenValues_; }
+
+  bool isDiagonalizable() const { return isDiagonalizable_; }
+  
+  bool isNonSingular() const { return isNonSingular_; }
+
+  const Matrix<double>& getRowLeftEigenVectors() const { return leftEigenVectors_; }
+
+  const Matrix<double>& getColumnRightEigenVectors() const { return rightEigenVectors_; }
+
+  virtual double freq(size_t i) const { return freq_[i]; }
+
+  virtual double Qij(size_t i, size_t j) const { return generator_(i, j); }
+
+  virtual double Pij_t    (size_t i, size_t j, double t) const { return getPij_t(t) (i, j); }
+  virtual double dPij_dt  (size_t i, size_t j, double t) const { return getdPij_dt(t) (i, j); }
+  virtual double d2Pij_dt2(size_t i, size_t j, double t) const { return getd2Pij_dt2(t) (i, j); }
+
+  double getInitValue(size_t i, int state) const throw (IndexOutOfBoundsException, BadIntException);
+
+  void setFreqFromData(const SequenceContainer& data, double pseudoCount = 0);
+
+  virtual void setFreq(std::map<int, double>&);
+
+  void enableEigenDecomposition(bool yn) { eigenDecompose_ = yn; }
+
+  bool enableEigenDecomposition() { return eigenDecompose_; }
+
+  /**
+   * @brief Tells the model that a parameter value has changed.
+   *
+   * This updates the matrices consequently.
+   */
+  virtual void fireParameterChanged(const ParameterList& parameters)
+  {
+    AbstractParameterAliasable::fireParameterChanged(parameters);
+    if ((parameters.size()!=1) || (parameters[0].getName()!=getNamespace()+"rate"))
+      updateMatrices();
+  }
+
+  void addRateParameter();
+
+protected:
+  /**
+   * @brief Diagonalize the \f$Q\f$ matrix, and fill the eigenValues_, iEigenValues_, 
+   * leftEigenVectors_ and rightEigenVectors_ matrices.
+   *
+   * The generator_ matrix and freq_ vector must be initialized.
+   *
+   * Eigen values and vectors are computed from the generator and
+   * assigned to the eigenValues_ for the real part, iEigenValues_ for
+   * the imaginary part, rightEigenVectors_ and leftEigenVectors_
+   * variables. isDiagonalizable_ checks if the generator_ is
+   * diagonalizable in R.
+   *
+   * The optional rate parameter is not taken into account in this
+   * method to prevent unnecessary computation.
+   */
+  
+  virtual void updateMatrices();
+
+public:
+  double getScale() const;
+
+  void setScale(double scale);
+
+  virtual double getRate() const;
+
+  virtual void setRate(double rate);
+
+
+  friend class AbstractBiblioSubstitutionModel;
+
+};
+
+
+/**
+ * @brief Partial implementation of the ReversibleSubstitutionModel interface.
+ *
+ * This class overrides the updateMatrices() method, which updates the
+ * generator_ matrix from the exchangeability_ matrix and freq_
+ * vector. It then computes eigen values and vectors and fills the
+ * corresponding vector (eigenValues_) and matrices (leftEigenVectors_
+ * and rightEigenVectors_). Because of reversibility,
+ * isDiagonalizable_ is set to true.
+ *
+ * The freq_ vector and exchangeability_ matrices are hence the only
+ * things to provide to create a substitution model. It is also
+ * possible to redefine one of these methods for better efficiency.
+ * The Pij_t, dPij_dt and d2Pij_dt2 are particularly inefficient since
+ * the matrix formula is used to compute all probabilities, and then
+ * the result for the initial and final state of interest is
+ * retrieved.
+ *
+ * @note This class is dedicated to "simple" substitution models, for
+ * which the number of states is equivalent to the number of
+ * characters in the alphabet. Consider using the
+ * MarkovModulatedSubstitutionModel for more complexe cases.
+ */
+  
+class AbstractReversibleSubstitutionModel :
+  public virtual AbstractSubstitutionModel,
+  public virtual ReversibleSubstitutionModel
+{
+public:
+  AbstractReversibleSubstitutionModel(const Alphabet* alpha, const std::string& prefix) :
+    AbstractParameterAliasable(prefix),
+    AbstractSubstitutionModel(alpha, prefix)
+  {
+    isDiagonalizable_ = true;
+    isNonSingular_    = true;
+  }
+
+  virtual ~AbstractReversibleSubstitutionModel() {}
+
+#ifndef NO_VIRTUAL_COV
+  virtual AbstractReversibleSubstitutionModel* clone() const = 0;
+#endif
+
+protected:
+
+  /**
+   * @brief Compute and diagonalize the \f$Q\f$ matrix, and fill the eigenValues_,
+   * leftEigenVectors_ and rightEigenVectors_ matrices.
+   *
+   * The exchangeability_ matrix and freq_ vector must be initialized.
+   * This function computes the generator_ matrix with the formula
+   * \f[
+   * Q = S \times \pi
+   * \f]
+   * where \f$Q\f$ is the generator matrix, \f$S\f$ is the exchangeability matrix and
+   * \f$Pi\f$ the diagonal matrix with frequencies.
+   *
+   * The generator is then scaled so that
+   * \f[
+   * \sum_i Q_{i,i} \times \pi_i = -1
+   * \f]
+   * (\f$\pi_i\f$ are the equilibrium frequencies).
+   *
+   * Eigen values and vectors are computed from the scaled generator and assigned to the
+   * eigenValues_, rightEigenVectors_ and leftEigenVectors_ variables.
+   */
+  virtual void updateMatrices();
+};
+
+} //end of namespace bpp.
+
+#endif  //_ABSTRACTSUBSTITUTIONMODEL_H_
+
diff --git a/src/Bpp/Phyl/Model/AbstractWordSubstitutionModel.cpp b/src/Bpp/Phyl/Model/AbstractWordSubstitutionModel.cpp
new file mode 100644
index 0000000..8de2a8d
--- /dev/null
+++ b/src/Bpp/Phyl/Model/AbstractWordSubstitutionModel.cpp
@@ -0,0 +1,665 @@
+//
+// File: AbstractWordSubstitutionModel.cpp
+// Created by:  Laurent Gueguen
+// Created on: Jan 2009
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "AbstractWordSubstitutionModel.h"
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Numeric/Matrix/EigenValue.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/WordAlphabet.h>
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+#include <Bpp/App/ApplicationTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <cmath>
+#include <complex>
+
+using namespace std;
+
+/******************************************************************************/
+
+AbstractWordSubstitutionModel::AbstractWordSubstitutionModel(
+  const std::vector<SubstitutionModel*>& modelVector,
+  const std::string& st) :
+  AbstractParameterAliasable(st),
+  AbstractSubstitutionModel(AbstractWordSubstitutionModel::extractAlph(modelVector), st),
+  new_alphabet_ (true),
+  VSubMod_      (),
+  VnestedPrefix_(),
+  Vrate_         (modelVector.size())
+{
+  enableEigenDecomposition(false);
+  size_t i, j;
+  size_t n = modelVector.size();
+
+  // test whether two models are identical
+
+  bool flag = 0;
+  i = 0;
+  j = 1;
+  while (!flag && i < (n - 1))
+  {
+    if (modelVector[i] == modelVector[j])
+      flag = 1;
+    else
+    {
+      j++;
+      if (j == n)
+      {
+        i++;
+        j = i + 1;
+      }
+    }
+  }
+
+  if (!flag)
+  {
+    for (i = 0; i < n; i++)
+    {
+      VSubMod_.push_back(modelVector[i]);
+      VnestedPrefix_.push_back(modelVector[i]->getNamespace());
+      VSubMod_[i]->setNamespace(st + TextTools::toString(i + 1) + "_" + VnestedPrefix_[i]);
+      addParameters_(VSubMod_[i]->getParameters());
+    }
+  }
+  else
+  {
+    string t = "";
+    for (i = 0; i < n; i++)
+    {
+      VSubMod_.push_back(modelVector[0]);
+      VnestedPrefix_.push_back(modelVector[0]->getNamespace());
+      t += TextTools::toString(i + 1);
+    }
+    VSubMod_[0]->setNamespace(st + t + "_" + VnestedPrefix_[0]);
+    addParameters_(VSubMod_[0]->getParameters());
+  }
+
+  for (i = 0; i < n; i++)
+  {
+    Vrate_[i] = 1.0 / static_cast<double>(n);
+  }
+}
+
+AbstractWordSubstitutionModel::AbstractWordSubstitutionModel(
+  const Alphabet* alph,
+  const std::string& st) :
+  AbstractParameterAliasable(st),
+  AbstractSubstitutionModel(alph, st),
+  new_alphabet_ (false),
+  VSubMod_      (),
+  VnestedPrefix_(),
+  Vrate_         (0)
+{
+  enableEigenDecomposition(false);
+}
+
+AbstractWordSubstitutionModel::AbstractWordSubstitutionModel(
+  SubstitutionModel* pmodel,
+  unsigned int num,
+  const std::string& st) :
+  AbstractParameterAliasable(st),
+  AbstractSubstitutionModel(new WordAlphabet(pmodel->getAlphabet(), num), st),
+  new_alphabet_ (true),
+  VSubMod_      (),
+  VnestedPrefix_(),
+  Vrate_         (num)
+{
+  enableEigenDecomposition(false);
+  size_t i;
+
+  string t = "";
+  for (i = 0; i < num; i++)
+  {
+    VSubMod_.push_back(pmodel);
+    VnestedPrefix_.push_back(pmodel->getNamespace());
+    Vrate_[i] = 1.0 / num;
+    t += TextTools::toString(i + 1);
+  }
+
+  pmodel->setNamespace(st + t + "_" + VnestedPrefix_[0]);
+  addParameters_(pmodel->getParameters());
+}
+
+AbstractWordSubstitutionModel::AbstractWordSubstitutionModel(
+  const AbstractWordSubstitutionModel& wrsm) :
+  AbstractParameterAliasable(wrsm),
+  AbstractSubstitutionModel(wrsm),
+  new_alphabet_ (wrsm.new_alphabet_),
+  VSubMod_      (),
+  VnestedPrefix_(wrsm.VnestedPrefix_),
+  Vrate_         (wrsm.Vrate_)
+{
+  size_t i;
+  size_t num = wrsm.VSubMod_.size();
+
+  if (wrsm.new_alphabet_)
+    alphabet_ = new WordAlphabet(*(dynamic_cast<const WordAlphabet*>(wrsm.getAlphabet())));
+
+  SubstitutionModel* pSM = 0;
+  if ((num > 1) & (wrsm.VSubMod_[0] == wrsm.VSubMod_[1]))
+    pSM = wrsm.VSubMod_[0]->clone();
+
+  for (i = 0; i < num; i++)
+  {
+    VSubMod_.push_back(pSM ? pSM : wrsm.VSubMod_[i]->clone());
+  }
+}
+
+AbstractWordSubstitutionModel& AbstractWordSubstitutionModel::operator=(
+  const AbstractWordSubstitutionModel& model)
+{
+  AbstractParameterAliasable::operator=(model);
+  AbstractSubstitutionModel::operator=(model);
+  new_alphabet_  = model.new_alphabet_;
+  VnestedPrefix_ = model.VnestedPrefix_;
+  Vrate_         = model.Vrate_;
+
+  size_t i;
+  size_t num = model.VSubMod_.size();
+
+  if (model.new_alphabet_)
+    alphabet_ = new WordAlphabet(*(dynamic_cast<const WordAlphabet*>(model.getAlphabet())));
+
+  SubstitutionModel* pSM = 0;
+  if ((num > 1) & (model.VSubMod_[0] == model.VSubMod_[1]))
+    pSM = model.VSubMod_[0]->clone();
+
+  for (i = 0; i < num; i++)
+  {
+    VSubMod_[i] =  (pSM ? pSM : model.VSubMod_[i]->clone());
+  }
+
+  return *this;
+}
+
+AbstractWordSubstitutionModel::~AbstractWordSubstitutionModel()
+{
+  if ((VSubMod_.size() > 1) && (VSubMod_[0] == VSubMod_[1]))
+  {
+    if (VSubMod_[0])
+      delete VSubMod_[0];
+  }
+  else
+    for (size_t i = 0; i < VSubMod_.size(); i++)
+    {
+      if (VSubMod_[i])
+        delete VSubMod_[i];
+    }
+  if (new_alphabet_)
+    delete alphabet_;
+}
+
+size_t AbstractWordSubstitutionModel::getNumberOfStates() const
+{
+  return getAlphabet()->getSize();
+}
+
+Alphabet* AbstractWordSubstitutionModel::extractAlph(const vector<SubstitutionModel*>& modelVector)
+{
+  size_t i;
+
+  vector<const Alphabet*> vAlph;
+
+  for (i = 0; i < modelVector.size(); i++)
+  {
+    vAlph.push_back(modelVector[i]->getAlphabet());
+  }
+
+  return new WordAlphabet(vAlph);
+}
+
+void AbstractWordSubstitutionModel::setNamespace(const std::string& prefix)
+{
+  AbstractSubstitutionModel::setNamespace(prefix);
+
+  if (VSubMod_.size() < 2 || VSubMod_[0] == VSubMod_[1])
+  {
+    string t = "";
+    for (size_t i = 0; i < VSubMod_.size(); i++)
+    {
+      t += TextTools::toString(i + 1);
+    }
+    VSubMod_[0]->setNamespace(prefix + t + "_" + VnestedPrefix_[0]);
+  }
+  else
+  {
+    for (size_t i = 0; i < VSubMod_.size(); i++)
+    {
+      VSubMod_[i]->setNamespace(prefix + TextTools::toString(i + 1) + "_" + VnestedPrefix_[i]);
+    }
+  }
+}
+
+/******************************************************************************/
+
+void AbstractWordSubstitutionModel::updateMatrices()
+{
+  // First we update position specific models. This need to be done
+  // here and not in fireParameterChanged, as some parameter aliases
+  // might have been defined and need to be resolved first.
+  if (VSubMod_.size() < 2 || VSubMod_[0] == VSubMod_[1])
+    VSubMod_[0]->matchParametersValues(getParameters());
+  else
+    for (size_t i = 0; i < VSubMod_.size(); i++)
+    {
+      VSubMod_[i]->matchParametersValues(getParameters());
+    }
+
+  size_t nbmod = VSubMod_.size();
+  size_t salph = getNumberOfStates();
+  size_t nbStop = 0;
+  vector<bool> vnull; // vector of the indices of lines with only zeros
+
+  // Generator
+
+  if (enableEigenDecomposition())
+  {
+    size_t i, j, n, l, k, m;
+
+    vector<size_t> vsize;
+
+    for (k = 0; k < nbmod; k++)
+    {
+      vsize.push_back(VSubMod_[k]->getNumberOfStates());
+    }
+
+    RowMatrix<double> gk, exch;
+
+    m = 1;
+
+    for (k = nbmod; k > 0; k--)
+    {
+      gk = VSubMod_[k - 1]->getGenerator();
+      for (i = 0; i < vsize[k - 1]; i++)
+      {
+        for (j = 0; j < vsize[k - 1]; j++)
+        {
+          if (i != j)
+          {
+            n = 0;
+            while (n < salph)
+            { // loop on prefix
+              for (l = 0; l < m; l++)
+              { // loop on suffix
+                generator_(n + i * m + l, n + j * m + l) = gk(i, j) * Vrate_[k - 1];
+              }
+              n += m * vsize[k - 1];
+            }
+          }
+        }
+      }
+      m *= vsize[k - 1];
+    }
+  }
+
+  // modification of generator_ and freq_
+
+  completeMatrices();
+
+  size_t i, j;
+  double x;
+
+  for (i = 0; i < salph; i++)
+  {
+    x = 0;
+    for (j = 0; j < salph; j++)
+    {
+      if (j != i)
+        x += generator_(i, j);
+    }
+    generator_(i, i) = -x;
+  }
+
+  // at that point generator_ and freq_ are done for models without
+  // enableEigenDecomposition
+
+  // Eigen values:
+
+  if (enableEigenDecomposition())
+  {
+    for (i = 0; i < salph; i++)
+    {
+      bool flag = true;
+      for (j = 0; j < salph; j++)
+      {
+        if ((i != j) && abs(generator_(i, j)) > NumConstants::TINY())
+        {
+          flag = false;
+          break;
+        }
+      }
+      if (flag)
+        nbStop++;
+      vnull.push_back(flag);
+    }
+
+    if (nbStop != 0)
+    {
+      int gi = 0, gj = 0;
+
+      RowMatrix<double> gk;
+
+      gk.resize(salph - nbStop, salph - nbStop);
+      for (i = 0; i < salph; i++)
+      {
+        if (!vnull[i])
+        {
+          gj = 0;
+          for (j = 0; j < salph; j++)
+          {
+            if (!vnull[j])
+            {
+              gk(i - gi, j - gj) = generator_(i, j);
+            }
+            else
+              gj++;
+          }
+        }
+        else
+          gi++;
+      }
+
+      EigenValue<double> ev(gk);
+      eigenValues_ = ev.getRealEigenValues();
+      iEigenValues_ = ev.getImagEigenValues();
+
+      for (i = 0; i < nbStop; i++)
+      {
+        eigenValues_.push_back(0);
+        iEigenValues_.push_back(0);
+      }
+
+      RowMatrix<double> rev = ev.getV();
+      rightEigenVectors_.resize(salph, salph);
+      gi = 0;
+      for (i = 0; i < salph; i++)
+      {
+        if (vnull[i])
+        {
+          gi++;
+          for (j = 0; j < salph; j++)
+          {
+            rightEigenVectors_(i, j) = 0;
+          }
+
+          rightEigenVectors_(i, salph - nbStop + gi - 1) = 1;
+        }
+        else
+        {
+          for (j = 0; j < salph - nbStop; j++)
+          {
+            rightEigenVectors_(i, j) = rev(i - gi, j);
+          }
+
+          for (j = salph - nbStop; j < salph; j++)
+          {
+            rightEigenVectors_(i, j) = 0;
+          }
+        }
+      }
+    }
+    else
+    {
+      EigenValue<double> ev(generator_);
+      eigenValues_ = ev.getRealEigenValues();
+      iEigenValues_ = ev.getImagEigenValues();
+      rightEigenVectors_ = ev.getV();
+      nbStop = 0;
+    }
+
+    try
+    {
+      MatrixTools::inv(rightEigenVectors_, leftEigenVectors_);
+
+      // is it diagonalizable ?
+
+      isDiagonalizable_ = true;
+      for (i = 0; i < size_ && isDiagonalizable_; i++)
+      {
+        if (abs(iEigenValues_[i]) > NumConstants::SMALL())
+          isDiagonalizable_ = false;
+      }
+
+
+      // is it singular?
+
+      // looking for the 0 eigenvector for which the non-stop right
+      // eigen vector elements are equal.
+      //
+      // there is a tolerance for numerical problems
+      //
+
+      size_t nulleigen = 0;
+      double val;
+      double seuil = 1;
+
+      isNonSingular_ = false;
+      while (!isNonSingular_)
+      {
+        nulleigen = 0;
+        while (nulleigen < salph - nbStop)
+        {
+          if ((abs(eigenValues_[nulleigen]) < NumConstants::SMALL()) && (abs(iEigenValues_[nulleigen]) < NumConstants::SMALL()))
+          {
+            i = 0;
+            while (vnull[i])
+              i++;
+
+            val = rightEigenVectors_(i, nulleigen);
+            i++;
+            while (i < salph)
+            {
+              if (!vnull[i])
+              {
+                if (abs(rightEigenVectors_(i, nulleigen) - val) > seuil * NumConstants::SMALL())
+                  break;
+              }
+              i++;
+            }
+
+            if (i < salph)
+              nulleigen++;
+            else
+            {
+              isNonSingular_ = true;
+              break;
+            }
+          }
+          else
+            nulleigen++;
+        }
+        if (seuil > 100)
+        {
+          ApplicationTools::displayWarning("!!! Equilibrium frequency of the model " + getName() + " has a precision less than " ""  + TextTools::toString(seuil * NumConstants::SMALL()) + ". There may be some computing issues.");
+          ApplicationTools::displayWarning("!!! Taylor series used instead");
+          break;
+        }
+        else
+          seuil *= 10;
+      }
+
+      if (isNonSingular_)
+      {
+        eigenValues_[nulleigen] = 0; // to avoid approximation errors on long long branches
+        iEigenValues_[nulleigen] = 0; // to avoid approximation errors on long long branches
+
+        for (i = 0; i < salph; i++)
+        {
+          freq_[i] = leftEigenVectors_(nulleigen, i);
+        }
+
+        x = 0;
+        for (i = 0; i < salph; i++)
+        {
+          x += freq_[i];
+        }
+
+        for (i = 0; i < salph; i++)
+        {
+          freq_[i] /= x;
+        }
+      }
+      else
+      {
+        ApplicationTools::displayMessage("Unable to find eigenvector for eigenvalue 1. Taylor series used instead.");
+        isDiagonalizable_ = false;
+      }
+    }
+
+    // if rightEigenVectors_ is singular
+    catch (ZeroDivisionException& e)
+    {
+      ApplicationTools::displayMessage("Singularity during  diagonalization. Taylor series used instead.");
+      isNonSingular_ = false;
+      isDiagonalizable_ = false;
+    }
+
+    if (!isNonSingular_)
+    {
+      double min = generator_(0, 0);
+      for (i = 1; i < salph; i++)
+      {
+        if (min > generator_(i, i))
+          min = generator_(i, i);
+      }
+
+      MatrixTools::scale(generator_, -1 / min);
+
+      if (vPowGen_.size() == 0)
+        vPowGen_.resize(30);
+
+      MatrixTools::getId(salph, tmpMat_);    // to compute the equilibrium frequency  (Q+Id)^256
+      MatrixTools::add(tmpMat_, generator_);
+      MatrixTools::pow(tmpMat_, 256, vPowGen_[0]);
+
+      for (i = 0; i < salph; i++)
+      {
+        freq_[i] = vPowGen_[0](0, i);
+      }
+
+      MatrixTools::getId(salph, vPowGen_[0]);
+    }
+
+    // normalization
+
+    x = 0;
+    for (i = 0; i < salph; i++)
+    {
+      x += freq_[i] * generator_(i, i);
+    }
+
+    MatrixTools::scale(generator_, -1. / x);
+    for (i = 0; i < salph; i++)
+    {
+      eigenValues_[i] /= -x;
+      iEigenValues_[i] /= -x;
+    }
+
+    if (!isNonSingular_)
+      MatrixTools::Taylor(generator_, 30, vPowGen_);
+  }
+
+  // compute the exchangeability_
+
+  for (i = 0; i < size_; i++)
+  {
+    for (j = 0; j < size_; j++)
+    {
+      exchangeability_(i, j) = generator_(i, j) / freq_[j];
+    }
+  }
+}
+
+void AbstractWordSubstitutionModel::setFreq(std::map<int, double>& freqs)
+{
+  map<int, double> tmpFreq;
+  size_t nbmod = VSubMod_.size();
+
+  size_t i, j, s, k, d, size;
+  d = size = getNumberOfStates();
+
+  if (VSubMod_.size() < 2 || VSubMod_[0] == VSubMod_[1])
+  {
+    s = VSubMod_[0]->getAlphabet()->getSize();
+    for (j = 0; j < s; j++)
+    {
+      tmpFreq[static_cast<int>(j)] = 0;
+    }
+
+    for (i = 0; i < nbmod; i++)
+    {
+      d /= s;
+      for (k = 0; k < size; k++)
+      {
+        tmpFreq[static_cast<int>((k / d) % s)] += freqs[static_cast<int>(k)];
+      }
+    }
+
+    for (k = 0; k < s; k++)
+    {
+      tmpFreq[static_cast<int>(k)] /= static_cast<double>(nbmod);
+    }
+
+    VSubMod_[0]->setFreq(tmpFreq);
+    matchParametersValues(VSubMod_[0]->getParameters());
+  }
+  else
+    for (i = 0; i < nbmod; i++)
+    {
+      tmpFreq.clear();
+      s = VSubMod_[i]->getAlphabet()->getSize();
+      d /= s;
+      for (j = 0; j < s; j++)
+      {
+        tmpFreq[static_cast<int>(j)] = 0;
+      }
+      for (k = 0; k < size; k++)
+      {
+        tmpFreq[static_cast<int>((k / d) % s)] += freqs[static_cast<int>(k)];
+      }
+      VSubMod_[i]->setFreq(tmpFreq);
+      matchParametersValues(VSubMod_[i]->getParameters());
+    }
+}
diff --git a/src/Bpp/Phyl/Model/AbstractWordSubstitutionModel.h b/src/Bpp/Phyl/Model/AbstractWordSubstitutionModel.h
new file mode 100644
index 0000000..3c736e5
--- /dev/null
+++ b/src/Bpp/Phyl/Model/AbstractWordSubstitutionModel.h
@@ -0,0 +1,184 @@
+//
+// File: AbstractWordSubstitutionModel.h
+// Created by: Laurent Gueguen
+// Created on: Jan 2009
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _ABSTRACTWORDSUBSTITUTIONMODEL_H_
+#define _ABSTRACTWORDSUBSTITUTIONMODEL_H_
+
+#include "AbstractSubstitutionModel.h"
+
+// From the STL:
+#include <vector>
+
+namespace bpp
+{
+/**
+ * @brief Abstract Basal class for words of substitution models.
+ * @author Laurent Guéguen
+ *
+ * Objects of this class are built from several substitution models.
+ * Each model corresponds to a position in the word. No model is
+ * directly accessible.
+ *
+ * Only substitutions with one letter changed are accepted.
+ *
+ * There is one substitution per word per unit of time
+ * on the equilibrium frequency, and each position has its specific rate.
+ * For example, if there are @f$n at f$ models and \f$\rho_i\f$ is the rate of
+ * model i (@f$\sum_{i=1}^{n} \rho_i = 1 at f$):
+ * @f{eqnarray*}
+ * Q_{abc \rightarrow abd} &=& \rho_2 Q^{(2)}_{c \rightarrow d}\\
+ * Q_{abc \rightarrow aed} &=& 0\\
+ * Q_{abc \rightarrow abc} &=& \rho_0 Q^{(0)}_{a \rightarrow a} + \rho_1 Q^{(1)}_{b \rightarrow b} + \rho_2 Q^{(2)}_{c \rightarrow c})
+ * @f}
+ *
+ * The parameters of this word model are the same as the ones of the
+ * models used. Their names have a new suffix, "phi_" where i stands
+ * for the position (i.e. the phase) in the word.
+ *
+ */
+class AbstractWordSubstitutionModel :
+    public virtual AbstractSubstitutionModel
+{
+private:
+  /**
+   * @ brief boolean flag to check if a specific WordAlphabet has been built
+   */
+  bool new_alphabet_;
+
+protected:
+  std::vector<SubstitutionModel*> VSubMod_;
+  std::vector<std::string> VnestedPrefix_;
+
+  std::vector<double> Vrate_;
+
+protected:
+  static Alphabet* extractAlph(const std::vector<SubstitutionModel*>& modelVector);
+
+protected:
+  void updateMatrices();
+
+  /**
+   * @brief Called by updateMatrices to handle specific modifications
+   * for inheriting classes
+   */
+  virtual void completeMatrices() = 0;
+
+public:
+  /**
+   * @brief Build a new AbstractWordSubstitutionModel object from a
+   * vector of pointers to SubstitutionModels.
+   *
+   * @param modelVector the vector of substitution models to use, in
+   *   the order of the positions in the words from left to right. All
+   *   the models must be different objects to avoid parameters
+   *   redundancy, otherwise only the first model is used. The used models
+   *   are owned by the instance.
+   * @param st the Namespace.
+   */
+  AbstractWordSubstitutionModel(
+    const std::vector<SubstitutionModel*>& modelVector,
+    const std::string& st);
+
+  /**
+   * @brief Build a new AbstractWordSubstitutionModel object from a
+   * pointer to an SubstitutionModel and a number of
+   * desired models.
+   *
+   * @param pmodel A pointer to the substitution model to use in all
+   * the positions. It will be owned by the instance.
+   * @param num The number of models involved.
+   * @param st the Namespace.
+   */
+  AbstractWordSubstitutionModel(
+    SubstitutionModel* pmodel,
+    unsigned int num,
+    const std::string& st);
+
+  AbstractWordSubstitutionModel(const AbstractWordSubstitutionModel&);
+
+  AbstractWordSubstitutionModel& operator=(const AbstractWordSubstitutionModel&);
+
+  virtual ~AbstractWordSubstitutionModel();
+
+  void setNamespace(const std::string& prefix);
+
+protected:
+  /**
+   *@brief Constructor for the derived classes only
+   */
+  AbstractWordSubstitutionModel(const Alphabet* alph, const std::string&);
+
+public:
+  virtual size_t getNumberOfStates() const;
+
+  /**
+   * @brief returns the ith model, or Null if i is not a valid number.
+   *
+   */
+  
+  const SubstitutionModel* getNModel(size_t i) const {
+    if (i< VSubMod_.size())
+        return dynamic_cast<const SubstitutionModel*>(VSubMod_[i]);
+    else
+      return 0;
+  }
+
+  size_t getNumberOfModels() const {
+    return VSubMod_.size();
+  }
+  
+  /**
+   *@brief Estimation of the parameters of the models so that the
+   *equilibrium frequencies match the given ones.
+   *
+   *@param freqs  map of the frequencies
+   *
+   * When there is one submodel for all the positions, the submodel
+   * parameters are fit on the means of the frequencies on each
+   * position. Otherwise, each model is fit on the frequencies on its
+   * corresponding position in the word.
+   *
+   **/
+  
+  virtual void setFreq(std::map<int, double>& freqs);
+};
+} // end of namespace bpp.
+
+#endif  // ABSTRACTWORDSUBSTITUTIONMODEL_
+
diff --git a/src/Bpp/Phyl/Model/BinarySubstitutionModel.cpp b/src/Bpp/Phyl/Model/BinarySubstitutionModel.cpp
new file mode 100644
index 0000000..3cac715
--- /dev/null
+++ b/src/Bpp/Phyl/Model/BinarySubstitutionModel.cpp
@@ -0,0 +1,241 @@
+//
+// File: BinarySubstitutionModel.cpp
+// Created by: Laurent Gueguen
+// Created on: 2009
+//
+
+/*
+   Copyright or � or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "BinarySubstitutionModel.h"
+
+// From the STL:
+#include <cmath>
+
+using namespace bpp;
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+using namespace std;
+
+/******************************************************************************/
+
+BinarySubstitutionModel::BinarySubstitutionModel(const BinaryAlphabet* alpha, double kappa) :
+  AbstractParameterAliasable("Binary."),
+  AbstractSubstitutionModel(alpha, "Binary."),
+  AbstractReversibleSubstitutionModel(alpha, "Binary."),
+  kappa_(kappa),
+  lambda_(0),
+  exp_(0),
+  p_(size_,size_)
+{
+  addParameter_(new Parameter(getNamespace() + "kappa", kappa_, &Parameter::R_PLUS_STAR));
+  updateMatrices();
+}
+
+/******************************************************************************/
+
+void BinarySubstitutionModel::updateMatrices()
+{
+  kappa_ = getParameterValue("kappa"); // alpha/beta
+  lambda_ = (kappa_ + 1) * (kappa_ + 1) / (2 * kappa_);
+
+  // Frequences:
+  freq_[0] = 1 / (kappa_ + 1);
+  freq_[1] = kappa_ / (kappa_ + 1);
+
+  // Generator:
+  generator_(0, 0) = rate_ * -(kappa_ + 1) / 2;
+  generator_(0, 1) = rate_ * (kappa_ + 1) / 2;
+  generator_(1, 0) = rate_ * (kappa_ + 1) / (2 * kappa_);
+  generator_(1, 1) = rate_ * -(kappa_ + 1) / (2 * kappa_);
+
+  // Eigen values:
+  eigenValues_[0] = 0;
+  eigenValues_[1] = -rate_ * lambda_;
+
+  // Eigen vectors:
+  leftEigenVectors_(0,0) = 1 / (kappa_ + 1);
+  leftEigenVectors_(0,1) = kappa_ / (kappa_ + 1);
+  if (kappa_ != 1.0)
+  {
+    leftEigenVectors_(1,0) = (kappa_ - 1) / (kappa_ + 1);
+    leftEigenVectors_(1,1) = -(kappa_ - 1) / (kappa_ + 1);
+  }
+  else
+  {
+    leftEigenVectors_(1,0) = 1;
+    leftEigenVectors_(1,1) = -1;
+  }
+
+  rightEigenVectors_(0,0) = 1;
+  rightEigenVectors_(1,0) = 1;
+
+  if (kappa_ != 1.0)
+  {
+    rightEigenVectors_(0,1) = kappa_ / (kappa_ - 1);
+    rightEigenVectors_(1,1) = -1 / (kappa_ - 1);
+  }
+  else
+  {
+    rightEigenVectors_(0,1) = 1 / 2;
+    rightEigenVectors_(1,1) = -1 / 2;
+  }
+}
+
+/******************************************************************************/
+
+double BinarySubstitutionModel::Pij_t(size_t i, size_t j, double d) const
+{
+  exp_ = exp(-lambda_ * d);
+
+  switch (i)
+  {
+  case 0: {
+    switch (j)
+    {
+    case 0: return (1 + kappa_ * exp_) / (kappa_ + 1);
+    case 1: return kappa_ / (kappa_ + 1) * (1 - exp_);
+    }
+  }
+  case 1: {
+    switch (j)
+    {
+    case 0: return (1 - exp_) / (kappa_ + 1);
+    case 1: return (kappa_ + exp_) / (kappa_ + 1);
+    }
+  }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+
+double BinarySubstitutionModel::dPij_dt(size_t i, size_t j, double d) const
+{
+  exp_ = exp(-lambda_ * d);
+
+  switch (i)
+  {
+  case 0: {
+    switch (j)
+    {
+    case 0: return -(kappa_ + 1) / 2 * exp_;
+    case 1: return (kappa_ + 1) / 2 * exp_;
+    }
+  }
+  case 1: {
+    switch (j)
+    {
+    case 0: return (kappa_ + 1) / (2 * kappa_) * exp_;
+    case 1: return -(kappa_ + 1) / (2 * kappa_) * exp_;
+    }
+  }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+
+double BinarySubstitutionModel::d2Pij_dt2(size_t i, size_t j, double d) const
+{
+  exp_ = exp(-lambda_ * d);
+
+  switch (i)
+  {
+  case 0: {
+    switch (j)
+    {
+    case 0: return lambda_ * (kappa_ + 1) / 2 * exp_;
+    case 1: return -lambda_ * (kappa_ + 1) / 2 * exp_;
+    }
+  }
+  case 1: {
+    switch (j)
+    {
+    case 0: return -lambda_ * (kappa_ + 1) / (2 * kappa_) * exp_;
+    case 1: return lambda_ * (kappa_ + 1) / (2 * kappa_) * exp_;
+    }
+  }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+
+const Matrix<double>& BinarySubstitutionModel::getPij_t(double d) const
+{
+  exp_ = exp(-lambda_ * d);
+
+  p_(0,0) = (1 + kappa_ * exp_) / (kappa_ + 1);
+  p_(0,1) = kappa_ / (kappa_ + 1) * (1 - exp_);
+
+  p_(1,0) =  (1 - exp_) / (kappa_ + 1);
+  p_(1,1) = (kappa_ + exp_) / (kappa_ + 1);
+
+  return p_;
+}
+
+const Matrix<double>& BinarySubstitutionModel::getdPij_dt(double d) const
+{
+  exp_ = exp(-lambda_ * d);
+
+  p_(0,0) = -(kappa_ + 1) / 2 * exp_;
+  p_(0,1) = (kappa_ + 1) / 2 * exp_;
+
+  p_(1,0) = (kappa_ + 1) / (2 * kappa_) * exp_;
+  p_(1,1) = -(kappa_ + 1) / (2 * kappa_) * exp_;
+
+  return p_;
+}
+
+const Matrix<double>& BinarySubstitutionModel::getd2Pij_dt2(double d) const
+{
+  exp_ = exp(-lambda_ * d);
+
+  p_(0,0) = lambda_ * (kappa_ + 1) / 2 * exp_;
+  p_(0,1) = -lambda_ * (kappa_ + 1) / 2 * exp_;
+  p_(1,0) = -lambda_ * (kappa_ + 1) / (2 * kappa_) * exp_;
+  p_(1,1) = lambda_ * (kappa_ + 1) / (2 * kappa_) * exp_;
+
+  return p_;
+}
+
+/******************************************************************************/
+
+void BinarySubstitutionModel::setFreq(std::map<int, double>& freqs)
+{
+  kappa_ = freqs[1] / freqs[0];
+  setParameterValue("kappa",kappa_);
+  updateMatrices();
+}
diff --git a/src/Bpp/Phyl/Model/BinarySubstitutionModel.h b/src/Bpp/Phyl/Model/BinarySubstitutionModel.h
new file mode 100644
index 0000000..8a1156f
--- /dev/null
+++ b/src/Bpp/Phyl/Model/BinarySubstitutionModel.h
@@ -0,0 +1,152 @@
+//
+// File: BinarySubstitutionModel.h
+// Created by: Laurent Gueguen
+// Created on: 2009
+//
+
+/*
+   Copyright or � or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _BINARYSUBSTITUTIONMODEL_H_
+#define _BINARYSUBSTITUTIONMODEL_H_
+
+#include "AbstractSubstitutionModel.h"
+#include <Bpp/Seq/Alphabet/BinaryAlphabet.h>
+
+namespace bpp
+{
+/**
+ * @brief The Model on two states
+ *
+ * \f[
+ * Q = r.\begin{pmatrix}
+ * -\kappa & \kappa  \\
+ * 1 & -1  \\
+ * \end{pmatrix}
+ * \f]
+ * \f[
+ * \pi = diag\left(\frac{1}{\kappa+1}, \frac{\kappa}{\kappa+1}\right)
+ * \f]
+ * Normalization: \f$r\f$ is set so that \f$\sum_i Q_{i,i}\pi_i = -1\f$:
+ * \f[
+ * Q = \begin{pmatrix}
+ * -\frac{\kappa + 1}2 & \frac{\kappa + 1}2 \\
+ * \frac{\kappa+1}{2\kappa} & -\frac{\kappa+1}{2\kappa}\\
+ * \end{pmatrix}
+ * \f]
+ *
+ * The eigen values are \f$\left(0, - \frac{(\kappa+1)^2}{2\kappa}\right)\f$,
+ * and IF \f$\kappa \neq 1\f$, the left eigen vectors are, by row:
+ * \f[
+ * U = \begin{pmatrix}
+ *  \frac{1}{1+\kappa} &  \frac{\kappa}{1+\kappa} \\
+ *  \frac{\kappa-1}{\kappa+1} & -\frac{\kappa-1}{\kappa+1} \\
+ * \end{pmatrix}
+ * \f]
+ * and the right eigen vectors are by column:
+ * \f[
+ * U^{-1} = \begin{pmatrix}
+ *  1 &  \frac \kappa{\kappa-1} \\
+ *  1 &  - \frac 1{\kappa-1} \\
+ * \end{pmatrix}
+ * \f]
+ *
+ * The probabilities of changes are computed analytically using the formulas, with \f$\lambda= \frac{(\kappa+1)^2}{2\kappa}\f$ :
+ * \f[
+ * P_{i,j}(t) = \begin{pmatrix}
+ * \frac{1}{\kappa+1} + \frac{\kappa}{\kappa+1}e^{-\lambda t} & \frac{\kappa}{\kappa+1} - \frac{\kappa}{\kappa+1}e^{-\lambda t} \\
+ * \frac{1}{\kappa+1} - \frac{1}{\kappa+1}e^{-\lambda t} & \frac{\kappa}{\kappa+1} + \frac{1}{\kappa+1}e^{-\lambda t} \\
+ * \end{pmatrix}
+ * \f]
+ *
+ * \f[
+ * \frac{\partial P_{i,j}(t)}{\partial t} = \begin{pmatrix}
+ * -\frac {\kappa+1} 2 e^{-\lambda t}  & \frac {\kappa+1} 2 e^{-\lambda t} \\
+ * \frac {\kappa+1} {2\kappa} e^{-\lambda t}  & - \frac {\kappa+1} {2\kappa} e^{-\lambda t} \\
+ * \end{pmatrix}
+ * \f]
+ * \f{multline*}
+ * \frac{\partial^2 P_{i,j}(t)}{\partial t^2} = \\
+ * \begin{pmatrix}
+ * \frac {\lambda (\kappa+1)} 2 e^{-\lambda t}  & -\ frac {\lambda (\kappa+1)} 2 e^{-\lambda t} \\
+ * \frac {\lambda (\kappa+1)} {2\kappa} e^{-\lambda t}  & - \frac {\lambda (\kappa+1)} {2\kappa} e^{-\lambda t} \\
+ * \end{pmatrix}
+ * \f}
+ *
+ * The parameter is named \c "kappa"
+ * and its value may be retrieve with the command
+ * \code
+ * getParameterValue("kappa")
+ * \endcode
+ *
+ */
+
+class BinarySubstitutionModel :
+  public AbstractReversibleSubstitutionModel
+{
+private:
+  double kappa_;
+
+protected:
+  mutable double lambda_, exp_;
+  mutable RowMatrix<double> p_;
+
+public:
+  BinarySubstitutionModel(const BinaryAlphabet* alpha, double kappa = 1.);
+
+  virtual ~BinarySubstitutionModel() {}
+
+  BinarySubstitutionModel* clone() const { return new BinarySubstitutionModel(*this); }
+
+  
+public:
+  double Pij_t    (size_t i, size_t j, double d) const;
+  double dPij_dt  (size_t i, size_t j, double d) const;
+  double d2Pij_dt2(size_t i, size_t j, double d) const;
+  const Matrix<double>& getPij_t    (double d) const;
+  const Matrix<double>& getdPij_dt  (double d) const;
+  const Matrix<double>& getd2Pij_dt2(double d) const;
+
+  std::string getName() const { return "Binary"; }
+
+  void setFreq(std::map<int, double>& freqs);
+
+  size_t getNumberOfStates() const { return 2; }
+
+protected:
+  void updateMatrices();
+};
+} // end of namespace bpp.
+
+#endif  // _BINARYSUBSTITUTIONMODEL_H_
+
diff --git a/src/Bpp/Phyl/Model/Codon/AbstractCodonDistanceSubstitutionModel.cpp b/src/Bpp/Phyl/Model/Codon/AbstractCodonDistanceSubstitutionModel.cpp
new file mode 100644
index 0000000..e7eef94
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/AbstractCodonDistanceSubstitutionModel.cpp
@@ -0,0 +1,87 @@
+//
+// File: AbstractCodonDistanceSubstitutionModel.cpp
+// Created by:  Laurent Gueguen
+// Created on: Feb 2009
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "AbstractCodonDistanceSubstitutionModel.h"
+#include <Bpp/Numeric/NumConstants.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+AbstractCodonDistanceSubstitutionModel::AbstractCodonDistanceSubstitutionModel(
+  const GeneticCode* palph,
+  const AlphabetIndex2* pdist,
+  const std::string& prefix,
+  bool paramSynRate) :
+  CodonSubstitutionModel(),
+  AbstractParameterAliasable(prefix),
+  geneticCode_(palph),
+  pdistance_(pdist),
+  alpha_(10000),
+  beta_(1),
+  gamma_(1)
+{
+  if (pdistance_)
+    addParameter_(new Parameter(prefix + "alpha", 10000, &Parameter::R_PLUS_STAR));
+
+  if (paramSynRate)
+    addParameter_(new Parameter(prefix + "gamma", 1, new IntervalConstraint(NumConstants::SMALL(), 999, true, true), true));
+
+  addParameter_(new Parameter(prefix + "beta", 1, new IntervalConstraint(NumConstants::SMALL(), 999, true, true), true));
+}
+
+void AbstractCodonDistanceSubstitutionModel::fireParameterChanged(const ParameterList& parameters)
+{
+  if (pdistance_)
+    alpha_ = getParameterValue("alpha");
+
+  if (hasParameter("gamma"))
+    gamma_ = getParameterValue("gamma");
+  beta_ = getParameterValue("beta");
+}
+
+double AbstractCodonDistanceSubstitutionModel::getCodonsMulRate(size_t i, size_t j) const
+{
+  return geneticCode_->areSynonymous(static_cast<int>(i), static_cast<int>(j)) ? gamma_ :
+         beta_ * (pdistance_ ? exp(-pdistance_->getIndex(
+                 geneticCode_->translate(static_cast<int>(i)),
+                 geneticCode_->translate(static_cast<int>(j))) / alpha_) : 1);
+}
+
diff --git a/src/Bpp/Phyl/Model/Codon/AbstractCodonDistanceSubstitutionModel.h b/src/Bpp/Phyl/Model/Codon/AbstractCodonDistanceSubstitutionModel.h
new file mode 100644
index 0000000..0b5a702
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/AbstractCodonDistanceSubstitutionModel.h
@@ -0,0 +1,148 @@
+//
+// File: AbstractCodonDistanceSubstitutionModel.h
+// Created by: Laurent Gueguen
+// Created on: jeudi 15 septembre 2011, à 21h 11
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _ABSTRACTCODONDISTANCESUBSTITUTIONMODEL_H_
+#define _ABSTRACTCODONDISTANCESUBSTITUTIONMODEL_H_
+
+#include "CodonSubstitutionModel.h"
+#include <Bpp/Numeric/AbstractParameterAliasable.h>
+
+
+// From bpp-seq:
+#include <Bpp/Seq/GeneticCode/GeneticCode.h>
+#include <Bpp/Seq/AlphabetIndex/AlphabetIndex2.h>
+
+namespace bpp
+{
+/**
+ * @brief Abstract class for modelling of non-synonymous abd
+ *  synonymous substitution rates in codon models.
+ *
+ * @author Laurent Guéguen
+ *
+ * If a distance @f$d at f$ between amino-acids is defined, the
+ *  non-synonymous rate is multiplied with, if the coded amino-acids
+ *  are @f$x at f$ and @f$y at f$, @f$\beta*\exp(-\alpha.d(x,y))@f$ with
+ *  non-negative parameter \c "alpha" and positive parameter \c
+ *  "beta".
+ *
+ * If such a distance is not defined, the non-synonymous substitution
+ *  rate is multiplied with @f$\beta at f$ with positive parameter \c
+ *  "beta" (ie @f$d=0 at f$).
+ *
+ * If paramSynRate is true, the synonymous substitution rate is
+ *  multiplied with @f$\gamma at f$ (with optional positive parameter \c
+ *  "gamma"), else it is multiplied with 1.
+ *
+ * 
+ * References:
+ * - Goldman N. and Yang Z. (1994), _Molecular Biology And Evolution_ 11(5) 725--736. 
+ * _ Kosakovsky Pond, S. and Muse, S.V. (2005), _Molecular Biology And Evolution_,
+ *   22(12), 2375--2385.
+ * - Mayrose, I. and Doron-Faigenboim, A. and Bacharach, E. and Pupko T.
+ *   (2007), Bioinformatics, 23, i319--i327.
+ *
+ */
+
+class AbstractCodonDistanceSubstitutionModel :
+  public virtual CodonSubstitutionModel,
+  public virtual AbstractParameterAliasable
+{
+private:
+  const GeneticCode* geneticCode_;
+  const AlphabetIndex2* pdistance_;
+
+  double alpha_, beta_;
+
+  double gamma_;
+public:
+  /**
+   *@brief Build a new AbstractCodonDistanceSubstitutionModel object from
+   * a pointer to NucleotideSubstitutionModel.
+   *
+   *@param palph pointer to a GeneticCode
+   *@param pdist optional pointer to a distance between amino-acids
+   *@param prefix the Namespace
+   *@param paramSynRate is true iff synonymous rate is parametrised
+   *       (default=false).
+   */
+
+  AbstractCodonDistanceSubstitutionModel(
+    const GeneticCode* palph,
+    const AlphabetIndex2* pdist,
+    const std::string& prefix,
+    bool paramSynRate = false);
+
+
+  AbstractCodonDistanceSubstitutionModel(
+    const AbstractCodonDistanceSubstitutionModel& model) :
+    AbstractParameterAliasable(model),
+    geneticCode_(model.geneticCode_),
+    pdistance_(model.pdistance_),
+    alpha_(model.alpha_),
+    beta_(model.beta_),
+    gamma_(model.gamma_)
+  {}
+
+  AbstractCodonDistanceSubstitutionModel& operator=(
+    const AbstractCodonDistanceSubstitutionModel& model)
+  {
+    AbstractParameterAliasable::operator=(model);
+    geneticCode_ = model.geneticCode_;
+    pdistance_ = model.pdistance_;
+    alpha_ = model.alpha_;
+    beta_ = model.beta_;
+    gamma_ = model.gamma_;
+    return *this;
+  }
+
+  ~AbstractCodonDistanceSubstitutionModel() {}
+
+public:
+  void fireParameterChanged(const ParameterList& parameters);
+
+  const GeneticCode* getGeneticCode() const { return geneticCode_; }
+
+public:
+  double getCodonsMulRate(size_t i, size_t j) const;
+};
+} // end of namespace bpp.
+
+#endif
+
diff --git a/src/Bpp/Phyl/Model/Codon/AbstractCodonFitnessSubstitutionModel.cpp b/src/Bpp/Phyl/Model/Codon/AbstractCodonFitnessSubstitutionModel.cpp
new file mode 100644
index 0000000..b15ab86
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/AbstractCodonFitnessSubstitutionModel.cpp
@@ -0,0 +1,83 @@
+//
+// File: AbstractCodonFitnessSubstitutionModel.cpp
+// Created by:  Fanny Pouyet
+// Created on: mars 2012
+//
+
+/*
+  Copyright or © or Copr. CNRS, (November 16, 2004)
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+ 
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+ 
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+ 
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+ 
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+# include "AbstractCodonFitnessSubstitutionModel.h"
+using namespace bpp;
+using namespace std;
+/****************************************************************************************/
+AbstractCodonFitnessSubstitutionModel::AbstractCodonFitnessSubstitutionModel(FrequenciesSet* pfitset, const string& prefix):
+  CodonSubstitutionModel(), AbstractParameterAliasable(prefix), pfitset_(pfitset), fitName_("")
+{
+  if (dynamic_cast<CodonFrequenciesSet*>(pfitset) == NULL)
+    throw Exception ("Bad type for fitness parameters"+ pfitset ->getName() );
+  fitName_="fit_"+ pfitset_->getNamespace();
+  pfitset_->setNamespace(prefix + fitName_);
+  addParameters_(pfitset_->getParameters() );
+}
+
+AbstractCodonFitnessSubstitutionModel::~AbstractCodonFitnessSubstitutionModel()
+{
+  if (pfitset_) delete pfitset_;
+}
+
+void AbstractCodonFitnessSubstitutionModel::fireParameterChanged (const ParameterList& parameters)
+{
+  pfitset_->matchParametersValues(parameters);
+}
+
+void AbstractCodonFitnessSubstitutionModel::setFreq(map<int, double>& frequencies)
+{
+  pfitset_->setFrequenciesFromMap(frequencies);
+  matchParametersValues(pfitset_->getParameters() );
+}
+
+double AbstractCodonFitnessSubstitutionModel::getCodonsMulRate(size_t i, size_t j) const
+{
+  double mu;
+  double phi_j= pfitset_->getFrequencies() [j];
+  double phi_i= pfitset_->getFrequencies() [i];
+  if (phi_i == phi_j) mu=1;
+  else if (phi_i==0)
+    mu=100;
+  else if (phi_j==0)
+    mu=0;
+  else
+    mu = -(log(phi_i/phi_j)/(1-(phi_i/phi_j)));
+  return mu;
+}
+
diff --git a/src/Bpp/Phyl/Model/Codon/AbstractCodonFitnessSubstitutionModel.h b/src/Bpp/Phyl/Model/Codon/AbstractCodonFitnessSubstitutionModel.h
new file mode 100644
index 0000000..0eb4707
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/AbstractCodonFitnessSubstitutionModel.h
@@ -0,0 +1,104 @@
+//
+// File: AbstractCodonFitnessSubstitutionModel.h
+// Created by:  Fanny Pouyet
+// Created on: mars 2012
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+ 
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+ 
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+ 
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+ 
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+# ifndef _ABSTRACTCODONFITNESSSUBSTITUTIONMODEL_H_
+# define _ABSTRACTCODONFITNESSSUBSTITUTIONMODEL_H_
+
+# include "CodonSubstitutionModel.h"
+#include "../FrequenciesSet/CodonFrequenciesSet.h"
+namespace bpp
+{
+  /**
+   * @brief Abstract class for modelling of ratios of substitution
+   * rates between codons, whatever they are synonymous or not.
+   *
+   * @author Fanny Pouyet, Laurent Guéguen
+   *
+   * The fitness of a codon is a value between 0 and 1 defining the
+   * relative advantage of a codon, compared to others. If a codon
+   * @f$i at f$ has a fitness @f$\phi_i at f$ and another one (@f$j at f$) has
+   * a fitness @f$\phi_j at f$, the substitution rate from codon @f$i at f$
+   * to codon @f$j at f$ is multiplied by
+   * \f[-\frac{\log(\frac{\phi_i}{\phi_j})}{1-\frac{\phi_i}{\phi_j}}\f]
+   *
+   * The set of fitnesses is implemented through a Codon
+   * FrequenciesSet object. The parameters are named \c
+   * "fit_NameOfTheParameterInTheFrequenciesSet".
+   */
+
+
+  class AbstractCodonFitnessSubstitutionModel :
+    public virtual CodonSubstitutionModel,
+    public virtual AbstractParameterAliasable
+  {
+  private:
+    FrequenciesSet* pfitset_;
+    std::string fitName_;
+  public:
+    AbstractCodonFitnessSubstitutionModel(FrequenciesSet* pfitset, const std::string& prefix);
+    AbstractCodonFitnessSubstitutionModel(const AbstractCodonFitnessSubstitutionModel& model):
+      AbstractParameterAliasable(model),
+      pfitset_(model.pfitset_->clone()),
+      fitName_(model.fitName_)
+    {}
+
+    AbstractCodonFitnessSubstitutionModel& operator=(const AbstractCodonFitnessSubstitutionModel& model){
+      AbstractParameterAliasable::operator=(model);
+      if (pfitset_) delete pfitset_;
+      pfitset_ = model.pfitset_->clone();
+      fitName_ = model.fitName_ ;
+      return *this;
+    }
+
+    virtual ~AbstractCodonFitnessSubstitutionModel();
+
+    void fireParameterChanged (const ParameterList& parameters);
+    void setFreq(std::map<int, double>& frequencies);
+    const FrequenciesSet& getFreq() const { return *pfitset_; }
+    void setNamespace (const std::string& prefix){
+      pfitset_->setNamespace(prefix + fitName_);
+    }
+
+  public:
+    double getCodonsMulRate(size_t i, size_t j) const;
+
+    const FrequenciesSet* getFitness() const { return pfitset_;}
+
+  };
+} // end of namespace bpp
+# endif
diff --git a/src/Bpp/Phyl/Model/Codon/AbstractCodonFrequenciesSubstitutionModel.cpp b/src/Bpp/Phyl/Model/Codon/AbstractCodonFrequenciesSubstitutionModel.cpp
new file mode 100644
index 0000000..491c37b
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/AbstractCodonFrequenciesSubstitutionModel.cpp
@@ -0,0 +1,87 @@
+//
+// File: AbstractCodonFrequenciesSubstitutionModel.cpp
+// Created by:  Laurent Gueguen
+// Created on: jeudi 15 septembre 2011, à 15h 02
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "AbstractCodonFrequenciesSubstitutionModel.h"
+
+// #include <Bpp/Seq/Alphabet/AlphabetTools.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+AbstractCodonFrequenciesSubstitutionModel::AbstractCodonFrequenciesSubstitutionModel(
+  FrequenciesSet* pfreq,
+  const std::string& prefix) :
+  CodonSubstitutionModel(),
+  AbstractParameterAliasable(prefix),
+  pfreqset_(pfreq),
+  freqName_("")
+{
+  if (dynamic_cast<CodonFrequenciesSet*>(pfreq) == NULL)
+    throw Exception("Bad type for equilibrium frequencies " + pfreq->getName());
+
+  freqName_ = pfreqset_->getNamespace();
+  pfreqset_->setNamespace(prefix + freqName_);
+  addParameters_(pfreqset_->getParameters());
+}
+
+AbstractCodonFrequenciesSubstitutionModel::~AbstractCodonFrequenciesSubstitutionModel()
+{
+  if (pfreqset_)
+    delete pfreqset_;
+}
+
+void AbstractCodonFrequenciesSubstitutionModel::fireParameterChanged(const ParameterList& parameters)
+{
+  pfreqset_->matchParametersValues(parameters);
+}
+
+
+void AbstractCodonFrequenciesSubstitutionModel::setFreq(map<int, double>& frequencies)
+{
+  pfreqset_->setFrequenciesFromMap(frequencies);
+  matchParametersValues(pfreqset_->getParameters());
+}
+
+double AbstractCodonFrequenciesSubstitutionModel::getCodonsMulRate(size_t i, size_t j) const
+{
+  return pfreqset_->getFrequencies()[j];
+}
+
diff --git a/src/Bpp/Phyl/Model/Codon/AbstractCodonFrequenciesSubstitutionModel.h b/src/Bpp/Phyl/Model/Codon/AbstractCodonFrequenciesSubstitutionModel.h
new file mode 100644
index 0000000..23b6fba
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/AbstractCodonFrequenciesSubstitutionModel.h
@@ -0,0 +1,117 @@
+//
+// File: AbstractCodonFrequenciesSubstitutionModel.h
+// Created by: jeudi 15 septembre 2011, à 15h 02
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _ABSTRACTCODONFREQUENCIESSUBSTITUTIONMODEL_H_
+#define _ABSTRACTCODONFREQUENCIESSUBSTITUTIONMODEL_H_
+
+#include "AbstractCodonSubstitutionModel.h"
+#include "../FrequenciesSet/CodonFrequenciesSet.h"
+
+namespace bpp
+{
+/**
+ * @brief Abstract Class for substitution models on codons
+ *  parametrized by frequencies.
+ *
+ * This class should be used with models which equilibrium
+ * distribution is fixed, ans does not depend on the parameters.
+ * Otherwise there may be problems of identifiability of the
+ * parameters.
+ *
+ * @author Laurent Guéguen
+ *
+ * If we denote @f$F at f$ the equilibrium frequency, the generator term
+ * defined from inherited and inheriting classes, @f$Q_{ij})@f$, is
+ * multiplied by @f$F_{j}@f$.
+ *
+ */
+
+class AbstractCodonFrequenciesSubstitutionModel :
+  virtual public CodonSubstitutionModel,
+  virtual public AbstractParameterAliasable
+{
+private:
+  FrequenciesSet* pfreqset_;
+  std::string freqName_;
+
+public:
+  /**
+   *@brief Build a AbstractCodonFrequenciesSubstitutionModel instance
+   *
+   *@param pfreq pointer to the AbstractFrequenciesSet equilibrium frequencies.
+   *        It is owned by the instance.
+   *@param prefix the Namespace
+   */
+
+  AbstractCodonFrequenciesSubstitutionModel(FrequenciesSet* pfreq,
+                                            const std::string& prefix);
+
+  AbstractCodonFrequenciesSubstitutionModel(const AbstractCodonFrequenciesSubstitutionModel& model) :
+    AbstractParameterAliasable(model),
+    pfreqset_(model.pfreqset_->clone()),
+    freqName_(model.freqName_)
+  {}
+
+  AbstractCodonFrequenciesSubstitutionModel& operator=(const AbstractCodonFrequenciesSubstitutionModel& model)
+  {
+    AbstractParameterAliasable::operator=(model);
+    if (pfreqset_) delete pfreqset_;
+    pfreqset_   = model.pfreqset_->clone();
+    freqName_   = model.freqName_;
+    return *this;
+  }
+
+  virtual ~AbstractCodonFrequenciesSubstitutionModel();
+
+  void fireParameterChanged(const ParameterList& parameters);
+
+  void setFreq(std::map<int, double>& frequencies);
+
+  const FrequenciesSet* getFrequenciesSet() const { return pfreqset_; }
+
+  void setNamespace(const std::string& prefix)
+  {
+    pfreqset_->setNamespace(prefix + freqName_);
+  }
+
+  double getCodonsMulRate(size_t, size_t) const;
+};
+} // end of namespace bpp.
+
+#endif
+
diff --git a/src/Bpp/Phyl/Model/Codon/AbstractCodonPhaseFrequenciesSubstitutionModel.cpp b/src/Bpp/Phyl/Model/Codon/AbstractCodonPhaseFrequenciesSubstitutionModel.cpp
new file mode 100644
index 0000000..15f48ca
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/AbstractCodonPhaseFrequenciesSubstitutionModel.cpp
@@ -0,0 +1,124 @@
+//
+// File: AbstractCodonPhaseFrequenciesSubstitutionModel.cpp
+// Created by:  Laurent Gueguen
+// Created on: vendredi 23 septembre 2011, à 16h 29
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "AbstractCodonPhaseFrequenciesSubstitutionModel.h"
+
+// #include <Bpp/Seq/Alphabet/AlphabetTools.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+AbstractCodonPhaseFrequenciesSubstitutionModel::AbstractCodonPhaseFrequenciesSubstitutionModel(
+  FrequenciesSet* pfreq,
+  const std::string& prefix) :
+  CodonSubstitutionModel(),
+  AbstractParameterAliasable(prefix),
+  posfreqset_(),
+  freqName_("")
+{
+  CodonFrequenciesSet* pCFS = dynamic_cast<CodonFrequenciesSet*>(pfreq);
+  if (pCFS == NULL)
+    throw Exception("Bad type for equilibrium frequencies " + pfreq->getName());
+
+  if ((dynamic_cast<CodonFromUniqueFrequenciesSet*>(pCFS))
+      || (dynamic_cast<CodonFromIndependentFrequenciesSet*>(pCFS) != NULL))
+    posfreqset_ = dynamic_cast<WordFrequenciesSet*>(pfreq)->clone();
+  else
+  {
+    vector<FrequenciesSet*> vFS;
+    if (dynamic_cast<FixedCodonFrequenciesSet*>(pCFS))
+      for (unsigned int i = 0; i < 3; i++)
+      {
+        vFS.push_back(new FixedFrequenciesSet(
+              pCFS->getAlphabet()->getNucleicAlphabet(),
+              pCFS->getAlphabet()->getNucleicAlphabet()->getSize()));
+      }
+    else
+      for (unsigned int i = 0; i < 3; i++)
+      {
+        vFS.push_back(new FullFrequenciesSet(pCFS->getAlphabet()->getNucleicAlphabet()));
+      }
+
+    posfreqset_ = new CodonFromIndependentFrequenciesSet(pCFS->getAlphabet(),
+                                                         vFS, "");
+
+    posfreqset_->setFrequencies(pfreq->getFrequencies());
+  }
+
+  freqName_ = pfreq->getNamespace();
+  posfreqset_->setNamespace(prefix + pfreq->getNamespace());
+  //  if (dynamic_cast<FixedCodonFrequenciesSet*>(pCFS)!=NULL)
+  addParameters_(posfreqset_->getParameters());
+}
+
+AbstractCodonPhaseFrequenciesSubstitutionModel::~AbstractCodonPhaseFrequenciesSubstitutionModel()
+{
+  if (posfreqset_)
+    delete posfreqset_;
+}
+
+void AbstractCodonPhaseFrequenciesSubstitutionModel::fireParameterChanged(const ParameterList& parameters)
+{
+  posfreqset_->matchParametersValues(parameters);
+}
+
+
+void AbstractCodonPhaseFrequenciesSubstitutionModel::setFreq(map<int, double>& frequencies)
+{
+  posfreqset_->setFrequenciesFromMap(frequencies);
+  matchParametersValues(posfreqset_->getParameters());
+}
+
+double AbstractCodonPhaseFrequenciesSubstitutionModel::getCodonsMulRate(size_t i, size_t j) const
+{
+  size_t i2(i), j2(j);
+
+  double x = 1.;
+  for (size_t k = 0; k < 3; k++)
+  {
+    if ((i2 % 4) != (j2 % 4))
+      x *= posfreqset_->getFrequenciesSetForLetter(2 - k).getFrequencies()[j2 % 4];
+    i2 /= 4;
+    j2 /= 4;
+  }
+  return x;
+}
+
diff --git a/src/Bpp/Phyl/Model/Codon/AbstractCodonPhaseFrequenciesSubstitutionModel.h b/src/Bpp/Phyl/Model/Codon/AbstractCodonPhaseFrequenciesSubstitutionModel.h
new file mode 100644
index 0000000..698ab62
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/AbstractCodonPhaseFrequenciesSubstitutionModel.h
@@ -0,0 +1,129 @@
+//
+// File: AbstractCodonPhaseFrequenciesSubstitutionModel.h
+// Created by: vendredi 23 septembre 2011, à 16h 29
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _ABSTRACTCODONPHASEFREQUENCIESSUBSTITUTIONMODEL_H_
+#define _ABSTRACTCODONPHASEFREQUENCIESSUBSTITUTIONMODEL_H_
+
+#include "AbstractCodonSubstitutionModel.h"
+#include "../FrequenciesSet/CodonFrequenciesSet.h"
+
+namespace bpp
+{
+/**
+ * @brief Abstract Class for substitution models on codons
+ *  parametrized by a frequency.
+ *
+ * @author Laurent Guéguen
+ *
+ * This class should be used with models which equilibrium
+ * distribution is fixed, ans does not depend on the parameters.
+ * Otherwise there may be problems of identifiability of the
+ * parameters.
+ *
+ * If we denote @f$F at f$ the given frequencies for codons,
+ * @f$F_{j_k}@f$ is the frequency of letter @f$j at f$ in phase
+ * @f$k at f$.
+ *
+ * For codons @f$i=i_1i_2i_3 at f$ and @f$j=j_1j_2j_3 at f$, the generator
+ * term defined from inherited and inheriting classes,
+ * @f$Q_{ij})@f$, is multiplied by the product of the @f$F_{j_k}@f$
+ * for each @f$k \in 1, 2, 3 at f$ such that @f$i_k \neq j_k at f$.
+ *
+ */
+
+class AbstractCodonPhaseFrequenciesSubstitutionModel :
+  public virtual CodonSubstitutionModel,
+  public virtual AbstractParameterAliasable
+{
+private:
+  /*
+   *@brief Position dependent version of Codon Frequencies Set
+   *
+   */
+
+  WordFrequenciesSet* posfreqset_;
+  std::string freqName_;
+
+public:
+  /**
+   *@brief Build a AbstractCodonPhaseFrequenciesSubstitutionModel instance
+   *
+   *@param pfreq pointer to the AbstractFrequenciesSet equilibrium frequencies.
+   *        It is owned by the instance.
+   *@param prefix the Namespace
+   */
+
+  AbstractCodonPhaseFrequenciesSubstitutionModel(FrequenciesSet* pfreq,
+                                                 const std::string& prefix);
+
+  AbstractCodonPhaseFrequenciesSubstitutionModel(const AbstractCodonPhaseFrequenciesSubstitutionModel& model) :
+    AbstractParameterAliasable(model),
+    posfreqset_(model.posfreqset_->clone()),
+    freqName_(model.freqName_)
+  {}
+
+  AbstractCodonPhaseFrequenciesSubstitutionModel& operator=(const AbstractCodonPhaseFrequenciesSubstitutionModel& model)
+  {
+    AbstractParameterAliasable::operator=(model);
+    if (posfreqset_)
+      delete posfreqset_;
+    posfreqset_   = model.posfreqset_->clone();
+    freqName_   = model.freqName_;
+
+    return *this;
+  }
+
+  virtual ~AbstractCodonPhaseFrequenciesSubstitutionModel();
+
+  void fireParameterChanged(const ParameterList& parameters);
+
+  void setFreq(std::map<int, double>& frequencies);
+
+  const FrequenciesSet* getFrequenciesSet() const { return posfreqset_; }
+
+  void setNamespace(const std::string& prefix)
+  {
+    posfreqset_->setNamespace(prefix + freqName_);
+  }
+
+  double getCodonsMulRate(size_t, size_t) const;
+};
+} // end of namespace bpp.
+
+#endif
+
diff --git a/src/Bpp/Phyl/Model/Codon/AbstractCodonSubstitutionModel.cpp b/src/Bpp/Phyl/Model/Codon/AbstractCodonSubstitutionModel.cpp
new file mode 100644
index 0000000..fa5941e
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/AbstractCodonSubstitutionModel.cpp
@@ -0,0 +1,195 @@
+//
+// File: CodonSubstitutionModel.cpp
+// Created by:  Laurent Gueguen
+// Created on: Feb 2009
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "AbstractCodonSubstitutionModel.h"
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+AbstractCodonSubstitutionModel::AbstractCodonSubstitutionModel(
+  const CodonAlphabet* palph,
+  NucleotideSubstitutionModel* pmod,
+  const std::string& st,
+  bool paramRates) :
+  AbstractParameterAliasable(st),
+  AbstractSubstitutionModel(palph, st),
+  AbstractWordSubstitutionModel(palph, st),
+  hasParametrizedRates_(paramRates)
+{
+  enableEigenDecomposition(1);
+
+  unsigned int i;
+  for (i = 0; i < 3; i++)
+  {
+    VSubMod_.push_back(pmod);
+    VnestedPrefix_.push_back(pmod->getNamespace());
+  }
+
+  pmod->setNamespace(st + "123_" + VnestedPrefix_[0]);
+  pmod->enableEigenDecomposition(0);
+  addParameters_(pmod->getParameters());
+
+  Vrate_.resize(3);
+  for (i = 0; i < 3; i++)
+  {
+    Vrate_[i] = 1.0 / 3;
+  }
+
+
+  if (hasParametrizedRates_)
+  {
+    // relative rates
+    for (i = 0; i < 2; i++)
+    {
+      addParameter_(new Parameter(st + "relrate" + TextTools::toString(i + 1), 1.0 / static_cast<double>(3 - i), &Parameter::PROP_CONSTRAINT_EX));
+    }
+  }
+}
+
+AbstractCodonSubstitutionModel::AbstractCodonSubstitutionModel(
+  const CodonAlphabet* palph,
+  NucleotideSubstitutionModel* pmod1,
+  NucleotideSubstitutionModel* pmod2,
+  NucleotideSubstitutionModel* pmod3,
+  const std::string& st,
+  bool paramRates) :
+  AbstractParameterAliasable(st),
+  AbstractSubstitutionModel(palph, st),
+  AbstractWordSubstitutionModel(palph, st),
+  hasParametrizedRates_(paramRates)
+{
+  unsigned int i;
+  enableEigenDecomposition(1);
+
+  if ((pmod1 == pmod2) || (pmod2 == pmod3) || (pmod1 == pmod3))
+  {
+    for (i = 0; i < 3; i++)
+    {
+      VSubMod_.push_back(pmod1);
+      VnestedPrefix_.push_back(pmod1->getNamespace());
+    }
+
+    pmod1->setNamespace(st + "123_" + VnestedPrefix_[0]);
+    pmod1->enableEigenDecomposition(0);
+    addParameters_(pmod1->getParameters());
+  }
+  else
+  {
+    VSubMod_.push_back(pmod1);
+    VnestedPrefix_.push_back(pmod1->getNamespace());
+    VSubMod_[0]->setNamespace(st + "1_" + VnestedPrefix_[0]);
+    VSubMod_[0]->enableEigenDecomposition(0);
+    addParameters_(pmod1->getParameters());
+
+    VSubMod_.push_back(pmod2);
+    VnestedPrefix_.push_back(pmod2->getNamespace());
+    VSubMod_[1]->setNamespace(st + "2_" + VnestedPrefix_[1]);
+    VSubMod_[1]->enableEigenDecomposition(0);
+    addParameters_(pmod2->getParameters());
+
+    VSubMod_.push_back(pmod3);
+    VnestedPrefix_.push_back(pmod3->getNamespace());
+    VSubMod_[2]->setNamespace(st + "3_" + VnestedPrefix_[2]);
+    VSubMod_[2]->enableEigenDecomposition(0);
+    addParameters_(pmod3->getParameters());
+  }
+
+  Vrate_.resize(3);
+  for (i = 0; i < 3; i++)
+  {
+    Vrate_[i] = 1.0 / 3;
+  }
+
+  if (hasParametrizedRates_)
+  {
+    // relative rates
+    for (i = 0; i < 2; i++)
+    {
+      addParameter_(new Parameter(st + "relrate" + TextTools::toString(i + 1), 1.0 / (3 - i), &Parameter::PROP_CONSTRAINT_EX));
+    }
+  }
+}
+
+void AbstractCodonSubstitutionModel::updateMatrices()
+{
+  if (hasParametrizedRates_)
+  {
+    size_t i, nbmod = VSubMod_.size();
+    double x;
+    size_t k;
+    for (k = nbmod - 1; k > 0; k--)
+    {
+      x = 1.0;
+      for (i = 0; i < k; i++)
+      {
+        x *= 1 - getParameterValue("relrate" + TextTools::toString(i + 1));
+      }
+      if (k != nbmod - 1)
+        x *= getParameterValue("relrate" + TextTools::toString(k + 1));
+      Vrate_[k] = x;
+    }
+  }
+
+  AbstractWordSubstitutionModel::updateMatrices();
+}
+
+void AbstractCodonSubstitutionModel::completeMatrices()
+{
+  size_t i, j;
+  size_t salph = getNumberOfStates();
+
+  const CodonAlphabet* ca = dynamic_cast<const CodonAlphabet*>(alphabet_);
+
+  for (i = 0; i < salph; i++)
+  {
+    for (j = 0; j < salph; j++)
+    {
+      if (ca->isStop(static_cast<int>(i)) || ca->isStop(static_cast<int>(j)))
+      {
+        generator_(i, j) = 0;
+      }
+      else
+        generator_(i, j) *= getCodonsMulRate(i, j);
+    }
+  }
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Codon/AbstractCodonSubstitutionModel.h b/src/Bpp/Phyl/Model/Codon/AbstractCodonSubstitutionModel.h
new file mode 100644
index 0000000..f87cdae
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/AbstractCodonSubstitutionModel.h
@@ -0,0 +1,172 @@
+//
+// File: AbstractCodonSubstitutionModel.h
+// Created by: Laurent Gueguen
+// Created on: Tue Dec 24 11:03:53 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _ABSTRACTCODONSUBSTITUTIONMODEL_H_
+#define _ABSTRACTCODONSUBSTITUTIONMODEL_H_
+
+#include "../AbstractWordSubstitutionModel.h"
+#include "../Nucleotide/NucleotideSubstitutionModel.h"
+#include "CodonSubstitutionModel.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/CodonAlphabet.h>
+
+namespace bpp
+{
+/**
+ * @brief Abstract class for substitution models on codons.
+ * @author Laurent Guéguen
+ *
+ * Objects of this class are built from either one (repeated three
+ * times) or three different substitution models of NucleicAlphabets.
+ * No model is directly accessible. </p>
+ *
+ * Only substitutions with one letter changed are accepted. </p>
+ *
+ * There is one substitution per codon per unit of time
+ * on the equilibrium frequency, and each position has its specific rate.
+ *
+ * The parameters of this codon are the same as the ones of the models
+ * used. Their names have a new prefix, "i_" where i stands for the
+ * the phase (1,2 or 3) in the codon.
+ */
+
+class AbstractCodonSubstitutionModel :
+  public virtual CodonSubstitutionModel,
+  public virtual AbstractWordSubstitutionModel
+{
+private:
+  /**
+   * @brief boolean for the parametrization of the position relative
+   * rates. Default : false.
+   *
+   */
+  bool hasParametrizedRates_;
+
+public:
+  /**
+   * @brief Build a new AbstractCodonSubstitutionModel object from
+   * a pointer to a NucleotideSubstitutionModel.
+   *
+   * @param palph pointer to a CodonAlphabet
+   * @param pmod pointer to the NucleotideSubstitutionModel to use in
+   *        the three positions. It is owned by the instance.
+   * @param st string of the Namespace
+   * @param paramRates boolean concerning the presence of position
+   * relative rates (default: false)
+   */
+
+  AbstractCodonSubstitutionModel(const CodonAlphabet* palph,
+                                 NucleotideSubstitutionModel* pmod,
+                                 const std::string& st,
+                                 bool paramRates = false);
+
+  /**
+   * @brief Build a new AbstractCodonSubstitutionModel object
+   * from three pointers to NucleotideSubstitutionModels.
+   *
+   * @param palph pointer to a CodonAlphabet
+   * @param pmod1, pmod2, pmod3 are pointers to the
+   *   NucleotideSubstitutionModel to use in the three positions.
+   *   All the models must be different objects to avoid redundant
+   *   parameters.  They are owned by the instance.
+   * @param st string of the Namespace
+   * @param paramRates boolean concerning the presence of position
+   * relative rates (default: false)
+   */
+
+  AbstractCodonSubstitutionModel(const CodonAlphabet*,
+                                 NucleotideSubstitutionModel* pmod1,
+                                 NucleotideSubstitutionModel* pmod2,
+                                 NucleotideSubstitutionModel* pmod3,
+                                 const std::string& st,
+                                 bool paramRates = false);
+
+
+  virtual ~AbstractCodonSubstitutionModel() {}
+
+  AbstractCodonSubstitutionModel(const AbstractCodonSubstitutionModel& model) :
+    AbstractParameterAliasable(model),
+    AbstractSubstitutionModel(model),
+    AbstractWordSubstitutionModel(model),
+    hasParametrizedRates_(model.hasParametrizedRates_)
+  {}
+
+  AbstractCodonSubstitutionModel& operator=(const AbstractCodonSubstitutionModel& model)
+  {
+    AbstractParameterAliasable::operator=(model);
+    AbstractSubstitutionModel::operator=(model);
+    AbstractWordSubstitutionModel::operator=(model);
+    hasParametrizedRates_ = model.hasParametrizedRates_;
+    return *this;
+  }
+
+#ifndef NO_VIRTUAL_COV
+  AbstractCodonSubstitutionModel*
+#else
+  Clonable*
+#endif
+  clone() const = 0;
+
+protected:
+  /**
+   * @brief Method inherited from AbstractWordSubstitutionModel
+   *
+   * This method sets the rates to/from stop codons to zero and
+   * performs the multiplication by the specific codon-codon rate.
+   *
+   **/
+
+  void completeMatrices();
+
+public:
+  void updateMatrices();
+
+  /**
+   * @brief Method inherited from CodonSubstitutionModel
+   *
+   * Here this methods returns 1;
+   *
+   **/
+  virtual double getCodonsMulRate(size_t i, size_t j) const { return 1.; }
+};
+} // end of namespace bpp.
+
+#endif
+
diff --git a/src/Bpp/Phyl/Model/Codon/CodonDistanceFitnessPhaseFrequenciesSubstitutionModel.cpp b/src/Bpp/Phyl/Model/Codon/CodonDistanceFitnessPhaseFrequenciesSubstitutionModel.cpp
new file mode 100644
index 0000000..6e5d28b
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/CodonDistanceFitnessPhaseFrequenciesSubstitutionModel.cpp
@@ -0,0 +1,115 @@
+//
+// File: CodonDistanceFitnessPhaseFrequenciesSubstitutionModel.cpp
+// Created by: Fanny Pouyet 
+// Created on: February 2012
+//
+ 
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+ 
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+ 
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+ 
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developi_ng or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+ 
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+
+#include "CodonDistanceFitnessPhaseFrequenciesSubstitutionModel.h"
+using namespace bpp;
+using namespace std;
+
+CodonDistanceFitnessPhaseFrequenciesSubstitutionModel::CodonDistanceFitnessPhaseFrequenciesSubstitutionModel(const GeneticCode* palph,
+                                                             NucleotideSubstitutionModel* pmod,
+                                                             FrequenciesSet* pfit,
+                                                             FrequenciesSet* pfreq,
+                                                             const AlphabetIndex2* pdist) :
+  AbstractParameterAliasable("CodonDistFitPhasFreq."),
+  AbstractSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), "CodonDistFitPhasFreq."),
+  AbstractWordSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), "CodonDistFitPhasFreq."),
+  AbstractCodonSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), pmod, "CodonDistFitPhasFreq."),
+  AbstractCodonDistanceSubstitutionModel(palph, pdist, "CodonDistFitPhasFreq."),
+  AbstractCodonPhaseFrequenciesSubstitutionModel(pfreq, "CodonDistFitPhasFreq."),
+  AbstractCodonFitnessSubstitutionModel(pfit, "CodonDistFitPhasFreq.")
+{
+  updateMatrices();
+}
+
+CodonDistanceFitnessPhaseFrequenciesSubstitutionModel::CodonDistanceFitnessPhaseFrequenciesSubstitutionModel(const GeneticCode* palph,
+                                                             NucleotideSubstitutionModel* pmod1,
+                                                             NucleotideSubstitutionModel* pmod2,
+                                                             NucleotideSubstitutionModel* pmod3,
+                                                             FrequenciesSet* pfit,
+                                                             FrequenciesSet* pfreq,
+                                                             const AlphabetIndex2* pdist) :
+  AbstractParameterAliasable("CodonDistFitPhasFreq."),
+  AbstractSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), "CodonDistFitPhasFreq."),
+  AbstractWordSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), "CodonDistFitPhasFreq."),
+  AbstractCodonSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), pmod1, pmod2, pmod3, "CodonDistFitPhasFreq."),
+  AbstractCodonDistanceSubstitutionModel(palph, pdist, "CodonDistFitPhasFreq."),
+  AbstractCodonPhaseFrequenciesSubstitutionModel(pfreq, "CodonDistFitPhasFreq."),
+  AbstractCodonFitnessSubstitutionModel(pfit,"CodonDistFitPhasFreq.")
+{
+  updateMatrices();
+}
+
+string CodonDistanceFitnessPhaseFrequenciesSubstitutionModel::getName() const
+{
+  return ("CodonDistFitPhasFreq");
+}
+
+void CodonDistanceFitnessPhaseFrequenciesSubstitutionModel::fireParameterChanged(const ParameterList& parameters)
+{
+  AbstractCodonDistanceSubstitutionModel::fireParameterChanged(parameters);
+  AbstractCodonPhaseFrequenciesSubstitutionModel::fireParameterChanged(parameters);
+  AbstractCodonFitnessSubstitutionModel::fireParameterChanged(parameters);
+
+  AbstractCodonSubstitutionModel::fireParameterChanged(parameters);
+}
+
+double CodonDistanceFitnessPhaseFrequenciesSubstitutionModel::getCodonsMulRate(size_t i, size_t j) const
+{
+  return AbstractCodonDistanceSubstitutionModel::getCodonsMulRate(i,j)
+    * AbstractCodonSubstitutionModel::getCodonsMulRate(i,j)
+    * AbstractCodonPhaseFrequenciesSubstitutionModel::getCodonsMulRate(i,j)
+    * AbstractCodonFitnessSubstitutionModel::getCodonsMulRate(i,j);
+}
+
+void CodonDistanceFitnessPhaseFrequenciesSubstitutionModel::setNamespace(const std::string& st)
+{
+  AbstractParameterAliasable::setNamespace(st);
+  AbstractCodonSubstitutionModel::setNamespace(st);
+  AbstractCodonDistanceSubstitutionModel::setNamespace(st);
+  AbstractCodonPhaseFrequenciesSubstitutionModel::setNamespace(st); 
+  AbstractCodonFitnessSubstitutionModel::setNamespace(st);
+}
+
+void CodonDistanceFitnessPhaseFrequenciesSubstitutionModel::setFreq(map<int,double>& frequencies)
+{
+  AbstractCodonPhaseFrequenciesSubstitutionModel::setFreq(frequencies);
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Codon/CodonDistanceFitnessPhaseFrequenciesSubstitutionModel.h b/src/Bpp/Phyl/Model/Codon/CodonDistanceFitnessPhaseFrequenciesSubstitutionModel.h
new file mode 100644
index 0000000..f044327
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/CodonDistanceFitnessPhaseFrequenciesSubstitutionModel.h
@@ -0,0 +1,161 @@
+//
+// File: CodonDistanceFitnessPhaseFrequenciesSubstitutionModel.h
+// Created by: Fanny Pouyet 
+// Created on: mars 2012
+//
+ 
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+ 
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+ 
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+ 
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+ 
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+ 
+#ifndef _CODONDISTANCEFITNESSPHASEFREQUENCIESSUBSTITUTIONMODEL_H_
+#define _CODONDISTANCEFITNESSPHASEFREQUENCIESSUBSTITUTIONMODEL_H_
+ 
+#include "AbstractCodonFitnessSubstitutionModel.h"
+#include "AbstractCodonSubstitutionModel.h"
+#include "AbstractCodonDistanceSubstitutionModel.h"
+#include "AbstractCodonPhaseFrequenciesSubstitutionModel.h"
+
+namespace bpp
+{
+  /**
+   * @brief Class for asynonymous and synonymous substitution models
+   * on codons with parameterized equilibrium frequencies and
+   * nucleotidic basic models.
+   *
+   * @author Fanny Pouyet, Laurent Guéguen
+   *
+   * This class should be used with models which equilibrium
+   * distribution is fixed, ans does not depend on the parameters.
+   * Otherwise there may be problems of identifiability of the
+   * parameters.
+   *
+   * See description in AbstractCodonDistanceSubstitutionModel
+   * class, AbstractCodonPhaseFrequenciesSubstitutionModel class,
+   * AbstractCodonFitnessSubstitutionModel class.
+   *
+   * Only substitutions with one letter changed are accepted. </p>
+   *
+   * The additional parameter to CodonPhaseFrequenciesSubstitutionModel
+   * is the ratio of nonsynonymous over synonymous substitutions.
+   *
+   * If a distance @f$d at f$ between amino-acids is defined, the ratio between
+   * non-synonymous and synonymous substitutions rates is, if the codied
+   * amino-acids are @f$x at f$ and @f$y at f$, @f$\beta*\exp(-\alpha.d(x,y))@f$ with
+   * non-negative parameter \c "alpha" and positive parameter \c "beta".
+   *
+   * If such a distance is not defined, the ratio between
+   * non-synonymous and synonymous substitutions rates is
+   * @f$\beta at f$ with positive parameter \c "beta".
+   *
+   * The fitness of a codon is a value between 0 and 1 defining the
+   * relative advantage of a codon, compared to others. If a codon
+   * @f$i at f$ has a fitness @f$\phi_i at f$ and another one (@f$j at f$)
+   * has a fitness @f$\phi_j at f$, the substitution rate from codon
+   * @f$i at f$ to codon @f$j at f$ is multiplied by
+   * \f[-\frac{\log(\frac{\phi_i}{\phi_j})}{1-\frac{\phi_i}{\phi_j}}\f]
+   * The set of fitnesses is implemented through a Codon
+   * FrequenciesSet object. The parameters are named \c
+   * "fit_NameOfTheParameterInTheFrequenciesSet".
+   *
+   * Reference:
+   * -  Yang Z. and Nielsen R. (2008), _Molecular Biology and Evolution_ 25(3):568--579.
+   */
+
+
+  class CodonDistanceFitnessPhaseFrequenciesSubstitutionModel :
+    public AbstractCodonSubstitutionModel,
+    public AbstractCodonDistanceSubstitutionModel,
+    public AbstractCodonPhaseFrequenciesSubstitutionModel,
+    public AbstractCodonFitnessSubstitutionModel
+  {
+  public:
+    CodonDistanceFitnessPhaseFrequenciesSubstitutionModel(const GeneticCode* palph,
+                                  NucleotideSubstitutionModel* pmod,
+                                  FrequenciesSet* pfit,
+                                  FrequenciesSet* pfreq,
+                                  const AlphabetIndex2* pdist = 0);
+    CodonDistanceFitnessPhaseFrequenciesSubstitutionModel(const GeneticCode* palph,
+                                  NucleotideSubstitutionModel* pmod1,
+                                  NucleotideSubstitutionModel* pmod2,
+                                  NucleotideSubstitutionModel* pmod3,
+                                  FrequenciesSet* pfit,
+                                  FrequenciesSet* pfreq,
+                                  const AlphabetIndex2* pdist = 0);
+
+    CodonDistanceFitnessPhaseFrequenciesSubstitutionModel(const CodonDistanceFitnessPhaseFrequenciesSubstitutionModel& model) :
+      AbstractParameterAliasable(model),
+      AbstractSubstitutionModel(model),
+      AbstractWordSubstitutionModel(model),
+      AbstractCodonSubstitutionModel(model),
+      AbstractCodonDistanceSubstitutionModel(model),
+      AbstractCodonPhaseFrequenciesSubstitutionModel(model),
+      AbstractCodonFitnessSubstitutionModel(model)
+    {}
+
+    CodonDistanceFitnessPhaseFrequenciesSubstitutionModel& operator=(
+                                                                     const CodonDistanceFitnessPhaseFrequenciesSubstitutionModel& model)
+    {
+      AbstractParameterAliasable::operator=(model);
+      AbstractSubstitutionModel::operator=(model);
+      AbstractWordSubstitutionModel::operator=(model);
+      AbstractCodonSubstitutionModel::operator=(model);
+      AbstractCodonDistanceSubstitutionModel::operator=(model);
+      AbstractCodonPhaseFrequenciesSubstitutionModel::operator=(model);
+      AbstractCodonFitnessSubstitutionModel::operator=(model);
+      return *this;
+    }
+
+    ~CodonDistanceFitnessPhaseFrequenciesSubstitutionModel() {}
+
+    CodonDistanceFitnessPhaseFrequenciesSubstitutionModel* clone() const
+    {
+      return new CodonDistanceFitnessPhaseFrequenciesSubstitutionModel(*this);
+    }
+
+  public:
+    void fireParameterChanged(const ParameterList& parameterlist);
+
+    std::string getName() const;
+
+    double getCodonsMulRate(size_t i, size_t j) const;
+
+    void setNamespace(const std::string&);
+
+    void setFreq(std::map<int,double>& frequencies);
+
+  };
+
+} // end of namespace bpp.
+
+#endif
+
diff --git a/src/Bpp/Phyl/Model/Codon/CodonDistanceFrequenciesSubstitutionModel.cpp b/src/Bpp/Phyl/Model/Codon/CodonDistanceFrequenciesSubstitutionModel.cpp
new file mode 100644
index 0000000..58fe922
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/CodonDistanceFrequenciesSubstitutionModel.cpp
@@ -0,0 +1,111 @@
+//
+// File: CodonDistanceFrequenciesSubstitutionModel.cpp
+// Created by:  Laurent Gueguen
+// Created on: Feb 2009
+//
+
+/*
+  Copyright or © or Copr. CNRS, (November 16, 2004)
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "CodonDistanceFrequenciesSubstitutionModel.h"
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+CodonDistanceFrequenciesSubstitutionModel::CodonDistanceFrequenciesSubstitutionModel(const GeneticCode* palph,
+                                                                                     NucleotideSubstitutionModel* pmod,
+                                                                                     FrequenciesSet* pfreq,
+                                                                                     const AlphabetIndex2* pdist,
+                                                                                     bool paramSynRate) :
+  AbstractParameterAliasable("CodonDistFreq."),
+  AbstractSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), "CodonDistFreq."),
+  AbstractWordSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), "CodonDistFreq."),
+  AbstractCodonSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), pmod, "CodonDistFreq."),
+  AbstractCodonDistanceSubstitutionModel(palph, pdist, "CodonDistFreq.", paramSynRate),
+  AbstractCodonFrequenciesSubstitutionModel(pfreq, "CodonDistFreq.")
+{
+  updateMatrices();
+}
+
+CodonDistanceFrequenciesSubstitutionModel::CodonDistanceFrequenciesSubstitutionModel(const GeneticCode* palph,
+                                                                                     NucleotideSubstitutionModel* pmod1,
+                                                                                     NucleotideSubstitutionModel* pmod2,
+                                                                                     NucleotideSubstitutionModel* pmod3,
+                                                                                     FrequenciesSet* pfreq,
+                                                                                     const AlphabetIndex2* pdist,
+                                                                                     bool paramSynRate) :
+  AbstractParameterAliasable("CodonDistFreq."),
+  AbstractSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), "CodonDistFreq."),
+  AbstractWordSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), "CodonDistFreq."),
+  AbstractCodonSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), pmod1, pmod2, pmod3, "CodonDistFreq."),
+  AbstractCodonDistanceSubstitutionModel(palph, pdist, "CodonDistFreq.", paramSynRate),
+  AbstractCodonFrequenciesSubstitutionModel(pfreq, "CodonDistFreq.")
+{
+  updateMatrices();
+}
+
+std::string CodonDistanceFrequenciesSubstitutionModel::getName() const
+{
+  return "CodonDistFreq";
+}
+
+void CodonDistanceFrequenciesSubstitutionModel::fireParameterChanged(const ParameterList& parameters)
+{
+  AbstractCodonDistanceSubstitutionModel::fireParameterChanged(parameters);
+  AbstractCodonFrequenciesSubstitutionModel::fireParameterChanged(parameters);
+
+  // Beware: must be call at the end
+  AbstractCodonSubstitutionModel::fireParameterChanged(parameters);
+}
+
+double CodonDistanceFrequenciesSubstitutionModel::getCodonsMulRate(size_t i, size_t j) const
+{
+  return AbstractCodonDistanceSubstitutionModel::getCodonsMulRate(i,j)
+    * AbstractCodonSubstitutionModel::getCodonsMulRate(i,j)
+    * AbstractCodonFrequenciesSubstitutionModel::getCodonsMulRate(i,j);
+}
+
+void CodonDistanceFrequenciesSubstitutionModel::setNamespace(const std::string& st)
+{
+  AbstractParameterAliasable::setNamespace(st);
+  AbstractCodonSubstitutionModel::setNamespace(st);
+  AbstractCodonDistanceSubstitutionModel::setNamespace(st);
+  AbstractCodonFrequenciesSubstitutionModel::setNamespace(st);
+}
+
+void CodonDistanceFrequenciesSubstitutionModel::setFreq(map<int,double>& frequencies)
+{
+  AbstractCodonFrequenciesSubstitutionModel::setFreq(frequencies);
+}
diff --git a/src/Bpp/Phyl/Model/Codon/CodonDistanceFrequenciesSubstitutionModel.h b/src/Bpp/Phyl/Model/Codon/CodonDistanceFrequenciesSubstitutionModel.h
new file mode 100644
index 0000000..05bb7fa
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/CodonDistanceFrequenciesSubstitutionModel.h
@@ -0,0 +1,183 @@
+//
+// File: CodonDistanceFrequenciesSubstitutionModel.h
+// Created by: Laurent Gueguen
+// Created on: lundi 19 septembre 2011, à 11h 47
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _CODONDISTANCEFREQUENCIESSUBSTITUTIONMODEL_H_
+#define _CODONDISTANCEFREQUENCIESSUBSTITUTIONMODEL_H_
+
+#include "AbstractCodonSubstitutionModel.h"
+#include "AbstractCodonDistanceSubstitutionModel.h"
+#include "AbstractCodonFrequenciesSubstitutionModel.h"
+
+namespace bpp
+{
+/**
+ * @brief Class for asynonymous substitution models on codons with
+ * parameterized equilibrium frequencies and nucleotidic models.
+ * @author Laurent Guéguen
+ *
+ * This class should be used with models which equilibrium
+ * distribution is fixed, ans does not depend on the parameters.
+ * Otherwise there may be problems of identifiability of the
+ * parameters.
+ *
+ * See description in AbstractCodonDistanceSubstitutionModel and
+ * AbstractCodonFrequenciesSubstitutionModel class.
+ *
+ * Only substitutions with one letter changed are accepted. </p>
+ *
+ * The additional parameters to CodonFrequenciesSubstitutionModel are
+ * the rates of nonsynonymous over synonymous substitutions.
+ *
+ * If a distance @f$d at f$ between amino-acids is defined, the
+ *  non-synonymous rate is multiplied with, if the coded amino-acids
+ *  are @f$x at f$ and @f$y at f$, @f$\beta*\exp(-\alpha.d(x,y))@f$ with
+ *  non-negative parameter \c "alpha" and positive parameter \c
+ *  "beta".
+ *
+ * If such a distance is not defined, the non-synonymous substitution
+ *  rate is multiplied with @f$\beta at f$ with positive parameter \c
+ *  "beta" (ie @f$d=0 at f$).
+ *
+ * If paramSynRate is true, the synonymous substitution rate is
+ *  multiplied with @f$\gamma at f$ (with optional positive parameter \c
+ *  "gamma"), else it is multiplied with 1.
+ *
+ * If such a distance is not defined, the ratio between non-synonymous
+ * and synonymous substitutions rates is @f$\beta at f$ with positive
+ * parameter \c "beta".
+ */
+
+class CodonDistanceFrequenciesSubstitutionModel :
+    public AbstractCodonSubstitutionModel,
+    public AbstractCodonDistanceSubstitutionModel,
+    public AbstractCodonFrequenciesSubstitutionModel
+{
+public:
+  /**
+   * @brief Build a new CodonDistanceFrequenciesSubstitutionModel object
+   * from three pointers to AbstractSubstitutionModels. NEW
+   * AbstractSubstitutionModels are copied from the given ones.
+   *
+   * @param palph pointer to a GeneticCode
+   * @param pmod pointer to the NucleotideSubstitutionModel to use in
+   *        the three positions. It is owned by the instance.
+   * @param pfreq pointer to the FrequenciesSet* equilibrium frequencies
+   * @param pdist optional pointer to the AlphabetIndex2 amino-acids
+   *        distance object.
+   * @param paramSynRate is true iff synonymous rate is parametrised
+   *        (default=false).
+   */
+  CodonDistanceFrequenciesSubstitutionModel(const GeneticCode* palph,
+                                            NucleotideSubstitutionModel* pmod,
+                                            FrequenciesSet* pfreq,
+                                            const AlphabetIndex2* pdist = 0,
+                                            bool paramSynRate = false);
+
+  /**
+   * @brief Build a new CodonDistanceFrequenciesSubstitutionModel object
+   * from three pointers to AbstractSubstitutionModels. NEW
+   * AbstractSubstitutionModels are copied from the given ones.
+   *
+   * @param palph pointer to a GeneticCode
+   * @param pmod1, pmod2, pmod3 are pointers to the
+   *   NucleotideSubstitutionModel to use in the three positions.
+   *   All the models must be different objects to avoid redundant
+   *   parameters.  They are owned by the instance.
+   * @param pfreq pointer to the FrequenciesSet* equilibrium frequencies
+   * @param pdist optional pointer to the AlphabetIndex2 amino-acids
+   *   distance object.
+   * @param paramSynRate is true iff synonymous rate is parametrised
+   *   (default=false).
+   */
+  CodonDistanceFrequenciesSubstitutionModel(const GeneticCode* palph,
+                                            NucleotideSubstitutionModel* pmod1,
+                                            NucleotideSubstitutionModel* pmod2,
+                                            NucleotideSubstitutionModel* pmod3,
+                                            FrequenciesSet* pfreq,
+                                            const AlphabetIndex2* pdist = 0,
+                                            bool paramSynRate = false);
+
+
+  CodonDistanceFrequenciesSubstitutionModel(
+    const CodonDistanceFrequenciesSubstitutionModel& model) :
+    AbstractParameterAliasable(model),
+    AbstractSubstitutionModel(model),
+    AbstractWordSubstitutionModel(model),
+    AbstractCodonSubstitutionModel(model),
+    AbstractCodonDistanceSubstitutionModel(model),
+    AbstractCodonFrequenciesSubstitutionModel(model)
+  {
+  }
+
+  CodonDistanceFrequenciesSubstitutionModel& operator=(
+    const CodonDistanceFrequenciesSubstitutionModel& model)
+  {
+    AbstractParameterAliasable::operator=(model);
+    AbstractSubstitutionModel::operator=(model);
+    AbstractWordSubstitutionModel::operator=(model);
+    AbstractCodonSubstitutionModel::operator=(model);
+    AbstractCodonDistanceSubstitutionModel::operator=(model);
+    AbstractCodonFrequenciesSubstitutionModel::operator=(model);
+    return *this;
+  }
+
+  ~CodonDistanceFrequenciesSubstitutionModel() {}
+
+  CodonDistanceFrequenciesSubstitutionModel* clone() const
+  {
+    return new CodonDistanceFrequenciesSubstitutionModel(*this);
+  }
+
+public:
+  void fireParameterChanged(const ParameterList& parameterlist);
+
+  std::string getName() const;
+
+  double getCodonsMulRate(size_t i, size_t j) const;
+
+  void setNamespace(const std::string&);
+
+  void setFreq(std::map<int,double>& frequencies);
+
+};
+
+} // end of namespace bpp.
+
+#endif
+
diff --git a/src/Bpp/Phyl/Model/Codon/CodonDistancePhaseFrequenciesSubstitutionModel.cpp b/src/Bpp/Phyl/Model/Codon/CodonDistancePhaseFrequenciesSubstitutionModel.cpp
new file mode 100644
index 0000000..e5d82c3
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/CodonDistancePhaseFrequenciesSubstitutionModel.cpp
@@ -0,0 +1,109 @@
+//
+// File: CodonDistancePhaseFrequenciesSubstitutionModel.cpp
+// Created by:  Laurent Gueguen
+// Created on: Feb 2009
+//
+
+/*
+  Copyright or © or Copr. CNRS, (November 16, 2004)
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "CodonDistancePhaseFrequenciesSubstitutionModel.h"
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+CodonDistancePhaseFrequenciesSubstitutionModel::CodonDistancePhaseFrequenciesSubstitutionModel(const GeneticCode* palph,
+                                                                                     NucleotideSubstitutionModel* pmod,
+                                                                                     FrequenciesSet* pfreq,
+                                                                                     const AlphabetIndex2* pdist) :
+  AbstractParameterAliasable("CodonDistPhasFreq."),
+  AbstractSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), "CodonDistPhasFreq."),
+  AbstractWordSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), "CodonDistPhasFreq."),
+  AbstractCodonSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), pmod, "CodonDistPhasFreq."),
+  AbstractCodonDistanceSubstitutionModel(palph, pdist, "CodonDistPhasFreq."),
+  AbstractCodonPhaseFrequenciesSubstitutionModel(pfreq, "CodonDistPhasFreq.")
+{
+  updateMatrices();
+}
+
+CodonDistancePhaseFrequenciesSubstitutionModel::CodonDistancePhaseFrequenciesSubstitutionModel(const GeneticCode* palph,
+                                                                                     NucleotideSubstitutionModel* pmod1,
+                                                                                     NucleotideSubstitutionModel* pmod2,
+                                                                                     NucleotideSubstitutionModel* pmod3,
+                                                                                     FrequenciesSet* pfreq,
+                                                                                     const AlphabetIndex2* pdist) :
+  AbstractParameterAliasable("CodonDistPhasFreq."),
+  AbstractSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), "CodonDistPhasFreq."),
+  AbstractWordSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), "CodonDistPhasFreq."),
+  AbstractCodonSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()), pmod1, pmod2, pmod3, "CodonDistPhasFreq."),
+  AbstractCodonDistanceSubstitutionModel(palph, pdist, "CodonDistPhasFreq."),
+  AbstractCodonPhaseFrequenciesSubstitutionModel(pfreq, "CodonDistPhasFreq.")
+{
+  updateMatrices();
+}
+
+std::string CodonDistancePhaseFrequenciesSubstitutionModel::getName() const
+{
+  return ("CodonDistPhasFreq");
+}
+
+void CodonDistancePhaseFrequenciesSubstitutionModel::fireParameterChanged(const ParameterList& parameters)
+{
+  AbstractCodonDistanceSubstitutionModel::fireParameterChanged(parameters);
+  AbstractCodonPhaseFrequenciesSubstitutionModel::fireParameterChanged(parameters);
+  
+  // Beware: must be call at the end
+  AbstractCodonSubstitutionModel::fireParameterChanged(parameters);
+}
+
+double CodonDistancePhaseFrequenciesSubstitutionModel::getCodonsMulRate(size_t i, size_t j) const
+{
+  return AbstractCodonDistanceSubstitutionModel::getCodonsMulRate(i,j)
+    * AbstractCodonSubstitutionModel::getCodonsMulRate(i,j)
+    * AbstractCodonPhaseFrequenciesSubstitutionModel::getCodonsMulRate(i,j);
+}
+
+void CodonDistancePhaseFrequenciesSubstitutionModel::setNamespace(const std::string& st)
+{
+  AbstractParameterAliasable::setNamespace(st);
+  AbstractCodonSubstitutionModel::setNamespace(st);
+  AbstractCodonDistanceSubstitutionModel::setNamespace(st);
+  AbstractCodonPhaseFrequenciesSubstitutionModel::setNamespace(st);
+}
+
+void CodonDistancePhaseFrequenciesSubstitutionModel::setFreq(map<int,double>& frequencies)
+{
+  AbstractCodonPhaseFrequenciesSubstitutionModel::setFreq(frequencies);
+}
diff --git a/src/Bpp/Phyl/Model/Codon/CodonDistancePhaseFrequenciesSubstitutionModel.h b/src/Bpp/Phyl/Model/Codon/CodonDistancePhaseFrequenciesSubstitutionModel.h
new file mode 100644
index 0000000..7a7c192
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/CodonDistancePhaseFrequenciesSubstitutionModel.h
@@ -0,0 +1,164 @@
+//
+// File: CodonDistancePhaseFrequenciesSubstitutionModel.h
+// Created by: Laurent Gueguen
+// Created on: lundi 19 septembre 2011, à 11h 47
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _CODONDISTANCEPHASEFREQUENCIESSUBSTITUTIONMODEL_H_
+#define _CODONDISTANCEPHASEFREQUENCIESSUBSTITUTIONMODEL_H_
+
+#include "AbstractCodonSubstitutionModel.h"
+#include "AbstractCodonDistanceSubstitutionModel.h"
+#include "AbstractCodonPhaseFrequenciesSubstitutionModel.h"
+
+namespace bpp
+{
+/**
+ * @brief Class for asynonymous substitution models on codons with
+ * parameterized equilibrium frequencies and nucleotidic basic models.
+ *
+ * @author Laurent Guéguen
+ *
+ * This class should be used with models which equilibrium
+ * distribution is fixed, ans does not depend on the parameters.
+ * Otherwise there may be problems of identifiability of the
+ * parameters.
+ *
+ * See description in AbstractCodonDistanceSubstitutionModel and
+ * AbstractCodonPhaseFrequenciesSubstitutionModel class.
+ *
+ * Only substitutions with one letter changed are accepted. </p>
+ *
+ * The additional parameter to CodonPhaseFrequenciesSubstitutionModel
+ * is the ratio of nonsynonymous over synonymous substitutions.
+ *
+ * If a distance @f$d at f$ between amino-acids is defined, the ratio between
+ * non-synonymous and synonymous substitutions rates is, if the codied
+ * amino-acids are @f$x at f$ and @f$y at f$, @f$\beta*\exp(-\alpha.d(x,y))@f$ with
+ * non-negative parameter \c "alpha" and positive parameter \c "beta".
+ *
+ * If such a distance is not defined, the ratio between non-synonymous
+ * and synonymous substitutions rates is @f$\beta at f$ with positive
+ * parameter \c "beta".
+ */
+
+class CodonDistancePhaseFrequenciesSubstitutionModel :
+    public AbstractCodonSubstitutionModel,
+    public AbstractCodonDistanceSubstitutionModel,
+    public AbstractCodonPhaseFrequenciesSubstitutionModel
+{
+public:
+  /**
+   * @brief Build a new CodonDistancePhaseFrequenciesSubstitutionModel object
+   * from three pointers to AbstractSubstitutionModels. NEW
+   * AbstractSubstitutionModels are copied from the given ones.
+   *
+   * @param palph pointer to a GeneticCode
+   * @param pmod pointer to the NucleotideSubstitutionModel to use in
+   *        the three positions. It is owned by the instance.
+   * @param pfreq pointer to the FrequenciesSet* equilibrium frequencies
+   * @param pdist optional pointer to the AlphabetIndex2 amino-acids distance object.
+   */
+  CodonDistancePhaseFrequenciesSubstitutionModel(const GeneticCode* palph,
+                                            NucleotideSubstitutionModel* pmod,
+                                            FrequenciesSet* pfreq,
+                                            const AlphabetIndex2* pdist = 0);
+
+  /**
+   * @brief Build a new CodonDistancePhaseFrequenciesSubstitutionModel object
+   * from three pointers to AbstractSubstitutionModels. NEW
+   * AbstractSubstitutionModels are copied from the given ones.
+   *
+   * @param palph pointer to a GeneticCode
+   * @param pmod1, pmod2, pmod3 are pointers to the
+   *   NucleotideSubstitutionModel to use in the three positions.
+   *   All the models must be different objects to avoid redundant
+   *   parameters.  They are owned by the instance.
+   * @param pfreq pointer to the FrequenciesSet* equilibrium frequencies
+   * @param pdist optional pointer to the AlphabetIndex2 amino-acids distance object.
+   */
+  CodonDistancePhaseFrequenciesSubstitutionModel(const GeneticCode* palph,
+                                            NucleotideSubstitutionModel* pmod1,
+                                            NucleotideSubstitutionModel* pmod2,
+                                            NucleotideSubstitutionModel* pmod3,
+                                            FrequenciesSet* pfreq,
+                                            const AlphabetIndex2* pdist = 0);
+
+  CodonDistancePhaseFrequenciesSubstitutionModel(
+    const CodonDistancePhaseFrequenciesSubstitutionModel& model) :
+    AbstractParameterAliasable(model),
+    AbstractSubstitutionModel(model),
+    AbstractWordSubstitutionModel(model),
+    AbstractCodonSubstitutionModel(model),
+    AbstractCodonDistanceSubstitutionModel(model),
+    AbstractCodonPhaseFrequenciesSubstitutionModel(model)
+  {}
+
+  CodonDistancePhaseFrequenciesSubstitutionModel& operator=(
+    const CodonDistancePhaseFrequenciesSubstitutionModel& model)
+  {
+    AbstractParameterAliasable::operator=(model);
+    AbstractSubstitutionModel::operator=(model);
+    AbstractWordSubstitutionModel::operator=(model);
+    AbstractCodonSubstitutionModel::operator=(model);
+    AbstractCodonDistanceSubstitutionModel::operator=(model);
+    AbstractCodonPhaseFrequenciesSubstitutionModel::operator=(model);
+    return *this;
+  }
+
+  ~CodonDistancePhaseFrequenciesSubstitutionModel() {}
+
+  CodonDistancePhaseFrequenciesSubstitutionModel* clone() const
+  {
+    return new CodonDistancePhaseFrequenciesSubstitutionModel(*this);
+  }
+
+public:
+  void fireParameterChanged(const ParameterList& parameterlist);
+
+  std::string getName() const;
+
+  double getCodonsMulRate(size_t i, size_t j) const;
+
+  void setNamespace(const std::string&);
+
+  void setFreq(std::map<int,double>& frequencies);
+};
+
+} // end of namespace bpp.
+
+#endif
+
diff --git a/src/Bpp/Phyl/Model/Codon/CodonDistanceSubstitutionModel.cpp b/src/Bpp/Phyl/Model/Codon/CodonDistanceSubstitutionModel.cpp
new file mode 100644
index 0000000..fbe750e
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/CodonDistanceSubstitutionModel.cpp
@@ -0,0 +1,97 @@
+//
+// File: CodonDistanceSubstitutionModel.cpp
+// Created by:  Laurent Gueguen
+// Created on: Feb 2009
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "CodonDistanceSubstitutionModel.h"
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+CodonDistanceSubstitutionModel::CodonDistanceSubstitutionModel(const GeneticCode* palph,
+                                                               NucleotideSubstitutionModel* pmod,
+                                                               const AlphabetIndex2* pdist) :
+  AbstractParameterAliasable("CodonDist."),
+  AbstractSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()),
+      "CodonDist."),
+  AbstractWordSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()),
+      "CodonDist."),
+  AbstractCodonSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()),
+      pmod, "CodonDist."),
+  AbstractCodonDistanceSubstitutionModel(palph, pdist, "CodonDist.")
+{
+  updateMatrices();
+}
+
+CodonDistanceSubstitutionModel::CodonDistanceSubstitutionModel(const GeneticCode* palph,
+                                                               NucleotideSubstitutionModel* pmod1,
+                                                               NucleotideSubstitutionModel* pmod2,
+                                                               NucleotideSubstitutionModel* pmod3,
+                                                               const AlphabetIndex2* pdist) :
+  AbstractParameterAliasable("CodonDist."),
+  AbstractSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()),
+      "CodonDist."),
+  AbstractWordSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()),
+      "CodonDist."),
+  AbstractCodonSubstitutionModel(dynamic_cast<const CodonAlphabet*>(palph->getSourceAlphabet()),
+      pmod1, pmod2, pmod3, "CodonDist."),
+  AbstractCodonDistanceSubstitutionModel(palph, pdist, "CodonDist.")
+{
+  updateMatrices();
+}
+
+std::string CodonDistanceSubstitutionModel::getName() const
+{
+  return ("CodonDist");
+}
+
+void CodonDistanceSubstitutionModel::fireParameterChanged(const ParameterList& parameters)
+{
+  AbstractCodonDistanceSubstitutionModel::fireParameterChanged(parameters);
+
+  // Beware: must be call at the end
+  AbstractCodonSubstitutionModel::fireParameterChanged(parameters);
+}
+
+double CodonDistanceSubstitutionModel::getCodonsMulRate(size_t i, size_t j) const
+{
+  return AbstractCodonDistanceSubstitutionModel::getCodonsMulRate(i,j)
+    * AbstractCodonSubstitutionModel::getCodonsMulRate(i,j);
+}
+
diff --git a/src/Bpp/Phyl/Model/Codon/CodonDistanceSubstitutionModel.h b/src/Bpp/Phyl/Model/Codon/CodonDistanceSubstitutionModel.h
new file mode 100644
index 0000000..be939ca
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/CodonDistanceSubstitutionModel.h
@@ -0,0 +1,143 @@
+//
+// File: CodonDistanceSubstitutionModel.h
+// Created by: Laurent Gueguen
+// Created on: Tue Dec 24 11:03:53 2003
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _CODONDISTANCESUBSTITUTIONMODEL_H_
+#define _CODONDISTANCESUBSTITUTIONMODEL_H_
+
+#include "AbstractCodonDistanceSubstitutionModel.h"
+#include "AbstractCodonSubstitutionModel.h"
+
+namespace bpp
+{
+  /**
+   * @brief Class for substitution models of codons with
+   * non-synonymous/synonymous ratios of substitution rates defined
+   * through a distance between amino-acids.
+   *
+   * @author Laurent Guéguen
+   *
+   * Objects of this class are built from three substitution models of
+   * NucleicAlphabets. No model is directly accessible. </p>
+   *
+   * Only substitutions with one letter changed are accepted. </p>
+   *
+   * If a distance @f$d at f$ between amino-acids is defined, the ratio between
+   * non-synonymous and synonymous substitutions rates is, if the codied
+   * amino-acids are @f$x at f$ and @f$y at f$, @f$\beta*\exp(-\alpha.d(x,y))@f$ with
+   * non-negative parameter \c "alpha" and positive parameter \c "beta".
+   *
+   * If such a distance is not defined, the ratio between non-synonymous
+   * and synonymous substitutions rates is @f$\beta at f$ with positive
+   * parameter \c "beta".
+   *
+   */
+
+  class CodonDistanceSubstitutionModel :
+    public AbstractCodonSubstitutionModel,
+    public AbstractCodonDistanceSubstitutionModel
+  {
+  public:
+    /**
+     * @brief Build a new CodonDistanceSubstitutionModel object from
+     * a pointer to NucleotideSubstitutionModel.
+     *
+     * @param palph pointer to a GeneticCode
+     * @param pmod  pointer to the NucleotideSubstitutionModel to use in the three positions.
+     * The instance will then own this substitution model.
+     * @param pdist optional pointer to a distance between amino-acids
+     */
+    CodonDistanceSubstitutionModel(const GeneticCode* palph,
+                                   NucleotideSubstitutionModel* pmod,
+                                   const AlphabetIndex2* pdist);
+
+    /**
+     * @brief Build a new CodonDistanceSubstitutionModel object
+     * from three pointers to NucleotideSubstitutionModels.
+     *
+     * @param palph pointer to a GeneticCode
+     * @param pmod1, pmod2, pmod3 pointers to the
+     *   NucleotideSubstitutionModels to use in the three positions.
+     *   Either all the models are different objects to avoid parameters
+     *   redondancy, or only the first model is used in every position.
+     *   The used models are owned by the instance.
+     * @param pdist optional pointer to the AlphabetIndex2 amino-acids distance object.
+     */
+  
+    CodonDistanceSubstitutionModel(const GeneticCode* palph,
+                                   NucleotideSubstitutionModel* pmod1,
+                                   NucleotideSubstitutionModel* pmod2,
+                                   NucleotideSubstitutionModel* pmod3,
+                                   const AlphabetIndex2* pdist);
+
+    CodonDistanceSubstitutionModel(const CodonDistanceSubstitutionModel& model) :
+      AbstractParameterAliasable(model),
+      AbstractSubstitutionModel(model),
+      AbstractWordSubstitutionModel(model),
+      AbstractCodonSubstitutionModel(model),
+      AbstractCodonDistanceSubstitutionModel(model)
+    {}
+
+    CodonDistanceSubstitutionModel & operator=(const CodonDistanceSubstitutionModel& model)
+    {
+      AbstractParameterAliasable::operator=(model);
+      AbstractSubstitutionModel::operator=(model);
+      AbstractWordSubstitutionModel::operator=(model);
+      AbstractCodonSubstitutionModel::operator=(model);
+      AbstractCodonDistanceSubstitutionModel::operator=(model);
+      return *this;
+    }
+
+    ~CodonDistanceSubstitutionModel() {}
+
+    CodonDistanceSubstitutionModel* clone() const
+    {
+      return new CodonDistanceSubstitutionModel(*this);
+    }
+
+  public:
+    void fireParameterChanged(const ParameterList& parameterlist);
+  
+    std::string getName() const;
+
+    double getCodonsMulRate(size_t i, size_t j) const;
+  };
+} // end of namespace bpp.
+
+#endif
+
diff --git a/src/Bpp/Phyl/Model/Codon/CodonRateFrequenciesSubstitutionModel.cpp b/src/Bpp/Phyl/Model/Codon/CodonRateFrequenciesSubstitutionModel.cpp
new file mode 100644
index 0000000..907598a
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/CodonRateFrequenciesSubstitutionModel.cpp
@@ -0,0 +1,102 @@
+//
+// File: CodonRateFrequenciesSubstitutionModel.cpp
+// Created by:  Laurent Gueguen
+// Created on: lundi 19 septembre 2011, à 12h 20
+//
+
+/*
+  Copyright or © or Copr. CNRS, (November 16, 2004)
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "CodonRateFrequenciesSubstitutionModel.h"
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+CodonRateFrequenciesSubstitutionModel::CodonRateFrequenciesSubstitutionModel(const CodonAlphabet* palph,
+                                                                             NucleotideSubstitutionModel* pmod,
+                                                                             FrequenciesSet* pfreq) :
+  AbstractParameterAliasable("CodonRateFreq."),
+  AbstractSubstitutionModel(palph, "CodonRateFreq."),
+  AbstractWordSubstitutionModel(palph, "CodonRateFreq."),
+  AbstractCodonSubstitutionModel(palph, pmod, "CodonRateFreq.", true),
+  AbstractCodonFrequenciesSubstitutionModel(pfreq, "CodonRateFreq.")
+{
+  updateMatrices();
+}
+
+CodonRateFrequenciesSubstitutionModel::CodonRateFrequenciesSubstitutionModel(const CodonAlphabet* palph,
+                                                                             NucleotideSubstitutionModel* pmod1,
+                                                                             NucleotideSubstitutionModel* pmod2,
+                                                                             NucleotideSubstitutionModel* pmod3,
+                                                                             FrequenciesSet* pfreq) :
+  AbstractParameterAliasable("CodonRateFreq."),
+  AbstractSubstitutionModel(palph, "CodonRateFreq."),
+  AbstractWordSubstitutionModel(palph, "CodonRateFreq."),
+  AbstractCodonSubstitutionModel(palph, pmod1, pmod2, pmod3, "CodonRateFreq.", true),
+  AbstractCodonFrequenciesSubstitutionModel(pfreq, "CodonRateFreq.")
+{
+  updateMatrices();
+}
+
+std::string CodonRateFrequenciesSubstitutionModel::getName() const
+{
+  return ("CodonRateFreq");
+}
+
+void CodonRateFrequenciesSubstitutionModel::fireParameterChanged(const ParameterList& parameters)
+{
+  AbstractCodonFrequenciesSubstitutionModel::fireParameterChanged(parameters);
+
+  // Beware: must be call at the end
+  AbstractCodonSubstitutionModel::fireParameterChanged(parameters);
+}
+
+double CodonRateFrequenciesSubstitutionModel::getCodonsMulRate(size_t i, size_t j) const
+{
+  return AbstractCodonSubstitutionModel::getCodonsMulRate(i,j)
+    * AbstractCodonFrequenciesSubstitutionModel::getCodonsMulRate(i,j);
+}
+
+void CodonRateFrequenciesSubstitutionModel::setNamespace(const std::string& st)
+{
+  AbstractParameterAliasable::setNamespace(st);
+  AbstractCodonSubstitutionModel::setNamespace(st);
+  AbstractCodonFrequenciesSubstitutionModel::setNamespace(st);
+}
+
+void CodonRateFrequenciesSubstitutionModel::setFreq(map<int,double>& frequencies)
+{
+  AbstractCodonFrequenciesSubstitutionModel::setFreq(frequencies);
+}
diff --git a/src/Bpp/Phyl/Model/Codon/CodonRateFrequenciesSubstitutionModel.h b/src/Bpp/Phyl/Model/Codon/CodonRateFrequenciesSubstitutionModel.h
new file mode 100644
index 0000000..88617c3
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/CodonRateFrequenciesSubstitutionModel.h
@@ -0,0 +1,127 @@
+//
+// File: CodonRateSubstitutionModel.h
+// Created by: Laurent Gueguen
+// Created on: Tue Dec 24 11:03:53 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _CODONRATEFREQUENCIESSUBSTITUTIONMODEL_H_
+#define _CODONRATEFREQUENCIESSUBSTITUTIONMODEL_H_
+
+#include "AbstractCodonSubstitutionModel.h"
+#include "AbstractCodonFrequenciesSubstitutionModel.h"
+
+namespace bpp
+{
+/**
+ * @brief Class for substitution models on non stop codons, with
+ * different parametrized rates on the models, depending on their
+ * phase and defined through a specific equilibrium distribution.
+ *
+ * @author Laurent Guéguen
+ *
+ * This class should be used with models which equilibrium
+ * distribution is fixed, ans does not depend on the parameters.
+ * Otherwise there may be problems of identifiability of the
+ * parameters.
+ *
+ * See description in AbstractCodonRateSubstitutionModel and
+ * AbstractCodonFrequenciesSubstitutionModel class.
+ *
+ */
+
+class CodonRateFrequenciesSubstitutionModel :
+    public AbstractCodonSubstitutionModel,
+    public AbstractCodonFrequenciesSubstitutionModel
+{
+public:
+  /**
+   *@brief Build a new CodonRateSubstitutionModel object from
+   *a pointer to NucleotideSubstitutionModels.
+   * @author Laurent Guéguen
+   *
+   *@param palph pointer to a CodonAlphabet
+   *@param pmod pointer to the NucleotideSubstitutionModel to use in the
+   *       three positions. It is owned by the instabce.
+   *@param pfreq pointer to the FrequenciesSet* equilibrium frequencies
+   */
+
+  CodonRateFrequenciesSubstitutionModel(const CodonAlphabet* palph,
+                                        NucleotideSubstitutionModel* pmod,
+                                        FrequenciesSet* pfreq);
+
+  /**
+   *@brief Build a new CodonRateSubstitutionModel object
+   *from three pointers to NucleotideSubstitutionModels.
+   *
+   *@param palph pointer to a CodonAlphabet
+   *@param pmod1, pmod2, pmod3 pointers to the
+   *   NucleotideSubstitutionModel to use in the three positions.
+   *   All the models must be different objects to avoid parameters
+   *   redondancy, otherwise only the first model is used. The used models
+   *   are owned by the instance.
+   *@param pfreq pointer to the FrequenciesSet* equilibrium frequencies
+   */
+
+  CodonRateFrequenciesSubstitutionModel(const CodonAlphabet* palph,
+                                        NucleotideSubstitutionModel* pmod1,
+                                        NucleotideSubstitutionModel* pmod2,
+                                        NucleotideSubstitutionModel* pmod3,
+                                        FrequenciesSet* pfreq);
+
+  ~CodonRateFrequenciesSubstitutionModel(){}
+
+#ifndef NO_VIRTUAL_COV
+  CodonRateFrequenciesSubstitutionModel*
+#else
+  Clonable*
+#endif
+  clone() const { return new CodonRateFrequenciesSubstitutionModel(*this); }
+
+public:
+  void fireParameterChanged(const ParameterList& parameterlist);
+  
+  std::string getName() const;
+
+  double getCodonsMulRate(size_t i, size_t j) const;
+
+  void setNamespace(const std::string& st);
+
+  void setFreq(std::map<int,double>& frequencies);
+};
+} // end of namespace bpp.
+
+#endif
+
diff --git a/src/Bpp/Phyl/Model/Codon/CodonRateSubstitutionModel.cpp b/src/Bpp/Phyl/Model/Codon/CodonRateSubstitutionModel.cpp
new file mode 100644
index 0000000..fd8b566
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/CodonRateSubstitutionModel.cpp
@@ -0,0 +1,84 @@
+//
+// File: CodonSubstitutionModel.cpp
+// Created by:  Laurent Gueguen
+// Created on: Feb 2009
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "CodonRateSubstitutionModel.h"
+
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+CodonRateSubstitutionModel::CodonRateSubstitutionModel(const CodonAlphabet* palph,
+                                                       NucleotideSubstitutionModel* pmod) :
+  AbstractParameterAliasable("CodonRate."),
+  AbstractSubstitutionModel(palph, "CodonRate."),
+  AbstractWordSubstitutionModel(palph, "CodonRate."),
+  AbstractCodonSubstitutionModel(palph, pmod, "CodonRate.", true)
+{
+  updateMatrices();
+}
+
+CodonRateSubstitutionModel::CodonRateSubstitutionModel(const CodonAlphabet* palph,
+                                                       NucleotideSubstitutionModel* pmod1,
+                                                       NucleotideSubstitutionModel* pmod2,
+                                                       NucleotideSubstitutionModel* pmod3) :
+  AbstractParameterAliasable("CodonRate."),
+  AbstractSubstitutionModel(palph, "CodonRate."),
+  AbstractWordSubstitutionModel(palph, "CodonRate."),
+  AbstractCodonSubstitutionModel(palph, pmod1, pmod2, pmod3, "CodonRate.", true)
+{
+  updateMatrices();
+}
+
+std::string CodonRateSubstitutionModel::getName() const
+{
+  return ("CodonRate");
+}
+
+void CodonRateSubstitutionModel::fireParameterChanged(const ParameterList& parameters)
+{
+  AbstractCodonSubstitutionModel::fireParameterChanged(parameters);
+}
+
+double CodonRateSubstitutionModel::getCodonsMulRate(size_t i, size_t j) const
+{
+  return AbstractCodonSubstitutionModel::getCodonsMulRate(i,j);
+}
+
diff --git a/src/Bpp/Phyl/Model/Codon/CodonRateSubstitutionModel.h b/src/Bpp/Phyl/Model/Codon/CodonRateSubstitutionModel.h
new file mode 100644
index 0000000..6f84d06
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/CodonRateSubstitutionModel.h
@@ -0,0 +1,111 @@
+//
+// File: CodonRateSubstitutionModel.h
+// Created by: Laurent Gueguen
+// Created on: Tue Dec 24 11:03:53 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _CODONRATESUBSTITUTIONMODEL_H_
+#define _CODONRATESUBSTITUTIONMODEL_H_
+
+#include "AbstractCodonSubstitutionModel.h"
+#include "../Nucleotide/NucleotideSubstitutionModel.h"
+
+namespace bpp
+{
+/**
+ * @brief Class for substitution models on non stop codons, with
+ * different rates on the models, depending on their phase.
+ *
+ * @author Laurent Guéguen
+ *
+ * See description in AbstractCodonRateSubstitutionModel class.
+ *
+ */
+
+class CodonRateSubstitutionModel :
+  public AbstractCodonSubstitutionModel
+{
+public:
+  /**
+   *@brief Build a new CodonRateSubstitutionModel object from
+   *a pointer to NucleotideSubstitutionModels.
+   * @author Laurent Guéguen
+   *
+   *@param palph pointer to a CodonAlphabet
+   *@param pmod pointer to the NucleotideSubstitutionModel to use in the
+   *       three positions. It is owned by the instabce.
+   */
+
+  CodonRateSubstitutionModel(const CodonAlphabet* palph,
+                             NucleotideSubstitutionModel* pmod);
+
+  /**
+   *@brief Build a new CodonRateSubstitutionModel object
+   *from three pointers to NucleotideSubstitutionModels.
+   *
+   *@param palph pointer to a CodonAlphabet
+   *@param pmod1, pmod2, pmod3 pointers to the
+   *   NucleotideSubstitutionModel to use in the three positions.
+   *   All the models must be different objects to avoid parameters
+   *   redondancy, otherwise only the first model is used. The used models
+   *   are owned by the instance.
+   */
+
+  CodonRateSubstitutionModel(const CodonAlphabet* palph,
+                             NucleotideSubstitutionModel* pmod1,
+                             NucleotideSubstitutionModel* pmod2,
+                             NucleotideSubstitutionModel* pmod3);
+
+  ~CodonRateSubstitutionModel(){}
+
+#ifndef NO_VIRTUAL_COV
+  CodonRateSubstitutionModel*
+#else
+  Clonable*
+#endif
+  clone() const { return new CodonRateSubstitutionModel(*this); }
+
+public:
+  void fireParameterChanged(const ParameterList& parameterlist);
+  
+  std::string getName() const;
+
+  double getCodonsMulRate(size_t i, size_t j) const;
+};
+} // end of namespace bpp.
+
+#endif
+
diff --git a/src/Bpp/Phyl/Model/Codon/CodonSubstitutionModel.h b/src/Bpp/Phyl/Model/Codon/CodonSubstitutionModel.h
new file mode 100644
index 0000000..de1fbaa
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/CodonSubstitutionModel.h
@@ -0,0 +1,84 @@
+//
+// File: CodonSubstitutionModel.h
+// Created by: Laurent Gueguen
+// Created on: Tue Dec 24 11:03:53 2003
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _CODONSUBSTITUTIONMODEL_H_
+#define _CODONSUBSTITUTIONMODEL_H_
+
+#include <Bpp/Numeric/ParameterAliasable.h>
+
+#include "../WordSubstitutionModel.h"
+
+namespace bpp
+{
+  /**
+   * @brief Abstract class for codon models
+   * @author Laurent Guéguen
+   *
+   * This class aims at defining methods needed for inheriting codon.
+   *
+   */
+  
+  class CodonSubstitutionModel:
+    public virtual SubstitutionModel
+  {
+  public:
+    CodonSubstitutionModel() {}
+    virtual ~CodonSubstitutionModel() {}
+
+#ifndef NO_VIRTUAL_COV
+    virtual CodonSubstitutionModel* clone() const = 0;
+#endif
+
+  public:
+
+    /**
+     * @brief Returns the multiplicative rate specific to two codons
+     * specified by their number. The respective generator rate is this
+     * rate multiplied by the rate defined by the model defined on
+     * nucleotides.
+     *
+     **/
+  
+    virtual double getCodonsMulRate(size_t, size_t) const = 0;
+  };
+  
+} // end of namespace bpp.
+
+#endif
+
diff --git a/src/Bpp/Phyl/Model/Codon/GY94.cpp b/src/Bpp/Phyl/Model/Codon/GY94.cpp
new file mode 100644
index 0000000..22b1dd9
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/GY94.cpp
@@ -0,0 +1,86 @@
+//
+// File: GY94.cpp
+// Created by:  Laurent Gueguen
+// Created on: July 2009
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "GY94.h"
+#include "../Nucleotide/K80.h"
+#include "../FrequenciesSet/CodonFrequenciesSet.h"
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+GY94::GY94(const GeneticCode* gc, FrequenciesSet* codonFreqs) :
+  AbstractBiblioSubstitutionModel("GY94."),
+  gacd_(),
+  pmodel_(new CodonDistanceFrequenciesSubstitutionModel(gc, new K80(dynamic_cast<const CodonAlphabet*>(gc->getSourceAlphabet())->getNucleicAlphabet()), codonFreqs, &gacd_))
+{
+  addParameter_(new Parameter("GY94.kappa",1,&Parameter::R_PLUS_STAR));
+  addParameter_(new Parameter("GY94.V",10000,&Parameter::R_PLUS_STAR));
+  
+  pmodel_->setNamespace("GY94.");
+  addParameters_(codonFreqs->getParameters());
+
+  lParPmodel_.addParameters(pmodel_->getParameters());
+  
+  vector<std::string> v=pmodel_->getFrequenciesSet()->getParameters().getParameterNames();
+  for (unsigned int i=0;i<v.size();i++)
+    mapParNamesFromPmodel_[v[i]]=getParameterNameWithoutNamespace(v[i]);
+
+  mapParNamesFromPmodel_["GY94.123_K80.kappa"]="kappa";
+  mapParNamesFromPmodel_["GY94.alpha"]="V";
+  
+  updateMatrices();
+}
+
+GY94::GY94(const GY94& gy94) :
+  AbstractBiblioSubstitutionModel(gy94),
+  gacd_(),
+  pmodel_(new CodonDistanceFrequenciesSubstitutionModel(*gy94.pmodel_))
+{}
+
+GY94& GY94::operator=(const GY94& gy94)
+{
+  AbstractBiblioSubstitutionModel::operator=(gy94);
+  pmodel_.reset(new CodonDistanceFrequenciesSubstitutionModel(*gy94.pmodel_));
+  return *this;
+}
+
+GY94::~GY94() {}
+
diff --git a/src/Bpp/Phyl/Model/Codon/GY94.h b/src/Bpp/Phyl/Model/Codon/GY94.h
new file mode 100644
index 0000000..78ba1c0
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/GY94.h
@@ -0,0 +1,121 @@
+//
+// File: GY94.h
+// Created by: Laurent Gueguen
+// Created on: July 2009
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _GY94_H_
+#define _GY94_H_
+
+#include "../AbstractBiblioSubstitutionModel.h"
+#include "CodonDistanceFrequenciesSubstitutionModel.h"
+#include <Bpp/Seq/AlphabetIndex/GranthamAAChemicalDistance.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The Goldman and Yang (1994) substitution model for codons.
+ * @author Laurent Guéguen
+ *
+ * This model has one rate of transitions and one rate of
+ * transversion. It also allows distinct equilibrium frequencies
+ * between codons. A multiplicative factor accounts for the selective
+ * restraints at the amino acid level. This factor applies on the
+ * distance @f$d at f$ between amino acids given by Grantham (1974).
+ * 
+ * For codons @f$i=i_1i_2i_3 at f$ and @f$j=j_1j_2j_3 at f$, the generator
+ * term @f$Q_{ij} (i \neq j)@f$ is:
+ *
+ * 0 if 2 or 3 of the pair @f$(i_1,j_1) (i_2,j_2) (i_3,j_3) @f$ are
+ * different.
+ *
+ * @f$\mu \pi_j \exp(-d_{aa_i,aa_j}/V)@f$ if exactly 1 of the pairs
+ * @f$(i_1,j_1) (i_2,j_2) (i_3,j_3) @f$ is different, and that
+ * difference is a transversion.
+ *
+ * @f$\mu \kappa \pi_j \exp(-d_{aa_i,aa_j}/V)@f$ if exactly 1 of the
+ * pairs @f$(i_1,j_1) (i_2,j_2) (i_3,j_3) @f$ is different, and that
+ * difference is a transition.
+ *
+ * @f$\mu at f$ is a normalization factor.
+ *
+ * This model includes 2 parameters (@f$\kappa at f$ and @f$V at f$). The
+ * codon frequencies @f$\pi_j at f$ are either observed or infered.
+ *
+ * Reference:
+ * - Goldman N. and Yang Z. (1994), _Molecular Biology And Evolution_ 11(5) 725--736. 
+ */
+class GY94:
+    public AbstractBiblioSubstitutionModel,
+    virtual public ReversibleSubstitutionModel
+{
+private:
+
+  GranthamAAChemicalDistance gacd_;
+  std::auto_ptr<CodonDistanceFrequenciesSubstitutionModel> pmodel_;
+
+public:
+  GY94(const GeneticCode* gc, FrequenciesSet* codonFreqs);
+       
+  ~GY94();
+
+  GY94(const GY94& gy94);
+  
+  GY94& operator=(const GY94& gy94);
+
+#ifndef NOVIRTUAL_COV_
+  GY94* 
+#else
+  Clonable*
+#endif
+  clone() const { return new GY94(*this); }
+
+public:
+
+  std::string getName() const { return "GY94"; }
+	
+  const SubstitutionModel& getModel() const { return *pmodel_.get(); }
+
+private:
+  SubstitutionModel& getModel() { return *pmodel_.get(); }
+
+};
+
+} //end of namespace bpp.
+
+#endif	//_GY94_H_
+
diff --git a/src/Bpp/Phyl/Model/Codon/MG94.cpp b/src/Bpp/Phyl/Model/Codon/MG94.cpp
new file mode 100644
index 0000000..6228cd2
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/MG94.cpp
@@ -0,0 +1,83 @@
+//
+// File: MG94.cpp
+// Created by:  Laurent Gueguen
+// Created on: July 2009
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "MG94.h"
+#include "../FrequenciesSet/CodonFrequenciesSet.h"
+#include "../Nucleotide/K80.h"
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+MG94::MG94(const GeneticCode* gc, FrequenciesSet* codonFreqs) :
+  AbstractBiblioSubstitutionModel("MG94."),
+  pmodel_(new CodonDistancePhaseFrequenciesSubstitutionModel(gc, new K80(dynamic_cast<const CodonAlphabet*>(gc->getSourceAlphabet())->getNucleicAlphabet()), codonFreqs))
+{
+  addParameter_(new Parameter("MG94.rho", 1, &Parameter::R_PLUS_STAR));
+
+  pmodel_->setNamespace("MG94.");
+  addParameters_(codonFreqs->getParameters());
+
+  lParPmodel_.addParameters(pmodel_->getParameters());
+  
+  vector<std::string> v=pmodel_->getFrequenciesSet()->getParameters().getParameterNames();
+  for (unsigned int i=0;i<v.size();i++)
+    mapParNamesFromPmodel_[v[i]]=getParameterNameWithoutNamespace(v[i]);
+
+  mapParNamesFromPmodel_["MG94.beta"]="rho";
+  
+  updateMatrices();
+}
+
+MG94::MG94(const MG94& mg94) :
+  AbstractBiblioSubstitutionModel(mg94),
+  pmodel_(new CodonDistancePhaseFrequenciesSubstitutionModel(*mg94.pmodel_))
+{}
+
+MG94& MG94::operator=(const MG94& mg94)
+{
+  AbstractBiblioSubstitutionModel::operator=(mg94);
+  pmodel_.reset(new CodonDistancePhaseFrequenciesSubstitutionModel(*mg94.pmodel_));
+  return *this;
+}
+
+MG94::~MG94() {}
+
+
diff --git a/src/Bpp/Phyl/Model/Codon/MG94.h b/src/Bpp/Phyl/Model/Codon/MG94.h
new file mode 100644
index 0000000..82e30bc
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/MG94.h
@@ -0,0 +1,115 @@
+//
+// File: MG94.h
+// Created by: Laurent Gueguen
+// Created on: July 2009
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _MG94_H_
+#define _MG94_H_
+
+#include "../AbstractBiblioSubstitutionModel.h"
+#include "CodonDistancePhaseFrequenciesSubstitutionModel.h"
+
+namespace bpp
+{
+/**
+ * @brief The Muse and Gaut (1994) substitution model for codons.
+ * @author Laurent Guéguen
+ *
+ * This model has one ratio @f$\rho at f$ of synonymous substitution rate
+ * over non-synonymous substitution rate. It allows distinct
+ * equilibrium frequencies between nucleotides.
+ *
+ * For codons @f$i=i_1i_2i_3 at f$ and @f$j=j_1j_2j_3 at f$, the generator term
+ * @f$Q_{ij} (i \neq j)@f$ is:
+ *
+ * 0 if 2 or 3 of the pair @f$(i_1,j_1)(i_2,j_2) (i_3,j_3) @f$ are different.
+ *
+ * @f$\mu \rho \pi_{j_k} @f$  if exactly 1 of the pairs
+ * @f$(i_1,j_1) (i_2,j_2) (i_3,j_3) @f$ is different (@f$k at f$), and that
+ * difference is synonymous.
+ *
+ * @f$\mu \pi_{j_k} @f$  if exactly 1 of the pairs
+ * @f$(i_1,j_1) (i_2,j_2) (i_3,j_3) @f$ is different (@f$k at f$), and that
+ * difference is non-synonymous.
+ *
+ * @f$\mu at f$ is a normalization factor.
+ *
+ * This model includes one parameter (@f$\rho at f$). The codon
+ * frequencies @f$\pi_j at f$ are either observed or infered.
+ *
+ * Reference:
+ * - Muse S.V. and Gaut B.S. (1994), Molecular_ Biology And Evolution_ 11(5) 715--724.
+ */
+
+
+class MG94 :
+    public AbstractBiblioSubstitutionModel,
+    virtual public ReversibleSubstitutionModel
+{
+private:
+  std::auto_ptr<CodonDistancePhaseFrequenciesSubstitutionModel> pmodel_;
+
+public:
+  MG94(const GeneticCode* gc, FrequenciesSet* codonFreqs);
+
+  MG94(const MG94& mg94);
+
+  MG94& operator=(const MG94& mg94);
+
+  ~MG94();
+
+#ifndef NO_VIRTUAL_COV
+  MG94*
+#else
+  Clonable*
+#endif
+  clone() const { return new MG94(*this); }
+
+public:
+  std::string getName() const { return "MG94"; }
+
+  const SubstitutionModel& getModel() const { return *pmodel_.get(); }
+
+private:
+  SubstitutionModel& getModel() { return *pmodel_.get(); }
+
+};
+
+} // end of namespace bpp.
+
+#endif  // _MG94_H_
+
diff --git a/src/Bpp/Phyl/Model/Codon/TripletSubstitutionModel.cpp b/src/Bpp/Phyl/Model/Codon/TripletSubstitutionModel.cpp
new file mode 100644
index 0000000..e9c1a81
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/TripletSubstitutionModel.cpp
@@ -0,0 +1,153 @@
+//
+// File: TripletSubstitutionModel.cpp
+// Created by:  Laurent Gueguen
+// Created on: Feb 2009
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "TripletSubstitutionModel.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Numeric/Matrix/EigenValue.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/WordAlphabet.h>
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <cmath>
+
+using namespace std;
+
+/******************************************************************************/
+
+TripletSubstitutionModel::TripletSubstitutionModel(
+    const CodonAlphabet* palph,
+    NucleotideSubstitutionModel* pmod) :
+  AbstractParameterAliasable("Triplet."),
+  AbstractSubstitutionModel(palph, "Triplet."),
+  WordSubstitutionModel(palph, "Triplet.")
+{
+  unsigned int i;
+  addParameters_(pmod->getParameters());
+
+  Vrate_.resize(3);
+  for (i = 0; i < 3; i++)
+  {
+    VSubMod_.push_back(pmod);
+    VnestedPrefix_.push_back(pmod->getNamespace());
+    Vrate_[i] = 1. / 3.;
+  }
+
+  // relative rates
+  for (i = 0; i < 2; i++)
+  {
+    addParameter_(new Parameter("Triplet.relrate" + TextTools::toString(i+1), 1.0 / (3 - i), &Parameter::PROP_CONSTRAINT_EX));
+  }
+
+  WordSubstitutionModel::updateMatrices();
+}
+
+TripletSubstitutionModel::TripletSubstitutionModel(
+    const CodonAlphabet* palph,
+    NucleotideSubstitutionModel* pmod1,
+    NucleotideSubstitutionModel* pmod2,
+    NucleotideSubstitutionModel* pmod3) :
+  AbstractParameterAliasable("Triplet."),
+  AbstractSubstitutionModel(palph, "Triplet."),
+  WordSubstitutionModel(palph, "Triplet.")
+{
+  string st = "Triplet.";
+
+  if ((pmod1 == pmod2) || (pmod2 == pmod3) || (pmod1 == pmod3))
+  {
+    int i;
+    for (i = 0; i < 3; i++)
+    {
+      VSubMod_.push_back(pmod1);
+      VnestedPrefix_.push_back(pmod1->getNamespace());
+    }
+
+    pmod1->setNamespace(st + "123_" + VnestedPrefix_[0]);
+    addParameters_(pmod1->getParameters());
+  }
+  else
+  {
+    VSubMod_.push_back(pmod1);
+    VnestedPrefix_.push_back(pmod1->getNamespace());
+    VSubMod_[0]->setNamespace(st + "1_" + VnestedPrefix_[0]);
+    addParameters_(pmod1->getParameters());
+
+    VSubMod_.push_back(pmod2);
+    VnestedPrefix_.push_back(pmod2->getNamespace());
+    VSubMod_[1]->setNamespace(st + "2_" + VnestedPrefix_[1]);
+    addParameters_(pmod2->getParameters());
+
+    VSubMod_.push_back(pmod3);
+    VnestedPrefix_.push_back(pmod3->getNamespace());
+    VSubMod_[2]->setNamespace(st + "3_" + VnestedPrefix_[2]);
+    addParameters_(pmod3->getParameters());
+  }
+
+  unsigned int i;
+  Vrate_.resize(3);
+  for (i = 0; i < 3; i++)
+  {
+    Vrate_[i] = 1.0 / 3;
+  }
+
+  // relative rates
+  for (i = 0; i < 2; i++)
+  {
+    addParameter_(new Parameter(st + "relrate" + TextTools::toString(i+1), 1.0 / (3 - i),&Parameter::PROP_CONSTRAINT_EX));
+  }
+
+  WordSubstitutionModel::updateMatrices();
+}
+
+string TripletSubstitutionModel::getName() const
+{
+  string s = "TripletSubstitutionModel model:";
+  for (unsigned int i = 0; i < VSubMod_.size(); i++)
+  {
+    s += " " + VSubMod_[i]->getName();
+  }
+
+  return s;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Codon/TripletSubstitutionModel.h b/src/Bpp/Phyl/Model/Codon/TripletSubstitutionModel.h
new file mode 100644
index 0000000..1f0159c
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/TripletSubstitutionModel.h
@@ -0,0 +1,113 @@
+//
+// File: TripletSubstitutionModel.h
+// Created by: Laurent Gueguen
+// Created on: Tue Dec 24 11:03:53 2003
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _TRIPLETSUBSTITUTIONMODEL_H_
+#define _TRIPLETSUBSTITUTIONMODEL_H_
+
+#include "../WordSubstitutionModel.h"
+#include "../Nucleotide/NucleotideSubstitutionModel.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/CodonAlphabet.h>
+
+namespace bpp
+{
+
+/**
+ * @brief Class for neutral substitution models on triplets,
+ * which correspond to codons that do not have any significance
+ * (whether they are STOP or functional).
+ * @author Laurent Guéguen
+ *
+ * Objects of this class are built from three substitution
+ * models of NucleicAlphabets. No model is directly accessible. </p>
+ *
+ */
+  
+class TripletSubstitutionModel :
+  public WordSubstitutionModel
+{
+public:
+
+  /**
+   *@brief Build a new TripletSubstitutionModel object from
+   *a pointer to a NucleotideSubstitutionModel. 
+   *
+   *@param palph pointer to a CodonAlphabet
+   *@param pmod  pointer to the NucleotideSubstitutionModel to be used
+   *       in the three positions. It is owned by the instance.
+   */
+  
+  TripletSubstitutionModel(const CodonAlphabet* palph,
+                                     NucleotideSubstitutionModel* pmod);
+  
+  /**
+   *@brief Build a new TripletSubstitutionModel object
+   *from three pointers to NucleotideSubstitutionModels. 
+   *
+   *@param palph pointer to a CodonAlphabet
+   *@param pmod1, pmod2, pmod3 pointers to the
+   *   NucleotideSubstitutionModels to use in the three positions. All
+   *   the models must be different objects to avoid parameters
+   *   redundancy, otherwise only the first model is used. The used
+   *   models are owned by the instance.
+   */
+
+  TripletSubstitutionModel(const CodonAlphabet* palph,
+                                     NucleotideSubstitutionModel* pmod1,
+                                     NucleotideSubstitutionModel* pmod2, 
+                                     NucleotideSubstitutionModel* pmod3);
+
+  ~TripletSubstitutionModel() {};
+  
+#ifndef NO_VIRTUAL_COV
+  TripletSubstitutionModel*
+#else
+  Clonable*
+#endif
+  clone() const { return new TripletSubstitutionModel(*this);}
+  
+public:
+  std::string getName() const;
+};
+
+} //end of namespace bpp.
+
+#endif	
+
diff --git a/src/Bpp/Phyl/Model/Codon/YN98.cpp b/src/Bpp/Phyl/Model/Codon/YN98.cpp
new file mode 100644
index 0000000..15aca0a
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/YN98.cpp
@@ -0,0 +1,86 @@
+//
+// File: YN98.cpp
+// Created by:  Laurent Gueguen
+// Created on: July 2009
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "YN98.h"
+#include "../Nucleotide/K80.h"
+#include "../FrequenciesSet/CodonFrequenciesSet.h"
+#include <Bpp/Numeric/NumConstants.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+YN98::YN98(const GeneticCode* gc, FrequenciesSet* codonFreqs) :
+  AbstractBiblioSubstitutionModel("YN98."),
+  pmodel_(new CodonDistanceFrequenciesSubstitutionModel(gc, new K80(dynamic_cast<const CodonAlphabet*>(gc->getSourceAlphabet())->getNucleicAlphabet()), codonFreqs))
+{
+  addParameter_(new Parameter("YN98.kappa", 1, &Parameter::R_PLUS_STAR));
+  addParameter_(new Parameter("YN98.omega", 1, new IntervalConstraint(NumConstants::MILLI(), 999, true, true), true));
+
+  pmodel_->setNamespace("YN98.");
+  addParameters_(codonFreqs->getParameters());
+
+  lParPmodel_.addParameters(pmodel_->getParameters());
+
+  vector<std::string> v = pmodel_->getFrequenciesSet()->getParameters().getParameterNames();
+
+  for (size_t i = 0; i < v.size(); i++)
+  {
+    mapParNamesFromPmodel_[v[i]] = getParameterNameWithoutNamespace(v[i]);
+  }
+  mapParNamesFromPmodel_["YN98.123_K80.kappa"] = "kappa";
+  mapParNamesFromPmodel_["YN98.beta"] = "omega";
+
+  updateMatrices();
+}
+
+
+YN98::YN98(const YN98& yn98) : AbstractBiblioSubstitutionModel(yn98),
+  pmodel_(new CodonDistanceFrequenciesSubstitutionModel(*yn98.pmodel_))
+{}
+
+YN98& YN98::operator=(const YN98& yn98)
+{
+  AbstractBiblioSubstitutionModel::operator=(yn98);
+  pmodel_.reset(new CodonDistanceFrequenciesSubstitutionModel(*yn98.pmodel_));
+  return *this;
+}
+
+YN98::~YN98() {}
diff --git a/src/Bpp/Phyl/Model/Codon/YN98.h b/src/Bpp/Phyl/Model/Codon/YN98.h
new file mode 100644
index 0000000..c01dd80
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/YN98.h
@@ -0,0 +1,119 @@
+//
+// File: YN98.h
+// Created by: Laurent Gueguen
+// Created on: July 2009
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _YN98_H_
+#define _YN98_H_
+
+#include "../AbstractBiblioSubstitutionModel.h"
+#include "CodonDistanceFrequenciesSubstitutionModel.h"
+
+namespace bpp
+{
+/**
+ * @brief The Yang and Nielsen (1998) substitution model for codons.
+ * @author Laurent Guéguen
+ *
+ * This model has one rate of transitions and one rate of
+ * transversion. It also allows distinct equilibrium frequencies
+ * between codons. A multiplicative factor accounts for the selective
+ * restraints at the amino acid level, depending on the synonymy of
+ * the amino acids.
+ *
+ * For codons @f$i=i_1i_2i_3 at f$ and @f$j=j_1j_2j_3 at f$, the generator
+ * term @f$Q_{ij} (i \neq j)@f$ is:
+ *
+ * 0 if 2 or 3 of the pair @f$(i_1,j_1) (i_2,j_2) (i_3,j_3) @f$ are different.
+ *
+ * @f$\mu \pi_j \omega at f$ if exactly 1 of the pairs @f$(i_1,j_1)
+ * (i_2,j_2) (i_3,j_3) @f$ is different, that difference is a
+ * transversion and amino acids coded by i and j are different.
+ *
+ * @f$\mu \pi_j @f$ if exactly 1 of the pairs @f$(i_1,j_1) (i_2,j_2)
+ * (i_3,j_3) @f$ is different, that difference is a transversion and
+ * amino acids coded by i and j are the same.
+ *
+ * @f$\mu \kappa \pi_j \omega at f$ if exactly 1 of the pairs
+ * @f$(i_1,j_1) (i_2,j_2) (i_3,j_3) @f$ is different, that difference
+ * is a transition and amino acids coded by i and j are different.
+ *
+ * @f$\mu \kappa \pi_j @f$ if exactly 1 of the pairs @f$(i_1,j_1)
+ * (i_2,j_2) (i_3,j_3) @f$ is different, that difference is a
+ * transition and amino acids coded by @f$i at f$ and @f$j at f$ are the
+ * same.
+ *
+ * @f$\mu at f$ is a normalization factor.
+ *
+ * This model includes 2 parameters (@f$\kappa at f$ and @f$\omega at f$).
+ * The codon frequencies @f$\pi_j at f$ are either observed or infered.
+ *
+ * Reference:
+ * -  Yang Z. and Nielsen R. (1998), _Journal of Molecular Evolution_ 46:409--418.
+ */
+class YN98 :
+    public AbstractBiblioSubstitutionModel,
+    public virtual ReversibleSubstitutionModel
+{
+private:
+  std::auto_ptr<CodonDistanceFrequenciesSubstitutionModel> pmodel_;
+
+public:
+  YN98(const GeneticCode* gc, FrequenciesSet* codonFreqs);
+
+  YN98(const YN98& yn98);
+
+  YN98& operator=(const YN98&);
+
+  ~YN98();
+
+  YN98* clone() const { return new YN98(*this); }
+
+public:
+  std::string getName() const { return "YN98"; }
+
+  const SubstitutionModel& getModel() const { return *pmodel_.get(); }
+
+private:
+  SubstitutionModel& getModel() { return *pmodel_.get(); }
+
+};
+
+} // end of namespace bpp.
+
+#endif  // _YN98_H_
+
diff --git a/src/Bpp/Phyl/Model/Codon/YNGKP_M1.cpp b/src/Bpp/Phyl/Model/Codon/YNGKP_M1.cpp
new file mode 100644
index 0000000..fdcb4e4
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/YNGKP_M1.cpp
@@ -0,0 +1,155 @@
+//
+// File: YNGKP_M1.cpp
+// Created by:  Laurent Gueguen
+// Created on: May 2010
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "YNGKP_M1.h"
+#include "YN98.h"
+
+#include <Bpp/Numeric/NumConstants.h>
+#include <Bpp/Numeric/Prob/SimpleDiscreteDistribution.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+YNGKP_M1::YNGKP_M1(const GeneticCode* gc, FrequenciesSet* codonFreqs) :
+  AbstractBiblioMixedSubstitutionModel("YNGKP_M1."),
+  pmixmodel_(0),
+  synfrom_(-1),
+  synto_(-1)
+{
+  // build the submodel
+
+  vector<double> v1, v2;
+  v1.push_back(0.5); v1.push_back(1);
+  v2.push_back(0.5); v2.push_back(0.5);
+
+  SimpleDiscreteDistribution* psdd = new SimpleDiscreteDistribution(v1, v2);
+
+  map<string, DiscreteDistribution*> mpdd;
+  mpdd["omega"] = psdd;
+
+  pmixmodel_.reset(new MixtureOfASubstitutionModel(gc->getSourceAlphabet(), new YN98(gc, codonFreqs), mpdd));
+  delete psdd;
+
+  // map the parameters
+
+  lParPmodel_.addParameters(pmixmodel_->getParameters());
+
+  vector<std::string> v = dynamic_cast<YN98*>(pmixmodel_->getNModel(0))->getFrequenciesSet()->getParameters().getParameterNames();
+
+  for (size_t i = 0; i < v.size(); i++)
+  {
+    mapParNamesFromPmodel_[v[i]] = v[i].substr(5);
+  }
+
+  mapParNamesFromPmodel_["YN98.kappa"] = "kappa";
+  mapParNamesFromPmodel_["YN98.omega_Simple.V1"] = "omega";
+  mapParNamesFromPmodel_["YN98.omega_Simple.theta1"] = "p0";
+
+  // specific parameters
+
+  string st;
+  for (map<string, string>::iterator it = mapParNamesFromPmodel_.begin(); it != mapParNamesFromPmodel_.end(); it++)
+  {
+    st = pmixmodel_->getParameterNameWithoutNamespace(it->first);
+    if (st != "omega_Simple.V1")
+    {
+      addParameter_(new Parameter("YNGKP_M1." + it->second, pmixmodel_->getParameterValue(st),
+                              pmixmodel_->getParameter(st).hasConstraint() ? pmixmodel_->getParameter(st).getConstraint()->clone() : 0, true));
+    }
+  }
+
+  addParameter_(new Parameter("YNGKP_M1.omega", 0.5, new IntervalConstraint(NumConstants::MILLI(), 1, true, false, NumConstants::MILLI()), true));
+
+  // look for synonymous codons
+  for (synfrom_ = 1; synfrom_ < static_cast<int>(gc->getSourceAlphabet()->getSize()); synfrom_++)
+  {
+    for (synto_ = 0; synto_ < synfrom_; synto_++)
+    {
+      if ((gc->areSynonymous(synfrom_, synto_))
+          && (pmixmodel_->getNModel(0)->Qij(synfrom_, synto_) != 0)
+          && (pmixmodel_->getNModel(1)->Qij(synfrom_, synto_) != 0))
+        break;
+    }
+    if (synto_ < synfrom_)
+      break;
+  }
+
+  if (synto_ == static_cast<int>(gc->getSourceAlphabet()->getSize()))
+    throw Exception("Impossible to find synonymous codons");
+
+  // update matrice
+
+  updateMatrices();
+}
+
+YNGKP_M1::YNGKP_M1(const YNGKP_M1& mod2) : AbstractBiblioMixedSubstitutionModel(mod2),
+  pmixmodel_(new MixtureOfASubstitutionModel(*mod2.pmixmodel_)),
+  synfrom_(mod2.synfrom_),
+  synto_(mod2.synto_)
+{}
+
+YNGKP_M1& YNGKP_M1::operator=(const YNGKP_M1& mod2)
+{
+  AbstractBiblioSubstitutionModel::operator=(mod2);
+
+  pmixmodel_.reset(new MixtureOfASubstitutionModel(*mod2.pmixmodel_));
+  synfrom_ = mod2.synfrom_;
+  synto_ = mod2.synto_;
+
+  return *this;
+}
+
+YNGKP_M1::~YNGKP_M1() {}
+
+void YNGKP_M1::updateMatrices()
+{
+  AbstractBiblioSubstitutionModel::updateMatrices();
+
+  // homogeneization of the synonymous substitution rates
+
+  Vdouble vd;
+
+  vd.push_back(1. / pmixmodel_->getNModel(0)->Qij(synfrom_, synto_));
+  vd.push_back(1. / pmixmodel_->getNModel(1)->Qij(synfrom_, synto_));
+
+  pmixmodel_->setVRates(vd);
+}
+
diff --git a/src/Bpp/Phyl/Model/Codon/YNGKP_M1.h b/src/Bpp/Phyl/Model/Codon/YNGKP_M1.h
new file mode 100644
index 0000000..707edfd
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/YNGKP_M1.h
@@ -0,0 +1,125 @@
+//
+// File: YNGKP_M1.h
+// Created by: Laurent Gueguen
+// Created on: May 2010
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _YNGKP_M1_H_
+#define _YNGKP_M1_H_
+
+#include "../AbstractBiblioMixedSubstitutionModel.h"
+#include "../MixtureOfASubstitutionModel.h"
+#include "../FrequenciesSet/CodonFrequenciesSet.h"
+
+#include <Bpp/Seq/GeneticCode/GeneticCode.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The Yang et al (2000) M1 substitution model for codons, with
+ * the more realistic modification in Wong & al (2004).
+ * @author Laurent Guéguen
+ *
+ * This model is a mixture of models as described in YN98 class, the
+ * mixture being defined on the selection parameter to allow it to
+ * vary among sites. A site is either negatively selected @f$ 0 <
+ * \omega_0 < 1 @f$ (with probability @f$p_0 @f$), or neutral (@f$
+ * \omega_1 = 1 @f$) with probability @f$1-p_0 @f$.
+ *
+ * The synonymous rates must be the same between both models, so the
+ * overall rates of the models are modified to respect this constraint
+ * and such that the mean rate of the mixed model equals one.
+ *
+ * This model includes 3 parameters (@f$\kappa at f$, @f$ p0 @f$ and
+ * @f$\omega at f$). The codon frequencies @f$\pi_j at f$ are either
+ * observed or infered.
+ *
+ * References:
+ *
+ * Yang, Z., R. Nielsen, N. Goldman, and A.-M. K. Pedersen (2000)
+ * Genetics 155:431-449.
+ * 
+ * Wong, W. S. W., Z. Yang, N. Goldman, and R. Nielsen. (2004)
+ * Genetics 168:1041--1051.
+ */
+class YNGKP_M1:
+    public AbstractBiblioMixedSubstitutionModel,
+    virtual public ReversibleSubstitutionModel
+{
+private:
+  std::auto_ptr<MixtureOfASubstitutionModel> pmixmodel_;
+
+
+  /*
+   *@brief indexes of 2 codons between which the substitution is
+   * synonymous, to set a basis to the homogeneization of the rates.
+   *
+   */
+
+  int synfrom_, synto_;
+  
+public:
+  YNGKP_M1(const GeneticCode* gc, FrequenciesSet* codonFreqs);
+
+  virtual ~YNGKP_M1();
+  
+  YNGKP_M1* clone() const { return new YNGKP_M1(*this); }
+
+  YNGKP_M1(const YNGKP_M1&);
+
+  YNGKP_M1& operator=(const YNGKP_M1&);
+
+protected:
+  void updateMatrices();
+
+public:
+  const SubstitutionModel& getModel() const { return *pmixmodel_.get(); }
+
+  const MixedSubstitutionModel& getMixedModel() const { return *pmixmodel_.get(); }
+
+  std::string getName() const { return "YNGKP_M1"; }
+
+private:
+  SubstitutionModel& getModel() { return *pmixmodel_.get(); }
+  
+  MixedSubstitutionModel& getMixedModel() { return *pmixmodel_.get(); }
+};
+
+} //end of namespace bpp.
+
+#endif	//_YNGKP_M1_H_
+
diff --git a/src/Bpp/Phyl/Model/Codon/YNGKP_M2.cpp b/src/Bpp/Phyl/Model/Codon/YNGKP_M2.cpp
new file mode 100644
index 0000000..319f146
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/YNGKP_M2.cpp
@@ -0,0 +1,162 @@
+//
+// File: YNGKP_M2.cpp
+// Created by:  Laurent Gueguen
+// Created on: May 2010
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "YNGKP_M2.h"
+#include "YN98.h"
+
+#include <Bpp/Numeric/NumConstants.h>
+#include <Bpp/Numeric/Prob/SimpleDiscreteDistribution.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+YNGKP_M2::YNGKP_M2(const GeneticCode* gc, FrequenciesSet* codonFreqs) :
+  AbstractBiblioMixedSubstitutionModel("YNGKP_M2."),
+  pmixmodel_(0),
+  synfrom_(-1),
+  synto_(-1)
+{
+  // build the submodel
+
+  vector<double> v1, v2;
+  v1.push_back(0.5); v1.push_back(1); v1.push_back(2);
+  v2.push_back(0.333333); v2.push_back(0.333333); v2.push_back(0.333334);
+
+  SimpleDiscreteDistribution* psdd = new SimpleDiscreteDistribution(v1, v2);
+
+  map<string, DiscreteDistribution*> mpdd;
+  mpdd["omega"] = psdd;
+
+  pmixmodel_.reset(new MixtureOfASubstitutionModel(gc->getSourceAlphabet(), new YN98(gc, codonFreqs), mpdd));
+  delete psdd;
+
+  // mapping the parameters
+
+  ParameterList pl = pmixmodel_->getParameters();
+  for (unsigned int i = 0; i < pl.size(); i++)
+  {
+    lParPmodel_.addParameter(Parameter(pl[i]));
+  }
+
+  vector<std::string> v = dynamic_cast<YN98*>(pmixmodel_->getNModel(0))->getFrequenciesSet()->getParameters().getParameterNames();
+
+  for (size_t i = 0; i < v.size(); i++)
+  {
+    mapParNamesFromPmodel_[v[i]] = getParameterNameWithoutNamespace("YNGKP_M2." + v[i].substr(5));
+  }
+
+  mapParNamesFromPmodel_["YN98.kappa"] = "kappa";
+  mapParNamesFromPmodel_["YN98.omega_Simple.V1"] = "omega0";
+  mapParNamesFromPmodel_["YN98.omega_Simple.theta1"] = "theta1";
+  mapParNamesFromPmodel_["YN98.omega_Simple.V3"] = "omega2";
+  mapParNamesFromPmodel_["YN98.omega_Simple.theta2"] = "theta2";
+
+  // specific parameters
+
+  string st;
+  for (map<string, string>::iterator it = mapParNamesFromPmodel_.begin(); it != mapParNamesFromPmodel_.end(); it++)
+  {
+    st = pmixmodel_->getParameterNameWithoutNamespace(it->first);
+    if (it->second.substr(0, 5) != "omega")
+      addParameter_(new Parameter("YNGKP_M2." + it->second, pmixmodel_->getParameterValue(st),
+                              pmixmodel_->getParameter(st).hasConstraint() ? pmixmodel_->getParameter(st).getConstraint()->clone() : 0, true));
+  }
+
+  addParameter_(new Parameter("YNGKP_M2.omega0", 0.5, new IntervalConstraint(NumConstants::MILLI(), 1, true, false), true));
+
+  addParameter_(new Parameter("YNGKP_M2.omega2", 2, new IntervalConstraint(1, 999, false, false, NumConstants::MILLI()), true));
+
+  // look for synonymous codons
+  for (synfrom_ = 1; synfrom_ < (int)gc->getSourceAlphabet()->getSize(); synfrom_++)
+  {
+    for (synto_ = 0; synto_ < synfrom_; synto_++)
+    {
+      if ((gc->areSynonymous(synfrom_, synto_))
+          && (pmixmodel_->getNModel(0)->Qij(synfrom_, synto_) != 0)
+          && (pmixmodel_->getNModel(1)->Qij(synfrom_, synto_) != 0))
+        break;
+    }
+    if (synto_ < synfrom_)
+      break;
+  }
+
+  if (synto_ == (int)gc->getSourceAlphabet()->getSize())
+    throw Exception("Impossible to find synonymous codons");
+
+  // update Matrices
+
+  updateMatrices();
+}
+
+YNGKP_M2::YNGKP_M2(const YNGKP_M2& mod2) : AbstractBiblioMixedSubstitutionModel(mod2),
+  pmixmodel_(new MixtureOfASubstitutionModel(*mod2.pmixmodel_)),
+  synfrom_(mod2.synfrom_),
+  synto_(mod2.synto_)
+{}
+
+YNGKP_M2& YNGKP_M2::operator=(const YNGKP_M2& mod2)
+{
+  AbstractBiblioMixedSubstitutionModel::operator=(mod2);
+
+  pmixmodel_.reset(new MixtureOfASubstitutionModel(*mod2.pmixmodel_));
+  synfrom_ = mod2.synfrom_;
+  synto_ = mod2.synto_;
+
+  return *this;
+}
+
+YNGKP_M2::~YNGKP_M2() {}
+
+void YNGKP_M2::updateMatrices()
+{
+  AbstractBiblioSubstitutionModel::updateMatrices();
+
+  // homogeneization of the synonymous substittion rates
+
+  Vdouble vd;
+
+  vd.push_back(1 / pmixmodel_->getNModel(0)->Qij(synfrom_, synto_));
+  vd.push_back(1 / pmixmodel_->getNModel(1)->Qij(synfrom_, synto_));
+  vd.push_back(1 / pmixmodel_->getNModel(2)->Qij(synfrom_, synto_));
+
+  pmixmodel_->setVRates(vd);
+}
+
diff --git a/src/Bpp/Phyl/Model/Codon/YNGKP_M2.h b/src/Bpp/Phyl/Model/Codon/YNGKP_M2.h
new file mode 100644
index 0000000..0f945ed
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/YNGKP_M2.h
@@ -0,0 +1,121 @@
+//
+// File: YNGKP_M2.h
+// Created by: Laurent Gueguen
+// Created on: May 2010
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _YNGKP_M2_H_
+#define _YNGKP_M2_H_
+
+#include "../AbstractBiblioMixedSubstitutionModel.h"
+#include "../MixtureOfASubstitutionModel.h"
+#include "../FrequenciesSet/CodonFrequenciesSet.h"
+
+#include <Bpp/Seq/GeneticCode/GeneticCode.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The Yang et al (2000) M2 substitution model for codons, with
+ * the more realistic modification in Wong & al (2004).
+ * @author Laurent Guéguen
+ *
+ * This model is a mixture of models as described in YN98 class, the
+ * mixture being defined on the selection parameter to allow it to
+ * vary among sites. A site is either negatively selected @f$ 0 <
+ * \omega_0 < 1 @f$ (with probability @f$p_0 @f$), or neutral (@f$
+ * \omega_1 = 1 @f$) with probability @f$p_1 @f$, or positively
+ * selected @f$ 1 < \omega_2 @f$ (with probability @f$p_2 @f$). This
+ * model includes 5 parameters (@f$kappa at f$, @f$ theta1=p0,
+ * theta2=\frac{p1}{p1+p2}, omega0 @f$ and @f$ omega2 @f$). The codon
+ * frequencies @f$\pi_j at f$ are either observed or infered.
+ *
+ * References:
+ *
+ * Yang, Z., R. Nielsen, N. Goldman, and A.-M. K. Pedersen (2000)
+ * Genetics 155:431-449.
+ * 
+ * Wong, W. S. W., Z. Yang, N. Goldman, and R. Nielsen. (2004)
+ * Genetics 168:1041--1051.
+ */
+class YNGKP_M2:
+    public AbstractBiblioMixedSubstitutionModel,
+    virtual public ReversibleSubstitutionModel
+{
+private:
+  std::auto_ptr<MixtureOfASubstitutionModel> pmixmodel_;
+
+  /*
+   *@brief indexes of 2 codons between which the substitution is
+   * synonymous, to set a basis to the homogeneization of the rates.
+   *
+   */
+
+  int synfrom_, synto_;
+  
+public:
+  YNGKP_M2(const GeneticCode* gc, FrequenciesSet* codonFreqs);
+
+  ~YNGKP_M2();
+  
+  YNGKP_M2* clone() const { return new YNGKP_M2(*this); }
+
+  YNGKP_M2(const YNGKP_M2&);
+
+  YNGKP_M2& operator=(const YNGKP_M2&);
+
+protected:
+  void updateMatrices();
+
+public:
+  const SubstitutionModel& getModel() const { return *pmixmodel_.get(); }
+
+  const MixedSubstitutionModel& getMixedModel() const { return *pmixmodel_.get(); }
+
+  std::string getName() const { return "YNGKP_M2"; }
+
+private:
+  SubstitutionModel& getModel() { return *pmixmodel_.get(); }
+
+  MixedSubstitutionModel& getMixedModel() { return *pmixmodel_.get(); }
+
+};
+
+} //end of namespace bpp.
+
+#endif	//_YNGKP_M2_H_
+
diff --git a/src/Bpp/Phyl/Model/Codon/YNGKP_M3.cpp b/src/Bpp/Phyl/Model/Codon/YNGKP_M3.cpp
new file mode 100644
index 0000000..3b53fb3
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/YNGKP_M3.cpp
@@ -0,0 +1,204 @@
+//
+// File: YNGKP_M3.cpp
+// Created by:  Laurent Gueguen
+// Created on: May 2010
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "YNGKP_M3.h"
+#include "YN98.h"
+
+#include <Bpp/Numeric/NumConstants.h>
+#include <Bpp/Numeric/Prob/SimpleDiscreteDistribution.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+YNGKP_M3::YNGKP_M3(const GeneticCode* gc, FrequenciesSet* codonFreqs, unsigned int nbOmega) :
+  AbstractBiblioMixedSubstitutionModel("YNGKP_M3."),
+  pmixmodel_(0),
+  synfrom_(-1),
+  synto_(-1)
+{
+  if (nbOmega < 1)
+    throw Exception("At least one omega is necessary in the YNGKP_M3 model");
+
+  // build the submodel
+
+  vector<double> v1, v2;
+  v1.push_back(0.5);
+  for (unsigned int i = 1; i < nbOmega; i++)
+  {
+    v1.push_back(0.5 + 0.5 * i);
+  }
+
+  for (unsigned int i = 0; i < nbOmega; i++)
+  {
+    v2.push_back(1. / nbOmega);
+  }
+
+  SimpleDiscreteDistribution* psdd = new SimpleDiscreteDistribution(v1, v2, NumConstants::MILLI());
+
+  map<string, DiscreteDistribution*> mpdd;
+  mpdd["omega"] = psdd;
+
+  pmixmodel_.reset(new MixtureOfASubstitutionModel(gc->getSourceAlphabet(), new YN98(gc, codonFreqs), mpdd));
+  delete psdd;
+
+  // mapping the parameters
+
+  ParameterList pl = pmixmodel_->getParameters();
+  for (size_t i = 0; i < pl.size(); i++)
+  {
+    lParPmodel_.addParameter(Parameter(pl[i]));
+  }
+
+  vector<std::string> v = dynamic_cast<YN98*>(pmixmodel_->getNModel(0))->getFrequenciesSet()->getParameters().getParameterNames();
+  for (size_t i = 0; i < v.size(); i++)
+  {
+    mapParNamesFromPmodel_[v[i]] = getParameterNameWithoutNamespace("YNGKP_M3." + v[i].substr(5));
+  }
+
+  mapParNamesFromPmodel_["YN98.kappa"] = "kappa";
+
+  for (unsigned int i = 1; i < nbOmega; i++)
+  {
+    mapParNamesFromPmodel_["YN98.omega_Simple.theta" + TextTools::toString(i)] = "theta" + TextTools::toString(i);
+  }
+
+
+  mapParNamesFromPmodel_["YN98.omega_Simple.V1"] = "omega0";
+  for (unsigned int i = 1; i < nbOmega; i++)
+  {
+    mapParNamesFromPmodel_["YN98.omega_Simple.V" + TextTools::toString(i + 1)] = "delta" + TextTools::toString(i);
+  }
+
+  // specific parameters
+
+  string st;
+  for (map<string, string>::iterator it = mapParNamesFromPmodel_.begin(); it != mapParNamesFromPmodel_.end(); it++)
+  {
+    st = pmixmodel_->getParameterNameWithoutNamespace(it->first);
+    if (it->second.substr(0, 5) != "delta")
+      addParameter_(new Parameter("YNGKP_M3." + it->second, pmixmodel_->getParameterValue(st),
+                              pmixmodel_->getParameter(st).hasConstraint() ? pmixmodel_->getParameter(st).getConstraint()->clone() : 0, true));
+  }
+
+  for (unsigned int i = 1; i < nbOmega; i++)
+  {
+    addParameter_(new Parameter("YNGKP_M3.delta" + TextTools::toString(i), 0.5, new IntervalConstraint(NumConstants::MILLI(), 999, true, true, NumConstants::MILLI()), true));
+  }
+
+  // look for synonymous codons
+  for (synfrom_ = 1; synfrom_ < (int)gc->getSourceAlphabet()->getSize(); synfrom_++)
+  {
+    for (synto_ = 0; synto_ < synfrom_; synto_++)
+    {
+      if ((gc->areSynonymous(synfrom_, synto_))
+          && (pmixmodel_->getNModel(0)->Qij(synfrom_, synto_) != 0)
+          && (pmixmodel_->getNModel(1)->Qij(synfrom_, synto_) != 0))
+        break;
+    }
+    if (synto_ < synfrom_)
+      break;
+  }
+
+  if (synto_ == (int)gc->getSourceAlphabet()->getSize())
+    throw Exception("Impossible to find synonymous codons");
+
+  // update Matrices
+  updateMatrices();
+}
+
+YNGKP_M3::YNGKP_M3(const YNGKP_M3& mod2) : AbstractBiblioMixedSubstitutionModel(mod2),
+  pmixmodel_(new MixtureOfASubstitutionModel(*mod2.pmixmodel_)),
+  synfrom_(mod2.synfrom_),
+  synto_(mod2.synto_)
+{}
+
+YNGKP_M3& YNGKP_M3::operator=(const YNGKP_M3& mod2)
+{
+  AbstractBiblioMixedSubstitutionModel::operator=(mod2);
+
+  pmixmodel_.reset(new MixtureOfASubstitutionModel(*mod2.pmixmodel_));
+  synfrom_ = mod2.synfrom_;
+  synto_ = mod2.synto_;
+
+  return *this;
+}
+
+YNGKP_M3::~YNGKP_M3() {}
+
+void YNGKP_M3::updateMatrices()
+{
+  for (unsigned int i = 0; i < lParPmodel_.size(); i++)
+  {
+    if (mapParNamesFromPmodel_.find(lParPmodel_[i].getName()) != mapParNamesFromPmodel_.end())
+    {
+      if (lParPmodel_[i].getName()[18] == 'V')
+      {
+        unsigned int ind = TextTools::toInt(lParPmodel_[i].getName().substr(19));
+        double x = getParameterValue("omega0");
+        for (unsigned j = 1; j < ind; j++)
+        {
+          x += getParameterValue("delta" + TextTools::toString(j));
+        }
+        lParPmodel_[i].setValue(x);
+      }
+      else
+      {
+        lParPmodel_[i].setValue(getParameter(getParameterNameWithoutNamespace(mapParNamesFromPmodel_[lParPmodel_[i].getName()])).getValue());
+      }
+    }
+  }
+
+  pmixmodel_->matchParametersValues(lParPmodel_);
+
+  // homogeneization of the synonymous substitution rates
+
+
+  Vdouble vd;
+
+  for (unsigned int i = 0; i < pmixmodel_->getNumberOfModels(); i++)
+  {
+    vd.push_back(1 / pmixmodel_->getNModel(i)->Qij(synfrom_, synto_));
+  }
+
+  pmixmodel_->setVRates(vd);
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Codon/YNGKP_M3.h b/src/Bpp/Phyl/Model/Codon/YNGKP_M3.h
new file mode 100644
index 0000000..94f82cf
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/YNGKP_M3.h
@@ -0,0 +1,120 @@
+//
+// File: YNGKP_M3.h
+// Created by: Laurent Gueguen
+// Created on: May 2010
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _YNGKP_M3_H_
+#define _YNGKP_M3_H_
+
+#include "../AbstractBiblioMixedSubstitutionModel.h"
+#include "../MixtureOfASubstitutionModel.h"
+#include "../FrequenciesSet/CodonFrequenciesSet.h"
+
+#include <Bpp/Seq/GeneticCode/GeneticCode.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The Yang et al (2000) M3 substitution model for codons.
+ * @author Laurent Guéguen
+ *
+ * This model is a mixture of models as described in YN98 class, the
+ * mixture being defined on the selection parameter to allow it to
+ * vary among sites. There are $K$ selection parameters @f$ \omega_0 <
+ * ... \omega_{K-1} @f$, with their respective probabilities @f$ p_0,
+ * ..., p_{K-1} @f$ with @f$ p_0+p_1+...+p_{K-1}=1 at f$. To garantee
+ * that the @f$\omega_i at f$ are in increasing order, we define
+ * @f$\delta_i=\omega_i - \omega_{i-1}@f$.
+ *
+ * This model includes 2*K parameters (@f$\kappa at f$, relative
+ * probabilities @f$ theta1, theta2, ..., thetaK-1 @f$ and @f$omega0,
+ * delta1, deltaK-1 at f$). The codon frequencies @f$\pi_j at f$ are either
+ * observed or infered.
+ *
+ * References:
+ *
+ * Yang, Z., R. Nielsen, N. Goldman, and A.-M. K. Pedersen (2000)
+ * Genetics 155:431-449.
+ * 
+ */
+class YNGKP_M3:
+    public AbstractBiblioMixedSubstitutionModel,
+    virtual public ReversibleSubstitutionModel
+{
+private:
+  std::auto_ptr<MixtureOfASubstitutionModel> pmixmodel_;
+
+  /*
+   *@brief indexes of 2 codons between which the substitution is
+   * synonymous, to set a basis to the homogeneization of the rates.
+   *
+   */
+
+  int synfrom_, synto_;
+  
+public:
+  YNGKP_M3(const GeneticCode* gc, FrequenciesSet* codonFreqs, unsigned int nclass = 3);
+
+  ~YNGKP_M3();
+  
+  YNGKP_M3* clone() const { return new YNGKP_M3(*this); }
+
+  YNGKP_M3(const YNGKP_M3&);
+
+  YNGKP_M3& operator=(const YNGKP_M3&);
+
+protected:
+  void updateMatrices();
+
+public:
+  const SubstitutionModel& getModel() const { return *pmixmodel_.get(); }
+
+  const MixedSubstitutionModel& getMixedModel() const { return *pmixmodel_.get(); }
+
+  std::string getName() const { return "YNGKP_M3"; }
+
+private:
+  SubstitutionModel& getModel() { return *pmixmodel_.get(); }
+  
+  MixedSubstitutionModel& getMixedModel() { return *pmixmodel_.get(); }
+};
+
+} //end of namespace bpp.
+
+#endif	//_YNGKP_M3_H_
+
diff --git a/src/Bpp/Phyl/Model/Codon/YNGKP_M7.cpp b/src/Bpp/Phyl/Model/Codon/YNGKP_M7.cpp
new file mode 100644
index 0000000..2a2c9e5
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/YNGKP_M7.cpp
@@ -0,0 +1,157 @@
+//
+// File: YNGKP_M7.cpp
+// Created by:  Laurent Gueguen
+// Created on: May 2010
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "YNGKP_M7.h"
+#include "YN98.h"
+
+#include <Bpp/Numeric/NumConstants.h>
+#include <Bpp/Numeric/Prob/BetaDiscreteDistribution.h>
+
+#include <Bpp/Text/TextTools.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+YNGKP_M7::YNGKP_M7(const GeneticCode* gc, FrequenciesSet* codonFreqs, unsigned int nclass) :
+  AbstractBiblioMixedSubstitutionModel("YNGKP_M7."),
+  pmixmodel_(0),
+  synfrom_(-1),
+  synto_(-1)
+{
+  if (nclass <= 0)
+    throw Exception("Bad number of classes for model YNGKP_M7: " + TextTools::toString(nclass));
+
+  // build the submodel
+
+  BetaDiscreteDistribution* pbdd = new BetaDiscreteDistribution(nclass, 2, 2);
+
+  map<string, DiscreteDistribution*> mpdd;
+  mpdd["omega"] = pbdd;
+
+  pmixmodel_.reset(new MixtureOfASubstitutionModel(gc->getSourceAlphabet(), new YN98(gc, codonFreqs), mpdd));
+  delete pbdd;
+
+  // mapping the parameters
+
+  ParameterList pl = pmixmodel_->getParameters();
+  for (size_t i = 0; i < pl.size(); i++)
+  {
+    lParPmodel_.addParameter(Parameter(pl[i]));
+  }
+
+  vector<std::string> v = dynamic_cast<YN98*>(pmixmodel_->getNModel(0))->getFrequenciesSet()->getParameters().getParameterNames();
+
+  for (size_t i = 0; i < v.size(); i++)
+  {
+    mapParNamesFromPmodel_[v[i]] = getParameterNameWithoutNamespace("YNGKP_M7." + v[i].substr(5));
+  }
+
+  mapParNamesFromPmodel_["YN98.kappa"] = "kappa";
+  mapParNamesFromPmodel_["YN98.omega_Beta.alpha"] = "p";
+  mapParNamesFromPmodel_["YN98.omega_Beta.beta"] = "q";
+
+  // specific parameters
+
+  string st;
+  for (map<string, string>::iterator it = mapParNamesFromPmodel_.begin(); it != mapParNamesFromPmodel_.end(); it++)
+  {
+    st = pmixmodel_->getParameterNameWithoutNamespace(it->first);
+    addParameter_(new Parameter("YNGKP_M7." + it->second, pmixmodel_->getParameterValue(st),
+                            pmixmodel_->getParameter(st).hasConstraint() ? pmixmodel_->getParameter(st).getConstraint()->clone() : 0, true));
+  }
+
+  // look for synonymous codons
+  for (synfrom_ = 1; synfrom_ < (int)gc->getSourceAlphabet()->getSize(); synfrom_++)
+  {
+    for (synto_ = 0; synto_ < synfrom_; synto_++)
+    {
+      if ((gc->areSynonymous(synfrom_, synto_))
+          && (pmixmodel_->getNModel(0)->Qij(synfrom_, synto_) != 0)
+          && (pmixmodel_->getNModel(1)->Qij(synfrom_, synto_) != 0))
+        break;
+    }
+    if (synto_ < synfrom_)
+      break;
+  }
+
+  if (synto_ == (int)gc->getSourceAlphabet()->getSize())
+    throw Exception("Impossible to find synonymous codons");
+
+  // update Matrices
+
+  updateMatrices();
+}
+
+YNGKP_M7::YNGKP_M7(const YNGKP_M7& mod2) : AbstractBiblioMixedSubstitutionModel(mod2),
+  pmixmodel_(new MixtureOfASubstitutionModel(*mod2.pmixmodel_)),
+  synfrom_(mod2.synfrom_),
+  synto_(mod2.synto_)
+{}
+
+YNGKP_M7& YNGKP_M7::operator=(const YNGKP_M7& mod2)
+{
+  AbstractBiblioMixedSubstitutionModel::operator=(mod2);
+
+  pmixmodel_.reset(new MixtureOfASubstitutionModel(*mod2.pmixmodel_));
+  synfrom_ = mod2.synfrom_;
+  synto_ = mod2.synto_;
+
+  return *this;
+}
+
+YNGKP_M7::~YNGKP_M7() {}
+
+void YNGKP_M7::updateMatrices()
+{
+  AbstractBiblioSubstitutionModel::updateMatrices();
+
+  // homogeneization of the synonymous substitution rates
+
+  Vdouble vd;
+
+  for (unsigned int i = 0; i < pmixmodel_->getNumberOfModels(); i++)
+  {
+    vd.push_back(1 / pmixmodel_->getNModel(i)->Qij(synfrom_, synto_));
+  }
+
+  pmixmodel_->setVRates(vd);
+}
+
diff --git a/src/Bpp/Phyl/Model/Codon/YNGKP_M7.h b/src/Bpp/Phyl/Model/Codon/YNGKP_M7.h
new file mode 100644
index 0000000..03e61dd
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/YNGKP_M7.h
@@ -0,0 +1,122 @@
+//
+// File: YNGKP_M7.h
+// Created by: Laurent Gueguen
+// Created on: May 2010
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _YNGKP_M7_H_
+#define _YNGKP_M7_H_
+
+#include "../AbstractBiblioMixedSubstitutionModel.h"
+#include "../MixtureOfASubstitutionModel.h"
+#include "../FrequenciesSet/CodonFrequenciesSet.h"
+
+#include <Bpp/Seq/GeneticCode/GeneticCode.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The Yang et al (2000) M7 substitution model for codons.
+ * @author Laurent Guéguen
+ *
+ * This model is a mixture of models as described in YN98 class, the
+ * mixture being defined on the selection parameter to allow it to
+ * vary among sites, following a Beta distribution.
+ *
+ * This model includes 3 parameters (@f$\kappa at f$, @f$ p @f$ and
+ * @f$q at f$) of the Beta distribution. The codon frequencies
+ * @f$\pi_j at f$ are either observed or infered.
+ *
+ * References:
+ *
+ * Yang, Z., R. Nielsen, N. Goldman, and A.-M. K. Pedersen (2000)
+ * Genetics 155:431-449.
+ * 
+ */
+class YNGKP_M7:
+    public AbstractBiblioMixedSubstitutionModel,
+    virtual public ReversibleSubstitutionModel
+{
+private:
+  std::auto_ptr<MixtureOfASubstitutionModel> pmixmodel_;
+
+  /*
+   *@brief indexes of 2 codons between which the substitution is
+   * synonymous, to set a basis to the homogeneization of the rates.
+   *
+   */
+
+  int synfrom_, synto_;
+  
+public:
+  /*
+   *@brief Constructor that requires the number of classes of the
+   * BetaDiscreteDistribution.
+   *
+   */
+  
+  YNGKP_M7(const GeneticCode* gc, FrequenciesSet* codonFreqs, unsigned int nclass);
+
+  ~YNGKP_M7();
+  
+  YNGKP_M7* clone() const { return new YNGKP_M7(*this); }
+
+  YNGKP_M7(const YNGKP_M7&);
+
+  YNGKP_M7& operator=(const YNGKP_M7&);
+
+protected:
+  void updateMatrices();
+
+public:
+  const SubstitutionModel& getModel() const { return *pmixmodel_.get(); }
+
+  const MixedSubstitutionModel& getMixedModel() const { return *pmixmodel_.get(); }
+
+  std::string getName() const { return "YNGKP_M7"; }
+
+private:
+  SubstitutionModel& getModel() { return *pmixmodel_.get(); }
+
+  MixedSubstitutionModel& getMixedModel() { return *pmixmodel_.get(); }
+
+};
+
+} //end of namespace bpp.
+
+#endif	//_YNGKP_M7_H_
+
diff --git a/src/Bpp/Phyl/Model/Codon/YNGKP_M8.cpp b/src/Bpp/Phyl/Model/Codon/YNGKP_M8.cpp
new file mode 100644
index 0000000..2fb5891
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/YNGKP_M8.cpp
@@ -0,0 +1,171 @@
+//
+// File: YNGKP_M8.cpp
+// Created by:  Laurent Gueguen
+// Created on: May 2010
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "YNGKP_M8.h"
+#include "YN98.h"
+
+#include <Bpp/Numeric/Prob/MixtureOfDiscreteDistributions.h>
+#include <Bpp/Numeric/Prob/SimpleDiscreteDistribution.h>
+#include <Bpp/Numeric/Prob/BetaDiscreteDistribution.h>
+#include <Bpp/Text/TextTools.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+YNGKP_M8::YNGKP_M8(const GeneticCode* gc, FrequenciesSet* codonFreqs, unsigned int nclass) :
+  AbstractBiblioMixedSubstitutionModel("YNGKP_M8."),
+  pmixmodel_(0),
+  synfrom_(-1),
+  synto_(-1)
+{
+  if (nclass <= 0)
+    throw Exception("Bad number of classes for model YNGKP_M8: " + TextTools::toString(nclass));
+
+  // build the submodel
+
+  BetaDiscreteDistribution* pbdd = new BetaDiscreteDistribution(nclass, 2, 2);
+
+  vector<double> val; val.push_back(2);
+  vector<double> prob; prob.push_back(1);
+  SimpleDiscreteDistribution* psdd = new SimpleDiscreteDistribution(val, prob);
+
+  vector<DiscreteDistribution*> v_distr;
+  v_distr.push_back(pbdd); v_distr.push_back(psdd);
+  prob.clear(); prob.push_back(0.5); prob.push_back(0.5);
+
+  MixtureOfDiscreteDistributions* pmodd = new MixtureOfDiscreteDistributions(v_distr, prob);
+
+  map<string, DiscreteDistribution*> mpdd;
+  mpdd["omega"] = pmodd;
+
+  pmixmodel_.reset(new MixtureOfASubstitutionModel(gc->getSourceAlphabet(), new YN98(gc, codonFreqs), mpdd));
+  delete pbdd;
+
+  // mapping the parameters
+
+  ParameterList pl = pmixmodel_->getParameters();
+  for (size_t i = 0; i < pl.size(); i++)
+  {
+    lParPmodel_.addParameter(Parameter(pl[i]));
+  }
+
+  vector<std::string> v = dynamic_cast<YN98*>(pmixmodel_->getNModel(0))->getFrequenciesSet()->getParameters().getParameterNames();
+
+  for (size_t i = 0; i < v.size(); i++)
+  {
+    mapParNamesFromPmodel_[v[i]] = getParameterNameWithoutNamespace("YNGKP_M8." + v[i].substr(5));
+  }
+
+  mapParNamesFromPmodel_["YN98.kappa"] = "kappa";
+  mapParNamesFromPmodel_["YN98.omega_Mixture.theta1"] = "p0";
+  mapParNamesFromPmodel_["YN98.omega_Mixture.1_Beta.alpha"] = "p";
+  mapParNamesFromPmodel_["YN98.omega_Mixture.1_Beta.beta"] = "q";
+  mapParNamesFromPmodel_["YN98.omega_Mixture.2_Simple.V1"] = "omegas";
+
+  // specific parameters
+
+  string st;
+  for (map<string, string>::iterator it = mapParNamesFromPmodel_.begin(); it != mapParNamesFromPmodel_.end(); it++)
+  {
+    st = pmixmodel_->getParameterNameWithoutNamespace(it->first);
+    if (it->second != "omegas")
+      addParameter_(new Parameter("YNGKP_M8." + it->second, pmixmodel_->getParameterValue(st),
+                              pmixmodel_->getParameter(st).hasConstraint() ? pmixmodel_->getParameter(st).getConstraint()->clone() : 0, true));
+  }
+
+  addParameter_(new Parameter("YNGKP_M8.omegas", 2., new IntervalConstraint(1, 1, false), true));
+
+  // look for synonymous codons
+  for (synfrom_ = 1; synfrom_ < (int)gc->getSourceAlphabet()->getSize(); synfrom_++)
+  {
+    for (synto_ = 0; synto_ < synfrom_; synto_++)
+    {
+      if ((gc->areSynonymous(synfrom_, synto_))
+          && (pmixmodel_->getNModel(0)->Qij(synfrom_, synto_) != 0)
+          && (pmixmodel_->getNModel(1)->Qij(synfrom_, synto_) != 0))
+        break;
+    }
+    if (synto_ < synfrom_)
+      break;
+  }
+
+  if (synto_ == (int)gc->getSourceAlphabet()->getSize())
+    throw Exception("Impossible to find synonymous codons");
+
+  // update Matrices
+  updateMatrices();
+}
+
+YNGKP_M8::YNGKP_M8(const YNGKP_M8& mod2) : AbstractBiblioMixedSubstitutionModel(mod2),
+  pmixmodel_(new MixtureOfASubstitutionModel(*mod2.pmixmodel_)),
+  synfrom_(mod2.synfrom_),
+  synto_(mod2.synto_)
+{}
+
+YNGKP_M8& YNGKP_M8::operator=(const YNGKP_M8& mod2)
+{
+  AbstractBiblioMixedSubstitutionModel::operator=(mod2);
+
+  pmixmodel_.reset(new MixtureOfASubstitutionModel(*mod2.pmixmodel_));
+  synfrom_ = mod2.synfrom_;
+  synto_ = mod2.synto_;
+
+  return *this;
+}
+
+YNGKP_M8::~YNGKP_M8() {}
+
+void YNGKP_M8::updateMatrices()
+{
+  AbstractBiblioSubstitutionModel::updateMatrices();
+
+  // homogeneization of the synonymous substittion rates
+
+  Vdouble vd;
+
+  for (unsigned int i = 0; i < pmixmodel_->getNumberOfModels(); i++)
+  {
+    vd.push_back(1 / pmixmodel_->getNModel(i)->Qij(synfrom_, synto_));
+  }
+
+  pmixmodel_->setVRates(vd);
+}
+
diff --git a/src/Bpp/Phyl/Model/Codon/YNGKP_M8.h b/src/Bpp/Phyl/Model/Codon/YNGKP_M8.h
new file mode 100644
index 0000000..849f101
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Codon/YNGKP_M8.h
@@ -0,0 +1,125 @@
+//
+// File: YNGKP_M8.h
+// Created by: Laurent Gueguen
+// Created on: May 2010
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _YNGKP_M8_H_
+#define _YNGKP_M8_H_
+
+#include "../AbstractBiblioMixedSubstitutionModel.h"
+#include "../MixtureOfASubstitutionModel.h"
+#include "../FrequenciesSet/CodonFrequenciesSet.h"
+
+#include <Bpp/Seq/GeneticCode/GeneticCode.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The Yang et al (2000) M8 substitution model for codons.
+ * @author Laurent Guéguen
+ *
+ * This model is a mixture of models as described in YN98 class, the
+ * mixture being defined on the selection parameter oomega to allow it
+ * to vary among sites, following a mixture of a Beta distribution and
+ * of another value above 1.
+ *
+ * This model includes 5 parameters (@f$\kappa at f$, @f$ \alpha @f$ and
+ * @f$\beta at f$) of the Beta distribution, @f$p0 at f$ the weight of the
+ * Beta distribution and @f$\omega @f$ the selection parameter above 1
+ * (with weight @f$ 1-p0 @f$). The codon frequencies @f$ \pi_j @f$ are
+ * either observed or infered.
+ *
+ * References:
+ *
+ * Yang, Z., R. Nielsen, N. Goldman, and A.-M. K. Pedersen (2000)
+ * Genetics 155:431-449.
+ * 
+ */
+class YNGKP_M8:
+    public AbstractBiblioMixedSubstitutionModel,
+    virtual public ReversibleSubstitutionModel
+{
+private:
+  std::auto_ptr<MixtureOfASubstitutionModel> pmixmodel_;
+
+  /*
+   *@brief indexes of 2 codons between which the substitution is
+   * synonymous, to set a basis to the homogeneization of the rates.
+   *
+   */
+
+  int synfrom_, synto_;
+  
+public:
+  /*
+   *@brief Constructor that requires the number of classes of the
+   * BetaDiscreteDistribution.
+   *
+   */
+  
+  YNGKP_M8(const GeneticCode* gc, FrequenciesSet* codonFreqs, unsigned int nbclass);
+
+  ~YNGKP_M8();
+  
+  YNGKP_M8* clone() const { return new YNGKP_M8(*this); }
+
+  YNGKP_M8(const YNGKP_M8&);
+
+  YNGKP_M8& operator=(const YNGKP_M8&);
+
+protected:
+  void updateMatrices();
+
+public:
+  const SubstitutionModel& getModel() const { return *pmixmodel_.get(); }
+
+  const MixedSubstitutionModel& getMixedModel() const { return *pmixmodel_.get(); }
+
+  std::string getName() const { return "YNGKP_M8"; }
+
+private:
+  SubstitutionModel& getModel() { return *pmixmodel_.get(); }
+
+  MixedSubstitutionModel& getMixedModel() { return *pmixmodel_.get(); }
+
+};
+
+} //end of namespace bpp.
+
+#endif	//_YNGKP_M8_H_
+
diff --git a/src/Bpp/Phyl/Model/FrequenciesSet/CodonFrequenciesSet.cpp b/src/Bpp/Phyl/Model/FrequenciesSet/CodonFrequenciesSet.cpp
new file mode 100644
index 0000000..59820c0
--- /dev/null
+++ b/src/Bpp/Phyl/Model/FrequenciesSet/CodonFrequenciesSet.cpp
@@ -0,0 +1,622 @@
+//
+// File: CodonFrequenciesSet.cpp
+// Created by: Laurent Gueguen
+// Created on: lundi 2 avril 2012, à 14h 15
+//
+
+/*
+   Copyright or (c) or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "CodonFrequenciesSet.h"
+#include "NucleotideFrequenciesSet.h"
+
+using namespace bpp;
+using namespace std;
+
+// ////////////////////////////
+// FullCodonFrequenciesSet
+
+FullCodonFrequenciesSet::FullCodonFrequenciesSet(const CodonAlphabet* alphabet, bool allowNullFreqs, const string& name) :
+  AbstractFrequenciesSet(alphabet->getSize(), alphabet, "Full.", name)
+{
+  size_t size = alphabet->getSize() - alphabet->numberOfStopCodons();
+  size_t j = 0;
+
+  for (size_t i = 0; i < alphabet->getSize() - 1; i++)
+  {
+    if (alphabet->isStop(static_cast<int>(i)))
+    {
+      getFreq_(i) = 0;
+    }
+    else
+    {
+      addParameter_(new Parameter(
+                      "Full.theta" + TextTools::toString(i + 1),
+                      1. / static_cast<double>(size - j),
+                      allowNullFreqs ?
+                      &Parameter::PROP_CONSTRAINT_IN :
+                      &FrequenciesSet::FREQUENCE_CONSTRAINT_MILLI));
+      getFreq_(i) = 1. / static_cast<double>(size);
+      j++;
+    }
+  }
+  size_t i = alphabet->getSize() - 1;
+  getFreq_(i) = (alphabet->isStop(static_cast<int>(i))) ? 0 : 1. / static_cast<double>(size);
+}
+
+
+FullCodonFrequenciesSet::FullCodonFrequenciesSet(const CodonAlphabet* alphabet, const vector<double>& initFreqs, bool allowNullFreqs, const string& name) :
+  AbstractFrequenciesSet(alphabet->getSize(), alphabet, "Full.", name)
+{
+  if (initFreqs.size() != alphabet->getSize())
+    throw Exception("FullCodonFrequenciesSet(constructor). There must be " + TextTools::toString(alphabet->getSize()) + " frequencies.");
+  double sum = 0.0;
+
+  for (size_t i = 0; i < initFreqs.size(); i++)
+  {
+    if (!alphabet->isStop(static_cast<int>(i)))
+    {
+      sum += initFreqs[i];
+    }
+  }
+
+  double y = 1;
+  for (size_t i = 0; i < alphabet->getSize() - 1; i++)
+  {
+    if (alphabet->isStop(static_cast<int>(i)))
+    {
+      getFreq_(i) = 0;
+    }
+    else
+    {
+      addParameter_(new Parameter(
+                      "Full.theta" + TextTools::toString(i + 1),
+                      initFreqs[i] / sum / y,
+                      allowNullFreqs ?
+                      &Parameter::PROP_CONSTRAINT_IN :
+                      &FrequenciesSet::FREQUENCE_CONSTRAINT_MILLI));
+      getFreq_(i) = initFreqs[i] / sum;
+      y -= initFreqs[i] / sum;
+    }
+  }
+  size_t i = alphabet->getSize() - 1;
+  getFreq_(i) = (alphabet->isStop(static_cast<int>(i))) ? 0 : initFreqs[i] / sum;
+}
+
+void FullCodonFrequenciesSet::setFrequencies(const vector<double>& frequencies)
+{
+  if (frequencies.size() != getAlphabet()->getSize())
+    throw DimensionException("FullFrequenciesSet::setFrequencies", frequencies.size(), getAlphabet()->getSize());
+  const CodonAlphabet* alphabet = getAlphabet();
+
+  double sum = 0.0;
+  size_t i;
+  for (i = 0; i < frequencies.size(); i++)
+  {
+    if (!(alphabet->isStop(static_cast<int>(i))))
+      sum += frequencies[i];
+  }
+
+  double y = 1;
+  for (i = 0; i < alphabet->getSize() - 1; i++)
+  {
+    if (alphabet->isStop(static_cast<int>(i)))
+    {
+      getFreq_(i) = 0;
+    }
+    else
+    {
+      getParameter_("theta" + TextTools::toString(i + 1)).setValue(frequencies[i] / sum / y);
+      y -= frequencies[i] / sum;
+      getFreq_(i) = frequencies[i] / sum;
+    }
+  }
+  i = alphabet->getSize() - 1;
+  getFreq_(i) = (alphabet->isStop(static_cast<int>(i))) ? 0 : frequencies[i] / sum;
+}
+
+void FullCodonFrequenciesSet::fireParameterChanged(const ParameterList& parameters)
+{
+  const CodonAlphabet* alphabet = getAlphabet();
+  double y = 1;
+  size_t i;
+  for (i = 0; i < alphabet->getSize() - 1; i++)
+  {
+    if (!(alphabet->isStop(static_cast<int>(i))))
+    {
+      getFreq_(i) = getParameter_("theta" + TextTools::toString(i + 1)).getValue() * y;
+      y *= 1 - getParameter_("theta" + TextTools::toString(i + 1)).getValue();
+    }
+  }
+
+  i = alphabet->getSize() - 1;
+  getFreq_(i) = (alphabet->isStop(static_cast<int>(i))) ? 0 : y;
+}
+
+
+// ////////////////////////////
+// FullPerAACodonFrequenciesSet
+
+FullPerAACodonFrequenciesSet::FullPerAACodonFrequenciesSet(const GeneticCode* gencode,
+                                                           const ProteinFrequenciesSet* ppfs) :
+  AbstractFrequenciesSet(gencode->getSourceAlphabet()->getSize(), gencode->getSourceAlphabet(), "FullPerAA.", "FullPerAA"),
+  pgc_(gencode),
+  ppfs_(ppfs->clone()),
+  vS_()
+{
+  const ProteicAlphabet* ppa = dynamic_cast<const ProteicAlphabet*>(pgc_->getTargetAlphabet());
+
+  for (size_t i = 0; i < ppa->getSize(); i++)
+  {
+    vector<int> vc = pgc_->getSynonymous(static_cast<int>(i));
+    vS_.push_back(Simplex(vc.size(), 1, ""));
+
+    Simplex& si = vS_[i];
+    si.setNamespace("FullPerAA." + ppa->getAbbr(static_cast<int>(i)) + "_");
+    addParameters_(si.getParameters());
+  }
+
+  ppfs_->setNamespace("FullPerAA." + ppfs_->getName() + ".");
+  addParameters_(ppfs_->getParameters());
+
+  updateFrequencies();
+}
+
+FullPerAACodonFrequenciesSet::FullPerAACodonFrequenciesSet(const GeneticCode* gencode) :
+  AbstractFrequenciesSet(gencode->getSourceAlphabet()->getSize(), gencode->getSourceAlphabet(), "FullPerAA.", "FullPerAA"),
+  pgc_(gencode),
+  ppfs_(new FixedProteinFrequenciesSet(dynamic_cast<const ProteicAlphabet*>(gencode->getTargetAlphabet()), "FullPerAA.")),
+  vS_()
+{
+  const ProteicAlphabet* ppa = dynamic_cast<const ProteicAlphabet*>(pgc_->getTargetAlphabet());
+
+  for (size_t i = 0; i < ppa->getSize(); i++)
+  {
+    vector<int> vc = pgc_->getSynonymous(static_cast<int>(i));
+    vS_.push_back(Simplex(vc.size(), 1, ""));
+
+    Simplex& si = vS_[i];
+    si.setNamespace("FullPerAA." + ppa->getAbbr(static_cast<int>(i)) + "_");
+    addParameters_(si.getParameters());
+  }
+
+  updateFrequencies();
+}
+
+FullPerAACodonFrequenciesSet::FullPerAACodonFrequenciesSet(const FullPerAACodonFrequenciesSet& ffs) :
+  CodonFrequenciesSet(ffs),
+  AbstractFrequenciesSet(ffs),
+  pgc_(ffs.pgc_),
+  ppfs_(ffs.ppfs_->clone()),
+  vS_(ffs.vS_)
+{
+  updateFrequencies();
+}
+
+FullPerAACodonFrequenciesSet::~FullPerAACodonFrequenciesSet()
+{
+  if (ppfs_)
+    delete ppfs_;
+  ppfs_ = 0;
+}
+
+FullPerAACodonFrequenciesSet& FullPerAACodonFrequenciesSet::operator=(const FullPerAACodonFrequenciesSet& ffs)
+{
+  if (ppfs_)
+    delete ppfs_;
+
+  CodonFrequenciesSet::operator=(ffs);
+  AbstractFrequenciesSet::operator=(ffs);
+  pgc_ = ffs.pgc_;
+  ppfs_ = ffs.ppfs_->clone();
+  vS_ = ffs.vS_;
+
+  return *this;
+}
+
+void FullPerAACodonFrequenciesSet::fireParameterChanged(const ParameterList& parameters)
+{
+  if (dynamic_cast<AbstractFrequenciesSet*>(ppfs_))
+    (dynamic_cast<AbstractFrequenciesSet*>(ppfs_))->matchParametersValues(parameters);
+  for (size_t i = 0; i < vS_.size(); i++)
+  {
+    vS_[i].matchParametersValues(parameters);
+  }
+  updateFrequencies();
+}
+
+void FullPerAACodonFrequenciesSet::updateFrequencies()
+{
+  const ProteicAlphabet* ppa = dynamic_cast<const ProteicAlphabet*>(pgc_->getTargetAlphabet());
+
+  for (size_t i = 0; i < ppa->getSize(); i++)
+  {
+    std::vector<int> vc = pgc_->getSynonymous(static_cast<int>(i));
+    for (size_t j = 0; j < vc.size(); j++)
+    {
+      getFreq_(vc[j]) = (ppfs_->getFrequencies())[i] * vS_[i].prob(j);
+    }
+  }
+}
+
+void FullPerAACodonFrequenciesSet::setFrequencies(const vector<double>& frequencies)
+{
+  if (frequencies.size() != getAlphabet()->getSize())
+    throw DimensionException("FullParAAFrequenciesSet::setFrequencies", frequencies.size(), getAlphabet()->getSize());
+
+  const ProteicAlphabet* ppa = dynamic_cast<const ProteicAlphabet*>(pgc_->getTargetAlphabet());
+
+  vector<double> vaa;
+  double S = 0;
+  for (size_t i = 0; i < ppa->getSize(); i++)
+  {
+    vector<double> vp;
+    double s = 0;
+    std::vector<int> vc = pgc_->getSynonymous(static_cast<int>(i));
+    for (size_t j = 0; j < vc.size(); j++)
+    {
+      vp.push_back(frequencies[vc[j]]);
+      s += frequencies[vc[j]];
+    }
+    S += s;
+    vaa.push_back(s);
+    vp /= s;
+    vS_[i].setFrequencies(vp);
+    matchParametersValues(vS_[i].getParameters());
+  }
+
+  vaa /= S; // to avoid counting of stop codons
+  ppfs_->setFrequencies(vaa);
+  matchParametersValues(ppfs_->getParameters());
+  updateFrequencies();
+}
+
+void FullPerAACodonFrequenciesSet::setNamespace(const std::string& prefix)
+{
+  const ProteicAlphabet* ppa = dynamic_cast<const ProteicAlphabet*>(pgc_->getTargetAlphabet());
+
+  AbstractFrequenciesSet::setNamespace(prefix);
+  ppfs_->setNamespace(prefix + ppfs_->getName() + ".");
+  for (size_t i = 0; i < vS_.size(); i++)
+  {
+    vS_[i].setNamespace(prefix + ppa->getAbbr(static_cast<int>(i)) + "_");
+  }
+}
+
+
+// ///////////////////////////////////////////
+// / FixedCodonFrequenciesSet
+
+FixedCodonFrequenciesSet::FixedCodonFrequenciesSet(const CodonAlphabet* alphabet, const vector<double>& initFreqs, const string& name) :
+  AbstractFrequenciesSet(alphabet->getSize(), alphabet, "Fixed.", name)
+{
+  setFrequencies(initFreqs);
+}
+
+FixedCodonFrequenciesSet::FixedCodonFrequenciesSet(const CodonAlphabet* alphabet, const string& name) :
+  AbstractFrequenciesSet(alphabet->getSize(), alphabet, "Fixed.", name)
+{
+  size_t size = alphabet->getSize() - alphabet->numberOfStopCodons();
+
+  for (size_t i = 0; i < alphabet->getSize(); i++)
+  {
+    getFreq_(i) = (alphabet->isStop(static_cast<int>(i))) ? 0 : 1. / static_cast<double>(size);
+  }
+}
+
+void FixedCodonFrequenciesSet::setFrequencies(const vector<double>& frequencies)
+{
+  const CodonAlphabet* ca = dynamic_cast<const CodonAlphabet*>(getAlphabet());
+  if (frequencies.size() != ca->getSize())
+    throw DimensionException("FixedFrequenciesSet::setFrequencies", frequencies.size(), ca->getSize());
+  double sum = 0.0;
+
+  for (size_t i = 0; i < frequencies.size(); i++)
+  {
+    if (!(ca->isStop(static_cast<int>(i))))
+      sum += frequencies[i];
+  }
+
+  for (size_t i = 0; i < ca->getSize(); i++)
+  {
+    getFreq_(i) = (ca->isStop(static_cast<int>(i))) ? 0 : frequencies[i] / sum;
+  }
+}
+
+
+// ///////////////////////////////////////////////////////////////////
+// // CodonFromIndependentFrequenciesSet
+
+
+CodonFromIndependentFrequenciesSet::CodonFromIndependentFrequenciesSet(
+  const CodonAlphabet* pCA,
+  const std::vector<FrequenciesSet*>& freqvector,
+  const string& name,
+  const string& mgmtStopFreq) :
+  WordFromIndependentFrequenciesSet(pCA, freqvector, "", name),
+  mStopNeigh_(),
+  mgmtStopFreq_(2)
+{
+  if (mgmtStopFreq=="uniform")
+    mgmtStopFreq_=0;
+  else if (mgmtStopFreq=="linear")
+    mgmtStopFreq_=1;
+  
+  // fill the map of the stop codons
+
+  vector<int> vspcod = getAlphabet()->stopCodons();
+  for (size_t ispcod = 0; ispcod < vspcod.size(); ispcod++)
+  {
+    size_t pow = 1;
+    int nspcod = vspcod[ispcod];
+    for (int ph = 0; ph < 3; ph++)
+    {
+      size_t nspcod0 = nspcod - pow * getAlphabet()->getNPosition(nspcod, 2 - ph);
+      for (size_t dec = 0; dec < 4; dec++)
+      {
+        size_t vois = nspcod0 + pow * dec;
+        if (!getAlphabet()->isStop(static_cast<int>(vois)))
+          mStopNeigh_[nspcod].push_back(static_cast<int>(vois));
+      }
+      pow *= 4;
+    }
+  }
+
+  updateFrequencies();
+}
+
+const CodonAlphabet* CodonFromIndependentFrequenciesSet::getAlphabet() const
+{
+  return dynamic_cast<const CodonAlphabet*>(WordFromIndependentFrequenciesSet::getAlphabet());
+}
+
+CodonFromIndependentFrequenciesSet::CodonFromIndependentFrequenciesSet(const CodonFromIndependentFrequenciesSet& iwfs) :
+  WordFromIndependentFrequenciesSet(iwfs),
+  mStopNeigh_(iwfs.mStopNeigh_),
+  mgmtStopFreq_(iwfs.mgmtStopFreq_)
+{
+  updateFrequencies();
+}
+
+CodonFromIndependentFrequenciesSet& CodonFromIndependentFrequenciesSet::operator=(const CodonFromIndependentFrequenciesSet& iwfs)
+{
+  WordFromIndependentFrequenciesSet::operator=(iwfs);
+  mStopNeigh_ = iwfs.mStopNeigh_;
+  mgmtStopFreq_ = iwfs.mgmtStopFreq_;
+  return *this;
+}
+
+void CodonFromIndependentFrequenciesSet::updateFrequencies()
+{
+  WordFromIndependentFrequenciesSet::updateFrequencies();
+
+  size_t s = getAlphabet()->getSize();
+
+  if (mgmtStopFreq_!=0)
+    {
+      // The frequencies of the stop codons are distributed to all
+      // neighbour non-stop codons
+      double f[64];
+      for (size_t i = 0; i < s; i++)
+        {
+          f[i] = 0;
+        }
+
+      std::map<int, Vint>::iterator mStopNeigh_it(mStopNeigh_.begin());
+      while (mStopNeigh_it != mStopNeigh_.end())
+        {
+          int stNb = mStopNeigh_it->first;
+          Vint vneigh = mStopNeigh_it->second;
+          double sneifreq = 0;
+          for (size_t vn = 0; vn < vneigh.size(); vn++)
+            {
+              sneifreq += pow(getFreq_(vneigh[vn]), mgmtStopFreq_);
+            }
+          double x = getFreq_(stNb) / sneifreq;
+          for (size_t vn = 0; vn < vneigh.size(); vn++)
+            {
+              f[vneigh[vn]] += pow(getFreq_(vneigh[vn]), mgmtStopFreq_) * x;
+            }
+          getFreq_(stNb) = 0;
+          mStopNeigh_it++;
+        }
+
+      for (size_t i = 0; i < s; i++)
+        {
+          getFreq_(i) += f[i];
+        }
+    }
+  else
+    {
+      double sum=0.;
+      for (unsigned int i = 0; i < s; i++)
+        if (!getAlphabet()->isStop(i))
+          sum+=getFreq_(i);
+ 
+      for (unsigned int i = 0; i < s; i++)
+        if (getAlphabet()->isStop(i))
+          getFreq_(i)=0;
+        else
+          getFreq_(i)/=sum;
+    }
+}
+
+// ///////////////////////////////////////////////////////////////////
+// // CodonFromUniqueFrequenciesSet
+
+
+CodonFromUniqueFrequenciesSet::CodonFromUniqueFrequenciesSet(const CodonAlphabet* pCA, FrequenciesSet* pfreq, const string& name, const string&  mgmtStopFreq) :
+  WordFromUniqueFrequenciesSet(pCA, pfreq, "", name),
+  mStopNeigh_(),
+  mgmtStopFreq_(2)
+{
+  if (mgmtStopFreq=="uniform")
+    mgmtStopFreq_=0;
+  else if (mgmtStopFreq=="linear")
+    mgmtStopFreq_=1;
+  
+  // fill the map of the stop codons
+
+  vector<int> vspcod = getAlphabet()->stopCodons();
+  for (size_t ispcod = 0; ispcod < vspcod.size(); ispcod++)
+    {
+      size_t pow = 1;
+      int nspcod = vspcod[ispcod];
+      for (int ph = 0; ph < 3; ph++)
+        {
+          size_t nspcod0 = nspcod - pow * getAlphabet()->getNPosition(nspcod, 2 - ph);
+          for (size_t dec = 0; dec < 4; dec++)
+            {
+              size_t vois = nspcod0 + pow * dec;
+              if (!getAlphabet()->isStop(static_cast<int>(vois)))
+                mStopNeigh_[nspcod].push_back(static_cast<int>(vois));
+            }
+          pow *= 4;
+        }
+    }
+
+  updateFrequencies();
+}
+
+const CodonAlphabet* CodonFromUniqueFrequenciesSet::getAlphabet() const
+{
+  return dynamic_cast<const CodonAlphabet*>(WordFromUniqueFrequenciesSet::getAlphabet());
+}
+
+
+CodonFromUniqueFrequenciesSet::CodonFromUniqueFrequenciesSet(const CodonFromUniqueFrequenciesSet& iwfs) :
+  WordFromUniqueFrequenciesSet(iwfs),
+  mStopNeigh_(iwfs.mStopNeigh_),
+  mgmtStopFreq_(iwfs.mgmtStopFreq_)
+{
+  updateFrequencies();
+}
+
+CodonFromUniqueFrequenciesSet& CodonFromUniqueFrequenciesSet::operator=(const CodonFromUniqueFrequenciesSet& iwfs)
+{
+  WordFromUniqueFrequenciesSet::operator=(iwfs);
+  mStopNeigh_ = iwfs.mStopNeigh_;
+  mgmtStopFreq_ = iwfs.mgmtStopFreq_;
+  return *this;
+}
+
+void CodonFromUniqueFrequenciesSet::updateFrequencies()
+{
+  WordFromUniqueFrequenciesSet::updateFrequencies();
+
+  size_t s = getAlphabet()->getSize();
+
+  if (mgmtStopFreq_!=0)
+    {
+      // The frequencies of the stop codons are distributed to all
+      // neighbour non-stop codons
+      double f[64];
+      for (size_t i = 0; i < s; i++)
+        {
+          f[i] = 0;
+        }
+
+      std::map<int, Vint>::iterator mStopNeigh_it(mStopNeigh_.begin());
+      while (mStopNeigh_it != mStopNeigh_.end())
+        {
+          int stNb = mStopNeigh_it->first;
+          Vint vneigh = mStopNeigh_it->second;
+          double sneifreq = 0;
+          for (size_t vn = 0; vn < vneigh.size(); vn++)
+            {
+              sneifreq += pow(getFreq_(vneigh[vn]), mgmtStopFreq_);
+            }
+          double x = getFreq_(stNb) / sneifreq;
+          for (size_t vn = 0; vn < vneigh.size(); vn++)
+            {
+              f[vneigh[vn]] += pow(getFreq_(vneigh[vn]), mgmtStopFreq_) * x;
+            }
+          getFreq_(stNb) = 0;
+          mStopNeigh_it++;
+        }
+
+      for (size_t i = 0; i < s; i++)
+        {
+          getFreq_(i) += f[i];
+        }
+    }
+  else
+    {
+      double sum=0.;
+      for (unsigned int i = 0; i < s; i++)
+        if (!getAlphabet()->isStop(i))
+          sum+=getFreq_(i);
+ 
+      for (unsigned int i = 0; i < s; i++)
+        if (getAlphabet()->isStop(i))
+          getFreq_(i)=0;
+        else
+          getFreq_(i)/=sum;
+    }
+}
+
+/*********************************************************************/
+
+FrequenciesSet* CodonFrequenciesSet::getFrequenciesSetForCodons(short option, const CodonAlphabet& CA, const string& mgmtStopFreq)
+{
+  FrequenciesSet* codonFreqs;
+
+  if (option == F0)
+    codonFreqs = new FixedCodonFrequenciesSet(&CA, "F0");
+  else if (option == F1X4)
+    codonFreqs = new CodonFromUniqueFrequenciesSet(&CA, new FullNucleotideFrequenciesSet(CA.getNucleicAlphabet()), "F1X4", mgmtStopFreq);
+  else if (option == F3X4)
+  {
+    vector<FrequenciesSet*> v_AFS(3);
+    v_AFS[0] = new FullNucleotideFrequenciesSet(CA.getNucleicAlphabet());
+    v_AFS[1] = new FullNucleotideFrequenciesSet(CA.getNucleicAlphabet());
+    v_AFS[2] = new FullNucleotideFrequenciesSet(CA.getNucleicAlphabet());
+    codonFreqs = new CodonFromIndependentFrequenciesSet(&CA, v_AFS, "F3X4", mgmtStopFreq);
+  }
+  else if (option == F61)
+    codonFreqs = new FullCodonFrequenciesSet(&CA, "F61");
+  else
+    throw Exception("FrequenciesSet::getFrequencySetForCodons(). Unvalid codon frequency set argument.");
+
+  return codonFreqs;
+}
+
+/******************************************************************************/
+
+const short CodonFrequenciesSet::F0   = 0;
+const short CodonFrequenciesSet::F1X4 = 1;
+const short CodonFrequenciesSet::F3X4 = 2;
+const short CodonFrequenciesSet::F61  = 3;
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/FrequenciesSet/CodonFrequenciesSet.h b/src/Bpp/Phyl/Model/FrequenciesSet/CodonFrequenciesSet.h
new file mode 100644
index 0000000..fc44808
--- /dev/null
+++ b/src/Bpp/Phyl/Model/FrequenciesSet/CodonFrequenciesSet.h
@@ -0,0 +1,390 @@
+//
+// File: CodonFrequenciesSet.h
+// Created by: laurent Gueguen
+// Created on: lundi 2 avril 2012, à 14h 03
+//
+
+/*
+  Copyright or (c) or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _CODONFREQUENCIESSET_H_
+#define _CODONFREQUENCIESSET_H_
+
+#include "WordFrequenciesSet.h"
+#include "FrequenciesSet.h"
+#include "ProteinFrequenciesSet.h"
+
+#include <Bpp/Seq/Alphabet/CodonAlphabet.h>
+#include <Bpp/Seq/GeneticCode/GeneticCode.h>
+#include <Bpp/Numeric/Prob/Simplex.h>
+
+namespace bpp
+{
+
+  /**
+   * @brief Parametrize a set of state frequencies for codons.
+   */
+  class CodonFrequenciesSet :
+    public virtual FrequenciesSet
+  {
+  public:
+#ifndef NO_VIRTUAL_COV
+    CodonFrequenciesSet* clone() const = 0;
+    
+    const CodonAlphabet* getAlphabet() const = 0;
+#endif
+    
+  public:
+    /**
+     * @brief A helper function that provide frequencies set for codon models
+     * according to PAML option.
+     *
+     * @param option A code describing the option, one of F61, F1X4 or F3X4.
+     * @param CA the Codon Alphabet to use.
+     * @param mgmtStopFreq the optional way the frequencies assigned
+     * to the stop codons are redistributed to the other codons, with
+     * F1X4 and F3X4 options. The available values are:
+     *  - uniform : each stop frequency is distributed evenly
+     *  - linear : each stop frequency is distributed to the neighbour
+     *     codons (ie 1 substitution away), in proportion to each
+     *     target codon frequency.
+     *  - quadratic (default): each stop frequency is distributed to the
+     *     neighbour codons (ie 1 substitution away), in proportion to
+     *     the square of each target codon frequency.
+     *
+     */
+    
+    static FrequenciesSet* getFrequenciesSetForCodons(short option, const CodonAlphabet& CA, const std::string& mgmtStopFreq = "quadratic");
+    
+    static const short F0;
+    static const short F1X4;
+    static const short F3X4;
+    static const short F61;
+    
+    
+  };
+
+
+  /**
+   * @brief A generic FrequenciesSet for Full Codon alphabets.
+   *
+   * It is very similar to FullFrequencySet, but only the non-stop codon
+   *   frequencies are parameterized.
+   */
+  class FullCodonFrequenciesSet :
+    public virtual CodonFrequenciesSet,
+    public AbstractFrequenciesSet
+  {
+  public:
+    /**
+     * @brief Construction with uniform frequencies on the letters of
+     * the alphabet. The stop codon frequencies are null.
+     */
+    FullCodonFrequenciesSet(const CodonAlphabet* alphabet, bool allowNullFreqs = false, const std::string& name = "Full");
+    FullCodonFrequenciesSet(const CodonAlphabet* alphabet, const std::vector<double>& initFreqs, bool allowNullFreqs = false, const std::string& name = "Full");
+
+#ifndef NO_VIRTUAL_COV
+    FullCodonFrequenciesSet*
+#else
+    Clonable*
+#endif
+    clone() const { return new FullCodonFrequenciesSet(*this); }
+
+  public:
+    /**
+     * @brief the given frequencies are normalized such thaat the sum of
+     * the frequencies on the non-stop codons equals 1.
+     *
+     */
+    void setFrequencies(const std::vector<double>& frequencies);
+
+#ifndef NO_VIRTUAL_COV
+    const CodonAlphabet* getAlphabet() const
+    {
+      return dynamic_cast<const CodonAlphabet*>(AbstractFrequenciesSet::getAlphabet());
+    }
+#endif
+
+  protected:
+    void fireParameterChanged(const ParameterList& parameters);
+  };
+
+
+  /**
+   * @brief FrequenciesSet useful for homogeneous and stationary models, codon implementation
+   *
+   * This set contains no parameter.
+   */
+  class FixedCodonFrequenciesSet :
+    public virtual CodonFrequenciesSet,
+    public AbstractFrequenciesSet
+  {
+  public:
+    FixedCodonFrequenciesSet(const CodonAlphabet* alphabet, const std::vector<double>& initFreqs, const std::string& name = "Fixed");
+
+    /**
+     * @brief Construction with uniform frequencies on the letters of
+     * the alphabet. The stop codon frequencies are null.
+     */
+    FixedCodonFrequenciesSet(const CodonAlphabet* alphabet, const std::string& name = "Fixed");
+
+#ifndef NO_VIRTUAL_COV
+    FixedCodonFrequenciesSet*
+#else
+    Clonable*
+#endif
+    clone() const { return new FixedCodonFrequenciesSet(*this); }
+
+  public:
+#ifndef NO_VIRTUAL_COV
+    const CodonAlphabet* getAlphabet() const
+    {
+      return dynamic_cast<const CodonAlphabet*>(AbstractFrequenciesSet::getAlphabet());
+    }
+#endif
+    /**
+     * @brief the given frequencies are normalized such thaat the sum of
+     * the frequencies on the non-stop codons equals 1.
+     *
+     */
+    void setFrequencies(const std::vector<double>& frequencies);
+
+  protected:
+    void fireParameterChanged(const ParameterList& parameters) {}
+  };
+
+  /**
+   * @brief FrequenciesSet integrating ProteinFrequenciesSet inside
+   * CodonFrequenciesSet. In this case, FrequencieSet defined inside
+   * each amino acid is parametrized as a FullFrequenciesSet. Hence
+   * there are 61-20=41 parameters in addition of the parameters of the
+   * ProteinFrequenciesSet.
+   *
+   *
+   */
+
+  class FullPerAACodonFrequenciesSet :
+    public virtual CodonFrequenciesSet,
+    public AbstractFrequenciesSet
+  {
+  
+  private:
+    const GeneticCode* pgc_;
+    ProteinFrequenciesSet* ppfs_;
+
+    /*
+     *@ brief vector of the simplexes, one for each AA
+     *
+     */
+  
+    std::vector<Simplex> vS_;
+
+    void updateFrequencies();
+  
+  public:
+  
+    FullPerAACodonFrequenciesSet(const GeneticCode* gencode, const ProteinFrequenciesSet* ppfs);
+
+    /**
+     * @brief Construction with fixed uniform frequencies on the amino acids.
+     * The stop codon frequencies are null.
+     */
+  
+    FullPerAACodonFrequenciesSet(const GeneticCode* gencode);
+
+    FullPerAACodonFrequenciesSet(const FullPerAACodonFrequenciesSet&);
+
+    FullPerAACodonFrequenciesSet& operator=(const FullPerAACodonFrequenciesSet&);
+
+    ~FullPerAACodonFrequenciesSet();
+ 
+#ifndef NO_VIRTUAL_COV
+    FullPerAACodonFrequenciesSet*
+#else
+    Clonable*
+#endif
+    clone() const { return new FullPerAACodonFrequenciesSet(*this); }
+
+  public:
+#ifndef NO_VIRTUAL_COV
+    const CodonAlphabet* getAlphabet() const
+    {
+      return dynamic_cast<const CodonAlphabet*>(AbstractFrequenciesSet::getAlphabet());
+    }
+#endif
+    /**
+     * @brief the given frequencies are normalized such thaat the sum of
+     * the frequencies on the non-stop codons equals 1.
+     *
+     */
+    void setFrequencies(const std::vector<double>& frequencies);
+
+    void setNamespace(const std::string& prefix);
+
+    const ProteinFrequenciesSet* getProteinFrequenciesSet() const
+    {
+      return ppfs_;
+    }
+    
+  protected:
+    void fireParameterChanged(const ParameterList& parameters);
+  };
+
+
+  /**
+   * @brief the Frequencies in codons are the product of Independent
+   * Frequencies in letters with the frequencies of stop codons set to
+   * zero.
+   *
+   *
+   * @author Laurent Guéguen
+   */
+
+  class CodonFromIndependentFrequenciesSet :
+    public virtual CodonFrequenciesSet,
+    public WordFromIndependentFrequenciesSet
+  {
+  private:
+
+    // a map associating stop codons numbers with numbers of neighbour non-stop codons
+    std::map<int, Vint> mStopNeigh_;
+
+    unsigned short mgmtStopFreq_;
+    
+  public:
+    /**
+     * @brief Constructor from a CodonAlphabet* and a vector of different FrequenciesSet*.
+     * Throws an Exception if their lengths do not match.
+     *
+     * @param pCA a pointer to the CodonAlphabet
+     * @param freqvector a vector of pointers to the phase specific FrequenciesSets
+     * @param name the optional name of the FrequenciesSet (default codon)
+     * @param mgmtStopFreq the optional way the frequencies assigned to the
+     * stop codons are redistributed to the other codons. The
+     * available values are:
+     *  - uniform : each stop frequency is distributed evenly
+     *  - linear : each stop frequency is distributed to the neighbour
+     *     codons (ie 1 substitution away), in proportion to each
+     *     target codon frequency.
+     *  - quadratic (default): each stop frequency is distributed to the
+     *     neighbour codons (ie 1 substitution away), in proportion to
+     *     the square of each target codon frequency.
+     *
+     */
+    CodonFromIndependentFrequenciesSet(const CodonAlphabet* pCA, const std::vector<FrequenciesSet*>& freqvector, const std::string& name = "Codon", const std::string& mgmtStopFreq = "quadratic");
+  
+    CodonFromIndependentFrequenciesSet(const CodonFromIndependentFrequenciesSet& iwfs);
+
+    ~CodonFromIndependentFrequenciesSet(){};
+  
+    CodonFromIndependentFrequenciesSet& operator=(const CodonFromIndependentFrequenciesSet& iwfs);
+  
+    CodonFromIndependentFrequenciesSet* clone() const { return new CodonFromIndependentFrequenciesSet(*this); }
+
+    const CodonAlphabet* getAlphabet() const;
+  
+    /*
+     *@ brief Update the frequencies given the parameters.
+     *
+     */
+
+    void updateFrequencies();
+  };
+
+
+  /**
+   * @brief the Frequencies in codons are the product of the frequencies
+   * for a unique FrequenciesSet in letters, with the frequencies of
+   * stop codons set to zero.
+   *
+   * @author Laurent Guéguen
+   */
+
+  class CodonFromUniqueFrequenciesSet :
+    public virtual CodonFrequenciesSet,
+    public WordFromUniqueFrequenciesSet
+  {
+  private:
+
+    // a map associating stop codons numbers with numbers of neighbour non-stop codons
+    std::map<int, Vint> mStopNeigh_;
+
+    unsigned short mgmtStopFreq_;
+    
+  public:
+    /**
+     * @brief Constructor from a CodonAlphabet* and a FrequenciesSet*
+     *  repeated three times.
+     *
+     * @param pCA a pointer to the CodonAlphabet
+     * @param pfreq a pointer to the nucleotidic FrequenciesSet
+     * @param name the optional name of the FrequenciesSet (default codon)
+     * @param mgmtStopFreq the optional way the frequencies assigned to the
+     * stop codons are redistributed to the other codons. The
+     * available values are:
+     *  - uniform : each stop frequency is distributed evenly
+     *  - linear : each stop frequency is distributed to the neighbour
+     *      codons (ie 1 substitution away), in proportion to each
+     *      target codon frequency.
+     *  - quadratic (default): each stop frequency is distributed to the
+     *      neighbour codons (ie 1 substitution away), in proportion to
+     *      the square of each target codon frequency.
+     *
+     */
+
+    CodonFromUniqueFrequenciesSet(const CodonAlphabet* pCA, FrequenciesSet* pfreq, const std::string& name = "Codon", const std::string& mgmtStopFreq = "quadratic");
+  
+    CodonFromUniqueFrequenciesSet(const CodonFromUniqueFrequenciesSet& iwfs);
+  
+    ~CodonFromUniqueFrequenciesSet(){};
+  
+    CodonFromUniqueFrequenciesSet& operator=(const CodonFromUniqueFrequenciesSet& iwfs);
+  
+    CodonFromUniqueFrequenciesSet* clone() const { return new CodonFromUniqueFrequenciesSet(*this); }
+  
+    const CodonAlphabet* getAlphabet() const;
+
+    /*
+     *@ brief Update the frequencies given the parameters.
+     *
+     */
+
+    void updateFrequencies();
+  };
+
+
+} // end of namespace bpp.
+
+#endif // _CODONFREQUENCIESSET_H_
+
+
diff --git a/src/Bpp/Phyl/Model/FrequenciesSet/FrequenciesSet.cpp b/src/Bpp/Phyl/Model/FrequenciesSet/FrequenciesSet.cpp
new file mode 100644
index 0000000..57b8d69
--- /dev/null
+++ b/src/Bpp/Phyl/Model/FrequenciesSet/FrequenciesSet.cpp
@@ -0,0 +1,205 @@
+//
+// File: FrequenciesSet.cpp
+// Created by: Bastien Boussau
+//             Julien Dutheil
+// Created on: Tue Aug 21 2007
+//
+
+/*
+   Copyright or (c) or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "FrequenciesSet.h"
+
+#include <Bpp/Numeric/NumConstants.h>
+#include <Bpp/Numeric/Prob/Simplex.h>
+
+using namespace bpp;
+
+#include <cmath>
+using namespace std;
+
+IntervalConstraint FrequenciesSet::FREQUENCE_CONSTRAINT_MILLI(NumConstants::MILLI(), 1 - NumConstants::MILLI(), false, false);
+IntervalConstraint FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL(NumConstants::SMALL(), 1 - NumConstants::SMALL(), false, false);
+
+// ///////////////////////////////////////
+// AbstractFrequenciesSet
+
+
+void AbstractFrequenciesSet::setFrequenciesFromMap(const map<int, double>& frequencies)
+{
+  size_t s = getAlphabet()->getSize();
+  vector<double> freq(s);
+  double x = 0;
+  for (size_t i = 0; i < s; i++)
+  {
+    map<int, double>::const_iterator it = frequencies.find(static_cast<int>(i));
+    if (it != frequencies.end())
+      freq[i] = it->second;
+    else
+      freq[i] = 0;
+    x += freq[i];
+  }
+  for (size_t i = 0; i < s; i++)
+  {
+    freq[i] /= x;
+  }
+  setFrequencies(freq);
+}
+
+// ////////////////////////////
+// FullFrequenciesSet
+
+FullFrequenciesSet::FullFrequenciesSet(const Alphabet* alphabet, bool allowNullFreqs, const string& name) :
+  AbstractFrequenciesSet(alphabet->getSize(), alphabet, "Full.", name)
+{
+  size_t size = alphabet->getSize();
+
+  for (size_t i = 0; i < alphabet->getSize() - 1; i++)
+  {
+    addParameter_(new Parameter(
+      "Full.theta" + TextTools::toString(i + 1),
+      1. / static_cast<double>(size - i),
+      allowNullFreqs ?
+      &Parameter::PROP_CONSTRAINT_IN :
+      &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+    getFreq_(i) = 1. / static_cast<double>(size);
+  }
+  size_t i = alphabet->getSize() - 1;
+  getFreq_(i) = 1. / static_cast<double>(size);
+}
+
+FullFrequenciesSet::FullFrequenciesSet(const Alphabet* alphabet, const vector<double>& initFreqs, bool allowNullFreqs, const string& name) :
+  AbstractFrequenciesSet(alphabet->getSize(), alphabet, "Full.", name)
+{
+  if (initFreqs.size() != alphabet->getSize())
+    throw Exception("FullFrequenciesSet(constructor). There must be " + TextTools::toString(alphabet->getSize()) + " frequencies.");
+  double sum = VectorTools::sum(initFreqs);
+  if (fabs(1. - sum) > NumConstants::SMALL())
+  {
+    throw Exception("Frequencies must equal 1 (sum = " + TextTools::toString(sum) + ").");
+  }
+
+  double y = 1;
+  for (size_t i = 0; i < alphabet->getSize() - 1; i++)
+  {
+    addParameter_(new Parameter(
+      "Full.theta" + TextTools::toString(i + 1),
+      initFreqs[i] / y,
+      allowNullFreqs ?
+      &Parameter::PROP_CONSTRAINT_IN :
+      &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+    getFreq_(i) = initFreqs[i];
+    y -= initFreqs[i];
+  }
+  size_t i = alphabet->getSize() - 1;
+  getFreq_(i) = initFreqs[i];
+}
+
+void FullFrequenciesSet::setFrequencies(const vector<double>& frequencies) 
+{
+  const Alphabet* alphabet = getAlphabet();
+  if (frequencies.size() != getNumberOfFrequencies())
+    throw DimensionException("FullFrequenciesSet::setFrequencies. Invalid number of frequencies.", frequencies.size(), getNumberOfFrequencies());
+
+  if (fabs(1. - VectorTools::sum(frequencies)) >= NumConstants::SMALL())
+    throw Exception("FullFrequenciesSet::setFrequencies. Frequencies do not sum to 1 : " + TextTools::toString(VectorTools::sum(frequencies)));
+
+  setFrequencies_(frequencies);
+
+  double y = 1;
+  for (size_t i = 0; i < alphabet->getSize() - 1; i++)
+  {
+    getParameter_("theta" + TextTools::toString(i + 1)).setValue(frequencies[i] / y);
+    y -= frequencies[i];
+  }
+}
+
+void FullFrequenciesSet::fireParameterChanged(const ParameterList& parameters)
+{
+  const Alphabet* alphabet = getAlphabet();
+  double y = 1;
+  size_t i;
+  for (i = 0; i < alphabet->getSize() - 1; i++)
+  {
+    getFreq_(i) = getParameter_("theta" + TextTools::toString(i + 1)).getValue() * y;
+    y *= 1 - getParameter_("theta" + TextTools::toString(i + 1)).getValue();
+  }
+
+  i = alphabet->getSize() - 1;
+  getFreq_(i) = y;
+}
+
+
+// ///////////////////////////////////////////
+// / FixedFrequenciesSet
+
+FixedFrequenciesSet::FixedFrequenciesSet(const Alphabet* alphabet, const vector<double>& initFreqs, const string& name) :
+  AbstractFrequenciesSet(initFreqs.size(), alphabet, "Fixed.", name)
+{
+  setFrequencies(initFreqs);
+}
+
+FixedFrequenciesSet::FixedFrequenciesSet(const Alphabet* alphabet, size_t nFreqs, const string& name) :
+  AbstractFrequenciesSet(nFreqs, alphabet, "Fixed.", name)
+{
+  size_t size = nFreqs;
+  for (size_t i = 0; i < nFreqs; ++i)
+  {
+    getFreq_(i) = 1. / static_cast<double>(size);
+  }
+}
+
+void FixedFrequenciesSet::setFrequencies(const vector<double>& frequencies) 
+{
+  if (frequencies.size() != getNumberOfFrequencies())
+    throw DimensionException("FixedFrequenciesSet::setFrequencies", frequencies.size(), getNumberOfFrequencies());
+  double sum = 0.0;
+  for (size_t i = 0; i < frequencies.size(); i++)
+  {
+    sum += frequencies[i];
+  }
+  if (fabs(1. - sum) > 0.00001)
+    throw Exception("FixedFrequenciesSet::setFrequencies. Frequencies sum must equal 1 (sum = " + TextTools::toString(sum) + ").");
+  setFrequencies_(frequencies);
+}
+
+MarkovModulatedFrequenciesSet::MarkovModulatedFrequenciesSet(FrequenciesSet* freqSet, const std::vector<double>& rateFreqs) :
+  AbstractFrequenciesSet(freqSet->getAlphabet()->getSize() * rateFreqs.size(), freqSet->getAlphabet(), "MarkovModulated.", "MarkovModulated." + freqSet->getName()),
+  freqSet_(freqSet),
+  rateFreqs_(rateFreqs)
+{
+  freqSet_->setNamespace(std::string("MarkovModulated.") + freqSet_->getNamespace());
+  addParameters_(freqSet_->getParameters());
+  setFrequencies_(VectorTools::kroneckerMult(rateFreqs, freqSet_->getFrequencies()));
+}
+
diff --git a/src/Bpp/Phyl/Model/FrequenciesSet/FrequenciesSet.h b/src/Bpp/Phyl/Model/FrequenciesSet/FrequenciesSet.h
new file mode 100644
index 0000000..f43de46
--- /dev/null
+++ b/src/Bpp/Phyl/Model/FrequenciesSet/FrequenciesSet.h
@@ -0,0 +1,294 @@
+//
+// File: FrequenciesSet.h
+// Created by: Bastien Boussau
+//             Julien Dutheil
+// Created on: Tue Aug 21 2007
+//
+
+/*
+   Copyright or (c) or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _FREQUENCIESSET_H_
+#define _FREQUENCIESSET_H_
+
+#include <Bpp/Numeric/Parametrizable.h>
+#include <Bpp/Numeric/AbstractParametrizable.h>
+#include <Bpp/Seq/Alphabet/Alphabet.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+namespace bpp
+{
+/**
+ * @brief Parametrize a set of state frequencies.
+ */
+class FrequenciesSet :
+  public virtual Parametrizable
+{
+public:
+#ifndef NO_VIRTUAL_COV
+  FrequenciesSet* clone() const = 0;
+#endif
+
+public:
+  /**
+   * @return The alphabet associated to this set.
+   */
+  virtual const Alphabet* getAlphabet() const = 0;
+
+  /**
+   * @return The frequencies values of the set.
+   */
+  virtual const std::vector<double>& getFrequencies() const = 0;
+
+  /**
+   * @brief Set the parameters in order to match a given set of frequencies.
+   *
+   * @param frequencies The set of frequencies to match.
+   * @throw DimensionException If the number of frequencies does not match the size of the alphabet.
+   * @throw Exception If the frequencies do not sum to 1.
+   */
+  virtual void setFrequencies(const std::vector<double>& frequencies) = 0;
+
+  /**
+   * @brief Set the Frequencies from the one of the map which keys
+   *  match with a letter of the Alphabet.
+   *  The frequencies are normalized so that the matching values sum 1.
+   *
+   * @param frequencies The set of frequencies to match.
+   */
+  virtual void setFrequenciesFromMap(const std::map<int, double>& frequencies) = 0;
+
+  virtual std::string getName() const = 0;
+
+  /**
+   * @return The number of frequencies in the set. In most cases this will correspond to the size of the alphabet,
+   * but it needs not be.
+   */
+  virtual size_t getNumberOfFrequencies() const = 0;
+
+public:
+  static IntervalConstraint FREQUENCE_CONSTRAINT_SMALL;
+  static IntervalConstraint FREQUENCE_CONSTRAINT_MILLI;
+};
+
+/**
+ * @brief Basic implementation of the FrequenciesSet interface.
+ */
+
+class AbstractFrequenciesSet :
+  public virtual FrequenciesSet,
+  public AbstractParametrizable
+{
+private:
+  const Alphabet* alphabet_;
+  std::vector<double> freq_;
+  std::string name_;
+
+public:
+  AbstractFrequenciesSet(size_t n, const Alphabet* alphabet, const std::string& prefix, const std::string& name) :
+    AbstractParametrizable(prefix),
+    alphabet_(alphabet),
+    freq_(n),
+    name_(name)
+  {}
+
+#ifndef NO_VIRTUAL_COV
+  AbstractFrequenciesSet*
+#else
+  Clonable*
+#endif
+  clone() const = 0;
+
+  AbstractFrequenciesSet(const AbstractFrequenciesSet& af) :
+    AbstractParametrizable(af),
+    alphabet_(af.alphabet_),
+    freq_(af.freq_),
+    name_(af.name_)
+  {}
+
+  AbstractFrequenciesSet& operator=(const AbstractFrequenciesSet& af)
+  {
+    AbstractParametrizable::operator=(af);
+    alphabet_ = af.alphabet_;
+    freq_ = af.freq_;
+    name_ = af.name_;
+    return *this;
+  }
+
+public:
+  const Alphabet* getAlphabet() const { return alphabet_; }
+
+  const std::vector<double>& getFrequencies() const { return freq_; }
+
+  void setFrequenciesFromMap(const std::map<int, double>& frequencies);
+
+  size_t getNumberOfFrequencies() const { return freq_.size(); }
+
+  std::string getName() const { return(name_); }
+
+protected:
+  std::vector<double>& getFrequencies_() { return freq_; }
+  double& getFreq_(size_t i) { return freq_[i]; }
+  const double& getFreq_(size_t i) const { return freq_[i]; }
+  void setFrequencies_(const std::vector<double>& frequencies) { freq_ = frequencies; }
+};
+
+/**
+ * @brief A generic FrequenciesSet allowing for the estimation of all frequencies.
+ *
+ * The FrequenciesSet has hence n-1 parameters, where n is the size of the input alphabet.
+ */
+class FullFrequenciesSet :
+  public AbstractFrequenciesSet
+{
+public:
+  /**
+   * @brief Construction with uniform frequencies on the letters of
+   * the alphabet.
+   */
+  FullFrequenciesSet(const Alphabet* alphabet, bool allowNullFreqs = false, const std::string& name = "Full");
+  FullFrequenciesSet(const Alphabet* alphabet, const std::vector<double>& initFreqs, bool allowNullFreqs = false, const std::string& name = "Full");
+
+  FullFrequenciesSet* clone() const { return new FullFrequenciesSet(*this); }
+
+public:
+  void setFrequencies(const std::vector<double>& frequencies);
+
+protected:
+  void fireParameterChanged(const ParameterList& parameters);
+};
+
+/**
+ * @brief FrequenciesSet to be used with a Markov-modulated substitution model.
+ *
+ * This implementation uses one parameter per character state frequency.
+ * The rate states are assumed to be fixed and are passed as an argument to the constructor, together with a 'regular'
+ * FrequenciesSet. The number of parameters hence do not depends on the number of rates used.
+ */
+class MarkovModulatedFrequenciesSet :
+  public AbstractFrequenciesSet
+{
+private:
+  FrequenciesSet* freqSet_;
+  std::vector<double> rateFreqs_;
+
+public:
+  MarkovModulatedFrequenciesSet(FrequenciesSet* freqSet, const std::vector<double>& rateFreqs);
+
+  MarkovModulatedFrequenciesSet(const MarkovModulatedFrequenciesSet& mmfs) :
+    AbstractFrequenciesSet(mmfs),
+    freqSet_(mmfs.freqSet_->clone()),
+    rateFreqs_(mmfs.rateFreqs_)
+  {}
+
+  MarkovModulatedFrequenciesSet& operator=(const MarkovModulatedFrequenciesSet& mmfs)
+  {
+    AbstractFrequenciesSet::operator=(mmfs);
+    freqSet_ = mmfs.freqSet_->clone();
+    rateFreqs_ = mmfs.rateFreqs_;
+    return *this;
+  }
+
+  MarkovModulatedFrequenciesSet* clone() const { return new MarkovModulatedFrequenciesSet(*this); }
+
+  virtual ~MarkovModulatedFrequenciesSet() { delete freqSet_; }
+
+public:
+  void setFrequencies(const std::vector<double>& frequencies)
+  {
+    // Just forward this method to the sequence state frequencies set. This may change in the future...
+    freqSet_->setFrequencies(frequencies);
+  }
+
+  void fireParameterChanged(const ParameterList& pl)
+  {
+   freqSet_->matchParametersValues(pl);
+    setFrequencies_(VectorTools::kroneckerMult(rateFreqs_, freqSet_->getFrequencies()));
+  }
+
+  const FrequenciesSet& getStatesFrequenciesSet() const { return *freqSet_; }
+
+  void setNamespace(const std::string& prefix)
+  {
+   AbstractFrequenciesSet::setNamespace(prefix);
+   freqSet_->setNamespace(prefix + freqSet_->getNamespace());
+  }
+
+};
+
+
+/**
+ * @brief FrequenciesSet useful for homogeneous and stationary models.
+ *
+ * This set contains no parameter.
+ */
+class FixedFrequenciesSet :
+  public AbstractFrequenciesSet
+{
+public:
+
+  /**
+   * @brief Construction with uniform frequencies on the letters of
+   * the alphabet.
+   *
+   * @param alphabet The alphabet for wich this frequencies set should be build.
+   * @param initFreqs The frequencies to use. The vector will determine the number of frequencies.
+   * @param name The name of the set.
+   */
+  FixedFrequenciesSet(const Alphabet* alphabet, const std::vector<double>& initFreqs, const std::string& name = "Fixed");
+
+  /**
+   * @brief Construction with uniform frequencies on the letters of
+   * the alphabet.
+   *
+   * @param alphabet The alphabet for wich this frequencies set should be build.
+   * @param nFreqs The number of frequencies.
+   * @param name The name of the set.
+   */
+  FixedFrequenciesSet(const Alphabet* alphabet, size_t nFreqs, const std::string& name = "Fixed");
+
+  FixedFrequenciesSet* clone() const { return new FixedFrequenciesSet(*this); }
+
+public:
+  void setFrequencies(const std::vector<double>& frequencies);
+
+protected:
+  void fireParameterChanged(const ParameterList& parameters) {}
+};
+
+ 
+} // end of namespace bpp.
+
+#endif // _FREQUENCIESSET_H_
+
+
diff --git a/src/Bpp/Phyl/Model/FrequenciesSet/MvaFrequenciesSet.cpp b/src/Bpp/Phyl/Model/FrequenciesSet/MvaFrequenciesSet.cpp
new file mode 100644
index 0000000..bcbec05
--- /dev/null
+++ b/src/Bpp/Phyl/Model/FrequenciesSet/MvaFrequenciesSet.cpp
@@ -0,0 +1,159 @@
+//
+// File: MvaFrequenciesSet.cpp
+// Created by: Mathieu Groussin
+// Created on: Sat Jan 12 2013
+//
+
+/*
+   Copyright or (c) or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+#include "MvaFrequenciesSet.h"
+
+// #include "../Protein.all"
+
+// #include <Bpp/Numeric/NumConstants.h>
+// #include <Bpp/Numeric/VectorTools.h>
+// #include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+using namespace bpp;
+
+#include <cmath>
+using namespace std;
+
+MvaFrequenciesSet::MvaFrequenciesSet(const ProteicAlphabet* alpha) :
+  AbstractFrequenciesSet(20, alpha, "MVA.", "MVAprotein"),
+  tPpalAxes_(),
+  rowCoords_(),
+  nbrOfAxes_(0),
+  model_(),
+  columnWeights_(),
+  paramValues_()
+{}
+
+void MvaFrequenciesSet::initSet(CoalaCore* coala)
+{
+  setNbrOfAxes(coala->getNbrOfAxes());
+  setTransposeMatrixOfPpalAxes(coala->getTppalAxesMatrix());
+  setMatrixOfRowCoords(coala->getRowCoordinates());
+  setVectorOfColumnWeights(coala->getColumnWeights());
+  defineParameters();
+  updateFrequencies();
+}
+
+void MvaFrequenciesSet::defineParameters()
+{
+  for (unsigned int i = 0; i < nbrOfAxes_; i++)
+  {
+    const vector<double> rCoords = rowCoords_.col(i);
+    double maxCoord = VectorTools::max(rCoords);
+    double minCoord = VectorTools::min(rCoords);
+    double sd = VectorTools::sd<double, double>(rCoords);
+    IntervalConstraint* constraint = new IntervalConstraint(minCoord - sd, maxCoord + sd, true, true);
+    if (paramValues_.find("RootAxPos" + TextTools::toString(i)) != paramValues_.end())
+      addParameter_(new Parameter("MVA.RootAxPos" + TextTools::toString(i), TextTools::toDouble(paramValues_["RootAxPos" + TextTools::toString(i)].substr(0, 8)), constraint));
+    else
+      addParameter_(new Parameter("MVA.RootAxPos" + TextTools::toString(i), 0., constraint));
+  }
+}
+
+void MvaFrequenciesSet::fireParameterChanged(const ParameterList& parameters)
+{
+  updateFrequencies();
+}
+
+void MvaFrequenciesSet::updateFrequencies() throw (Exception)
+{
+  if (nbrOfAxes_ == 0)
+    throw Exception("The number of axes kept by the MVA analysis was not set. You should initialize it with the setNbrOfAxes function");
+  vector<double> positions;
+
+  for (unsigned int i = 0; i < nbrOfAxes_; i++)
+  {
+    positions.push_back(getParameter("RootAxPos" + TextTools::toString(i)).getValue());
+  }
+
+  vector<double> tmpFreqs(20, 0.0);
+  vector<double> freqs(20, 0.0);
+
+  computeReverseCOA(positions, tmpFreqs);
+  computeCoordsFirstSpaceCOA(tmpFreqs, freqs);
+
+  setFrequencies_(freqs);
+
+  bool norm = false;
+  for (unsigned int i = 0; i < 20; i++)
+  {
+    if (getFreq_(i) < 0.001)
+    {
+      norm = true;
+      getFreq_(i) = 0.001;
+    }
+    if (getFreq_(i) > 0.5)
+    {
+      norm = true;
+      getFreq_(i) = 0.5;
+    }
+  }
+  if (norm == true)
+  {
+    double s = VectorTools::sum(getFrequencies());
+    for (int i = 0; i < 20; i++)
+    {
+      getFreq_(i) = getFreq_(i) / s;
+    }
+  }
+}
+
+void MvaFrequenciesSet::setFrequencies(const vector<double>& frequencies) throw (DimensionException, Exception)
+{}
+
+void MvaFrequenciesSet::computeReverseCOA(const std::vector<double>& positions, std::vector<double>& tmpFreqs) throw (Exception)
+{
+  for (unsigned int i = 0; i < 20; i++)
+  {
+    for (unsigned int j = 0; j < nbrOfAxes_; j++)
+    {
+      tmpFreqs[i] = tmpFreqs[i] + tPpalAxes_(j, i) * positions[j];
+    }
+  }
+}
+
+void MvaFrequenciesSet::computeCoordsFirstSpaceCOA(std::vector<double>& tmpFreqs, std::vector<double>& freqs) throw (Exception)
+{
+  if (freqs.size() != tmpFreqs.size())
+    throw Exception("MvaFrequenciesSet::computeCoordsFirstSpaceCOA : error in the size of the vectors");
+  // The vector of amino acid frequencies is calculated from the original column weights
+  for (unsigned int i = 0; i < tmpFreqs.size(); i++)
+  {
+    freqs[i] = (tmpFreqs[i] + 1) * columnWeights_[i];
+  }
+}
diff --git a/src/Bpp/Phyl/Model/FrequenciesSet/MvaFrequenciesSet.h b/src/Bpp/Phyl/Model/FrequenciesSet/MvaFrequenciesSet.h
new file mode 100644
index 0000000..5bc364a
--- /dev/null
+++ b/src/Bpp/Phyl/Model/FrequenciesSet/MvaFrequenciesSet.h
@@ -0,0 +1,124 @@
+//
+// File: MvaFrequenciesSet.h
+// Created by: Mathieu Groussin
+// Created on: Sat Jan 12 2013
+//
+
+/*
+   Copyright or (c) or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _MVAFREQUENCIESSET_H_
+#define _MVAFREQUENCIESSET_H_
+
+#include "ProteinFrequenciesSet.h"
+#include "../Protein/Coala.h"
+
+namespace bpp
+{
+
+/**
+ * @brief A frequencies set used to estimate frequencies at the root with the COaLA model.
+ * Frequencies at the root are optimized in the same way than the equlibrium frequencies on branches.
+ * Hyperparameters are used, which represent positions along the principal axes obtained from a preliminary Correspondence Analysis.
+ * From the optimized positions, the 20 frequencies are calculated.
+ * @author Mathieu Groussin
+ */	
+	
+class MvaFrequenciesSet :
+  public virtual ProteinFrequenciesSet,
+  public AbstractFrequenciesSet
+{
+public:
+  /**
+   * @brief Constructor 
+   */
+	MvaFrequenciesSet(const ProteicAlphabet* alpha);
+	
+#ifndef NO_VIRTUAL_COV
+	MvaFrequenciesSet*
+#else
+	Clonable*
+#endif
+	clone() const { return new MvaFrequenciesSet(*this); }
+	
+	MvaFrequenciesSet& operator=(const MvaFrequenciesSet& mfs)
+	{
+		//			AbstractParametrizable::operator=(af);
+		AbstractFrequenciesSet::operator=(mfs);
+		tPpalAxes_ = mfs.tPpalAxes_;
+		rowCoords_ = mfs.rowCoords_;
+		nbrOfAxes_ = mfs.nbrOfAxes_;
+		model_ = mfs.model_;
+		columnWeights_ = mfs.columnWeights_;
+		paramValues_ = mfs.paramValues_;
+		return *this;
+	}
+	
+protected:
+	RowMatrix<double> tPpalAxes_;
+	RowMatrix<double> rowCoords_;
+	size_t nbrOfAxes_;
+	std::string model_;
+	std::vector<double> columnWeights_;
+	std::map<std::string,std::string> paramValues_;
+	
+public:
+  const ProteicAlphabet* getAlphabet() const { return dynamic_cast<const ProteicAlphabet*>(AbstractFrequenciesSet::getAlphabet()); }
+
+	void setTransposeMatrixOfPpalAxes(const RowMatrix<double>& matrix) { tPpalAxes_ = matrix; }
+	void setMatrixOfRowCoords(const RowMatrix<double>& matrix) { rowCoords_ = matrix; }
+	void setNbrOfAxes(const size_t& nAxes) { nbrOfAxes_ = nAxes; }
+	void setModelName(const std::string& modelName) { model_ = modelName; }
+	void setVectorOfColumnWeights(const std::vector<double>& cw) { columnWeights_ = cw; }
+	void setParamValues(std::map<std::string, std::string>& valuesSettings) {paramValues_ = valuesSettings;}
+	
+	void setFrequencies(const std::vector<double>& frequencies) throw (DimensionException, Exception);
+	
+	void defineParameters();
+	void fireParameterChanged(const ParameterList& parameters);
+	void updateFrequencies() throw (Exception);
+	
+	void initSet(CoalaCore* coala);
+	
+	void computeReversePCA(const std::vector<double>& positions, std::vector<double>& tmpFreqs) throw (Exception);
+	void computeCoordsFirstSpacePCA(std::vector<double>& tmpFreqs, std::vector<double>& freqs) throw (Exception);
+	void computeReverseCOA(const std::vector<double>& positions, std::vector<double>& tmpFreqs) throw (Exception);
+	void computeCoordsFirstSpaceCOA(std::vector<double>& tmpFreqs, std::vector<double>& freqs) throw (Exception);	
+	
+};
+
+
+} // end of namespace bpp.
+
+#endif // _MVAFREQUENCIESSET_H_
+
diff --git a/src/Bpp/Phyl/Model/FrequenciesSet/NucleotideFrequenciesSet.cpp b/src/Bpp/Phyl/Model/FrequenciesSet/NucleotideFrequenciesSet.cpp
new file mode 100644
index 0000000..0faac35
--- /dev/null
+++ b/src/Bpp/Phyl/Model/FrequenciesSet/NucleotideFrequenciesSet.cpp
@@ -0,0 +1,161 @@
+//
+// File: NucleotideFrequenciesSet.cpp
+// Created by: Bastien Boussau
+//             Julien Dutheil
+// Created on: Tue Aug 21 2007
+//
+
+/*
+   Copyright or (c) or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "NucleotideFrequenciesSet.h"
+
+#include <Bpp/Numeric/NumConstants.h>
+
+using namespace bpp;
+
+#include <cmath>
+using namespace std;
+
+// ///////////////////////////////////////
+// FullNucleotideFrequenciesSet
+
+
+FullNucleotideFrequenciesSet::FullNucleotideFrequenciesSet(
+  const NucleicAlphabet* alphabet, bool allowNullFreqs,
+  const string& name) :
+  AbstractFrequenciesSet(4, alphabet, "Full.", name)
+{
+  addParameter_(new Parameter(
+    "Full.theta", 0.5,
+    allowNullFreqs ?
+    &Parameter::PROP_CONSTRAINT_IN :
+    &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+  addParameter_(new Parameter(
+    "Full.theta1", 0.5,
+    allowNullFreqs ?
+    &Parameter::PROP_CONSTRAINT_IN :
+    &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+  addParameter_(new Parameter("Full.theta2", 0.5,
+                    allowNullFreqs ?
+                    &Parameter::PROP_CONSTRAINT_IN :
+                    &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+  getFreq_(0) = getFreq_(1) = getFreq_(2) = getFreq_(3) = 0.25;
+}
+
+FullNucleotideFrequenciesSet::FullNucleotideFrequenciesSet(
+  const NucleicAlphabet* alphabet, double theta, double theta1, double theta2,
+  bool allowNullFreqs, const string& name) :
+  AbstractFrequenciesSet(4, alphabet, "Full.", name)
+{
+  addParameter_(new Parameter(
+    "Full.theta",
+    theta,
+    allowNullFreqs ?
+    &Parameter::PROP_CONSTRAINT_IN :
+    &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+  addParameter_(new Parameter(
+    "Full.theta1",
+    theta1,
+    allowNullFreqs ?
+    &Parameter::PROP_CONSTRAINT_IN :
+    &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+  addParameter_(new Parameter(
+    "Full.theta2",
+    theta2,
+    allowNullFreqs ?
+    &Parameter::PROP_CONSTRAINT_IN :
+    &Parameter::PROP_CONSTRAINT_EX));
+  getFreq_(0) = theta1 * (1. - theta);
+  getFreq_(1) = (1 - theta2) * theta;
+  getFreq_(2) = theta2 * theta;
+  getFreq_(3) = (1 - theta1) * (1. - theta);
+}
+
+void FullNucleotideFrequenciesSet::setFrequencies(const vector<double>& frequencies) 
+{
+  if (frequencies.size() != 4) throw DimensionException(" FullNucleotideFrequenciesSet::setFrequencies", frequencies.size(), 4);
+  double sum = 0.0;
+  for (unsigned int i = 0; i < 4; i++)
+  {
+    sum += frequencies[i];
+  }
+  if (fabs(1. - sum) > NumConstants::SMALL())
+    throw Exception("FullNucleotideFrequenciesSet::setFrequencies. Frequencies must equal 1 (sum = " + TextTools::toString(sum) + ").");
+  double theta = frequencies[1] + frequencies[2];
+  getParameter_(0).setValue(theta);
+  getParameter_(1).setValue(frequencies[0] / (1 - theta));
+  getParameter_(2).setValue(frequencies[2] / theta);
+
+  setFrequencies_(frequencies);
+}
+
+void FullNucleotideFrequenciesSet::fireParameterChanged(const ParameterList& parameters)
+{
+  double theta  = getParameter_(0).getValue();
+  double theta1 = getParameter_(1).getValue();
+  double theta2 = getParameter_(2).getValue();
+  getFreq_(0) = theta1 * (1. - theta);
+  getFreq_(1) = (1 - theta2) * theta;
+  getFreq_(2) = theta2 * theta;
+  getFreq_(3) = (1 - theta1) * (1. - theta);
+}
+
+// /////////////////////////////////////////
+// GCFrequenciesSet
+
+void GCFrequenciesSet::setFrequencies(const vector<double>& frequencies) 
+{
+  if (frequencies.size() != 4) throw DimensionException("GCFrequenciesSet::setFrequencies", frequencies.size(), 4);
+  double sum = 0.0;
+  for (unsigned int i = 0; i < 4; i++)
+  {
+    sum += frequencies[i];
+  }
+  if (fabs(1. - sum) > NumConstants::SMALL())
+    throw Exception("GCFrequenciesSet::setFrequencies. Frequencies must equal 1 (sum = " + TextTools::toString(sum) + ").");
+  double theta = frequencies[1] + frequencies[2];
+  // We set everything in one shot here:
+  getParameter_(0).setValue(theta);
+  getFreq_(0) = getFreq_(3) = (1. - theta) / 2.;
+  getFreq_(1) = getFreq_(2) = theta / 2.;
+}
+
+void GCFrequenciesSet::fireParameterChanged(const ParameterList& parameters)
+{
+  double theta = getParameter_(0).getValue();
+  getFreq_(0) = getFreq_(3) = (1. - theta) / 2.;
+  getFreq_(1) = getFreq_(2) = theta / 2.;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/FrequenciesSet/NucleotideFrequenciesSet.h b/src/Bpp/Phyl/Model/FrequenciesSet/NucleotideFrequenciesSet.h
new file mode 100644
index 0000000..59b3ee1
--- /dev/null
+++ b/src/Bpp/Phyl/Model/FrequenciesSet/NucleotideFrequenciesSet.h
@@ -0,0 +1,201 @@
+//
+// File: NucleotideFrequenciesSet.h
+// Created by: Bastien Boussau
+//             Julien Dutheil
+// Created on: Tue Aug 21 2007
+//
+
+/*
+   Copyright or (c) or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _NUCLEOTIDEFREQUENCIESSET_H_
+#define _NUCLEOTIDEFREQUENCIESSET_H_
+
+#include "FrequenciesSet.h"
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+
+namespace bpp
+{
+/**
+ * @brief Parametrize a set of state frequencies for nucleotides.
+ */
+class NucleotideFrequenciesSet :
+  public virtual FrequenciesSet
+{
+public:
+#ifndef NO_VIRTUAL_COV
+  NucleotideFrequenciesSet* clone() const = 0;
+
+  const NucleicAlphabet* getAlphabet() const = 0;
+#endif
+};
+
+/**
+ * @brief Nucleotide FrequenciesSet using only one parameter, the GC content.
+ */
+class GCFrequenciesSet :
+  public virtual NucleotideFrequenciesSet,
+  public AbstractFrequenciesSet
+{
+public:
+  GCFrequenciesSet(const NucleicAlphabet* alphabet) :
+    AbstractFrequenciesSet(4, alphabet, "GC.", "GC")
+  {
+    addParameter_(new Parameter("GC.theta", 0.5, &Parameter::PROP_CONSTRAINT_IN));
+    getFreq_(0) = getFreq_(1) = getFreq_(2) = getFreq_(3) = 0.25;
+  }
+
+  GCFrequenciesSet(const NucleicAlphabet* alphabet, double theta) :
+    AbstractFrequenciesSet(4, alphabet, "GC.", "GC")
+  {
+    addParameter_(new Parameter("GC.theta", theta, &Parameter::PROP_CONSTRAINT_IN));
+    getFreq_(0) = getFreq_(3) = (1. - theta) / 2.;
+    getFreq_(1) = getFreq_(2) = theta / 2.;
+  }
+
+#ifndef NO_VIRTUAL_COV
+  GCFrequenciesSet*
+#else
+  Clonable*
+#endif
+  clone() const { return new GCFrequenciesSet(*this); }
+
+public:
+#ifndef NO_VIRTUAL_COV
+  const NucleicAlphabet* getAlphabet() const
+  {
+    return dynamic_cast<const NucleicAlphabet*>(AbstractFrequenciesSet::getAlphabet());
+  }
+#endif
+
+  void setFrequencies(const std::vector<double>& frequencies);
+
+protected:
+  void fireParameterChanged(const ParameterList& parameters);
+};
+
+/**
+ * @brief Nucleotide FrequenciesSet using three independent parameters
+ * (theta, theta1, theta2) to modelize the four frequencies:
+ *
+ * \f[
+ * \begin{cases}
+ * \theta = \pi_C + \pi_G\\
+ * \theta_1 = \frac{\pi_A}{1 - \theta} = \frac{\pi_A}{\pi_A + \pi_T}\\
+ * \theta_2 = \frac{\pi_G}{\theta} = \frac{\pi_G}{\pi_C + \pi_G}\\
+ * \end{cases}
+ * \Longleftrightarrow
+ * \begin{cases}
+ * \pi_A = \theta_1 (1 - \theta)\\
+ * \pi_C = (1 - \theta_2) \theta\\
+ * \pi_G = \theta_2 \theta\\
+ * \pi_T = (1 - \theta_1)(1 - \theta).
+ * \end{cases}
+ * \f]
+ *
+ * with \f$\pi_x\f$ the frequency of nucleotide \f$x\f$.
+ *
+ */
+  
+class FullNucleotideFrequenciesSet :
+  public virtual NucleotideFrequenciesSet,
+  public AbstractFrequenciesSet
+{
+public:
+  FullNucleotideFrequenciesSet(const NucleicAlphabet* alphabet, bool allowNullFreqs = false, const std::string& name = "Full");
+
+  FullNucleotideFrequenciesSet(const NucleicAlphabet* alphabet, double theta, double theta1, double theta2, bool allowNullFreqs = false, const std::string& name = "Full");
+
+#ifndef NO_VIRTUAL_COV
+  FullNucleotideFrequenciesSet*
+#else
+  Clonable*
+#endif
+  clone() const { return new FullNucleotideFrequenciesSet(*this); }
+
+public:
+#ifndef NO_VIRTUAL_COV
+  const NucleicAlphabet* getAlphabet() const
+  {
+    return dynamic_cast<const NucleicAlphabet*>(AbstractFrequenciesSet::getAlphabet());
+  }
+#endif
+
+  void setFrequencies(const std::vector<double>& frequencies);
+
+protected:
+  void fireParameterChanged(const ParameterList& parameters);
+};
+
+
+/**
+ * @brief FrequenciesSet useful for homogeneous and stationary models, nucleotide implementation
+ *
+ * This set contains no parameter.
+ */
+class FixedNucleotideFrequenciesSet :
+  public virtual NucleotideFrequenciesSet,
+  public FixedFrequenciesSet
+{
+public:
+  FixedNucleotideFrequenciesSet(const NucleicAlphabet* alphabet, const std::vector<double>& initFreqs, const std::string& name = "Fixed") :
+    FixedFrequenciesSet(alphabet, initFreqs, name) {}
+
+  /**
+   * @brief Construction with uniform frequencies on the letters of
+   * the alphabet.
+   */
+  FixedNucleotideFrequenciesSet(const NucleicAlphabet* alphabet, const std::string& name = "Fixed") :
+    FixedFrequenciesSet(alphabet, alphabet->getSize(), name) {}
+
+#ifndef NO_VIRTUAL_COV
+  FixedNucleotideFrequenciesSet*
+#else
+  NucleotideFrequenciesSet*
+#endif
+  clone() const { return new FixedNucleotideFrequenciesSet(*this); }
+
+#ifndef NO_VIRTUAL_COV
+  const NucleicAlphabet* getAlphabet() const
+  {
+    return dynamic_cast<const NucleicAlphabet*>(AbstractFrequenciesSet::getAlphabet());
+  }
+#endif
+};
+
+
+} // end of namespace bpp.
+
+#endif // _NUCLEOTIDEFREQUENCIESSET_H_
+
+
diff --git a/src/Bpp/Phyl/Model/FrequenciesSet/ProteinFrequenciesSet.h b/src/Bpp/Phyl/Model/FrequenciesSet/ProteinFrequenciesSet.h
new file mode 100644
index 0000000..533facb
--- /dev/null
+++ b/src/Bpp/Phyl/Model/FrequenciesSet/ProteinFrequenciesSet.h
@@ -0,0 +1,135 @@
+//
+// File: ProteinFrequenciesSet.h
+// Created by: Bastien Boussau
+//             Julien Dutheil
+// Created on: Tue Aug 21 2007
+//
+
+/*
+   Copyright or (c) or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _PROTEINFREQUENCIESSET_H_
+#define _PROTEINFREQUENCIESSET_H_
+
+#include <Bpp/Seq/Alphabet/ProteicAlphabet.h>
+#include "FrequenciesSet.h"
+
+namespace bpp
+{
+/**
+ * @brief Parametrize a set of state frequencies for proteins.
+ */
+class ProteinFrequenciesSet :
+  public virtual FrequenciesSet
+{
+public:
+#ifndef NO_VIRTUAL_COV
+  ProteinFrequenciesSet* clone() const = 0;
+
+  const ProteicAlphabet* getAlphabet() const = 0;
+#endif
+};
+
+/**
+ * @brief Protein FrequenciesSet using 19 independent parameters to modelize the 20 frequencies.
+ *
+ * The parameters are called @f$ \theta_{i \in 1..19} @f$, and are initialized so that all frequencies are equal to  0.005, that is
+ * @f[ \theta_i = \frac{0.05}{0.956{i-1}},\quad i = 1..19 @f] or according to a user-specified vector of initial values.
+ */
+class FullProteinFrequenciesSet :
+  public virtual ProteinFrequenciesSet,
+  public FullFrequenciesSet
+{
+public:
+  FullProteinFrequenciesSet(const ProteicAlphabet* alphabet, bool allowNullFreqs = false, const std::string& name = "Full") :
+    FullFrequenciesSet(alphabet, allowNullFreqs, name) {}
+  FullProteinFrequenciesSet(const ProteicAlphabet* alphabet, const std::vector<double>& initFreqs, bool allowNullFreqs = false, const std::string& name = "Full") :
+    FullFrequenciesSet(alphabet, initFreqs, allowNullFreqs, name) {}
+
+#ifndef NO_VIRTUAL_COV
+  FullProteinFrequenciesSet*
+#else
+  Clonable*
+#endif
+  clone() const { return new FullProteinFrequenciesSet(*this); }
+
+public:
+#ifndef NO_VIRTUAL_COV
+  const ProteicAlphabet* getAlphabet() const
+  {
+    return dynamic_cast<const ProteicAlphabet*>(AbstractFrequenciesSet::getAlphabet());
+  }
+#endif
+};
+
+/**
+ * @brief FrequenciesSet useful for homogeneous and stationary models, protein implementation
+ *
+ * This set contains no parameter.
+ */
+class FixedProteinFrequenciesSet :
+  public virtual ProteinFrequenciesSet,
+  public FixedFrequenciesSet
+{
+public:
+  FixedProteinFrequenciesSet(const ProteicAlphabet* alphabet, const std::vector<double>& initFreqs, const std::string& name = "Fixed") :
+    FixedFrequenciesSet(alphabet, initFreqs, name) {}
+
+  /**
+   * @brief Construction with uniform frequencies on the letters of
+   * the alphabet.
+   */
+  FixedProteinFrequenciesSet(const ProteicAlphabet* alphabet, const std::string& name = "Fixed") :
+    FixedFrequenciesSet(alphabet, alphabet->getSize(), name) {}
+
+#ifndef NO_VIRTUAL_COV
+  FixedProteinFrequenciesSet*
+#else
+  FixedFrequenciesSet*
+#endif
+  clone() const { return new FixedProteinFrequenciesSet(*this); }
+
+#ifndef NO_VIRTUAL_COV
+  const ProteicAlphabet* getAlphabet() const
+  {
+    return dynamic_cast<const ProteicAlphabet*>(AbstractFrequenciesSet::getAlphabet());
+  }
+#endif
+};
+
+
+} // end of namespace bpp.
+
+#endif // _PROTEINFREQUENCIESSET_H_
+
+
diff --git a/src/Bpp/Phyl/Model/FrequenciesSet/WordFrequenciesSet.cpp b/src/Bpp/Phyl/Model/FrequenciesSet/WordFrequenciesSet.cpp
new file mode 100644
index 0000000..9499c70
--- /dev/null
+++ b/src/Bpp/Phyl/Model/FrequenciesSet/WordFrequenciesSet.cpp
@@ -0,0 +1,396 @@
+//
+// File: WordFrequenciesSet.cpp
+// Created by: Laurent Gueguen
+// Created on: lundi 2 avril 2012, à 14h 02
+//
+
+/*
+   Copyright or (c) or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "WordFrequenciesSet.h"
+
+
+using namespace bpp;
+
+#include <cmath>
+using namespace std;
+
+size_t AbstractWordFrequenciesSet::getSizeFromVector(const std::vector<FrequenciesSet*>& freqVector)
+{
+  size_t s = 1;
+  size_t l = freqVector.size();
+
+  for (size_t i = 0; i < l; i++)
+  {
+    s *= freqVector[i]->getAlphabet()->getSize();
+  }
+
+  return s;
+}
+
+AbstractWordFrequenciesSet::AbstractWordFrequenciesSet(size_t size, const Alphabet* palph, const string& prefix, const string& name) :
+  AbstractFrequenciesSet(size, palph, prefix, name)
+{}
+
+size_t AbstractWordFrequenciesSet::getLength() const
+{
+  return dynamic_cast<const WordAlphabet*>(getAlphabet())->getLength();
+}
+
+AbstractWordFrequenciesSet::~AbstractWordFrequenciesSet()
+{}
+
+// ///////////////////////////////////////////////////////////////////
+// // WordFromIndependentFrequenciesSet
+
+
+WordFromIndependentFrequenciesSet::WordFromIndependentFrequenciesSet(
+                                                                     const WordAlphabet* pWA,
+                                                                     const std::vector<FrequenciesSet*>& freqVector,
+                                                                     const string& prefix, const string& name) :
+  AbstractWordFrequenciesSet(pWA->getSize(), pWA, prefix, name),
+  vFreq_(),
+  vNestedPrefix_()
+{
+  size_t sf = getSizeFromVector(freqVector);
+  if (pWA->getSize() !=  sf)
+    throw Exception("WordFromIndependentFrequenciesSet: Size of the frequencies does not match size of the alphabet : " + TextTools::toString(sf) + " vs " + TextTools::toString(pWA->getSize()));
+
+  size_t l = freqVector.size();
+
+  for (size_t i = 0; i < l; i++)
+  {
+    vFreq_.push_back(freqVector[i]);
+    vNestedPrefix_.push_back(freqVector[i]->getNamespace());
+    vFreq_[i]->setNamespace(prefix + TextTools::toString(i + 1) + "_" + vNestedPrefix_[i]);
+    addParameters_(vFreq_[i]->getParameters());
+  }
+
+  updateFrequencies();
+}
+
+WordFromIndependentFrequenciesSet::WordFromIndependentFrequenciesSet(const WordFromIndependentFrequenciesSet& iwfs) :
+  AbstractWordFrequenciesSet(iwfs),
+  vFreq_(iwfs.vFreq_.size()),
+  vNestedPrefix_(iwfs.vNestedPrefix_)
+{
+  for (unsigned i = 0; i < iwfs.vFreq_.size(); i++)
+  {
+    vFreq_[i] =  iwfs.vFreq_[i]->clone();
+  }
+  updateFrequencies();
+}
+
+WordFromIndependentFrequenciesSet::~WordFromIndependentFrequenciesSet()
+{
+  for (unsigned i = 0; i < vFreq_.size(); i++)
+  {
+    delete vFreq_[i];
+  }
+}
+
+WordFromIndependentFrequenciesSet& WordFromIndependentFrequenciesSet::operator=(const WordFromIndependentFrequenciesSet& iwfs)
+{
+  AbstractWordFrequenciesSet::operator=(iwfs);
+  vNestedPrefix_ = iwfs.vNestedPrefix_;
+
+  //Clean current frequencies first:
+  for (unsigned i = 0; i < vFreq_.size(); i++)
+  {
+    delete vFreq_[i];
+  }
+
+  vFreq_.resize(iwfs.vFreq_.size());
+  for (unsigned i = 0; i < vFreq_.size(); i++)
+  {
+    vFreq_[i] = iwfs.vFreq_[i]->clone();
+  }
+  updateFrequencies();
+
+  return *this;
+}
+
+void WordFromIndependentFrequenciesSet::fireParameterChanged(const ParameterList& pl)
+{
+  size_t l = vFreq_.size();
+
+  bool f = 0;
+  for (size_t i = 0; i < l; i++)
+  {
+    f |= vFreq_[i]->matchParametersValues(pl);
+  }
+
+  if (f)
+    updateFrequencies();
+}
+
+void WordFromIndependentFrequenciesSet::updateFrequencies()
+{
+  size_t l = vFreq_.size();
+  size_t s = getAlphabet()->getSize();
+  vector<double> f[l];
+
+  size_t i, p, t, i2;
+
+  for (i = 0; i < l; i++)
+  {
+    f[i] = vFreq_[i]->getFrequencies();
+  }
+
+  for (i = 0; i < s; i++)
+  {
+    i2 = i;
+    getFreq_(i) = 1;
+    for (p = l; p > 0; p--)
+    {
+      t = vFreq_[p - 1]->getAlphabet()->getSize();
+      getFreq_(i) *= f[p - 1][i2 % t];
+      i2 /= t;
+    }
+  }
+}
+
+void WordFromIndependentFrequenciesSet::setFrequencies(const vector<double>& frequencies) 
+{
+  if (frequencies.size() != getAlphabet()->getSize())
+    throw DimensionException("WordFromIndependentFrequenciesSet::setFrequencies", frequencies.size(), getAlphabet()->getSize());
+  double sum = 0.0;
+  size_t size = frequencies.size();
+  for (size_t i = 0; i < size; i++)
+  {
+    sum += frequencies[i];
+  }
+  if (fabs(1. - sum) > 0.000001)
+    throw Exception("WordFromIndependentFrequenciesSet::setFrequencies. Frequencies must equal 1 (sum = " + TextTools::toString(sum) + ").");
+
+  size_t d, i, j, s, l = vFreq_.size();
+  int k;
+  vector<double> freq;
+
+  d = size;
+  for (i = 0; i < l; i++)
+  {
+    s = vFreq_[i]->getAlphabet()->getSize();
+    freq.resize(s);
+    d /= s;
+    for (j = 0; j < s; j++)
+    {
+      freq[j] = 0;
+    }
+    for (k = 0; k < (int)size; k++)
+    {
+      freq[(k / d) % s] += frequencies[k];
+    }
+    vFreq_[i]->setFrequencies(freq);
+  }
+
+  for (i = 0; i < l; i++)
+  {
+    matchParametersValues(vFreq_[i]->getParameters());
+  }
+
+  updateFrequencies();
+}
+
+
+size_t WordFromIndependentFrequenciesSet::getLength() const
+{
+  return vFreq_.size();
+}
+
+void WordFromIndependentFrequenciesSet::setNamespace(const std::string& prefix)
+{
+  AbstractFrequenciesSet::setNamespace(prefix);
+  for (size_t i = 0; i < vFreq_.size(); i++)
+  {
+    vFreq_[i]->setNamespace(prefix + TextTools::toString(i + 1) + "_" + vNestedPrefix_[i]);
+  }
+}
+
+std::string WordFromIndependentFrequenciesSet::getDescription() const
+{
+  string s = getName() +" : " + vFreq_[0]->getName();
+  for (size_t i = 1; i < vFreq_.size(); i++)
+  {
+    s += " * " + vFreq_[i]->getName();
+  }
+  return s;
+}
+
+// ///////////////////////////////////////////////////////////////////
+// // WordFromUniqueFrequenciesSet
+
+
+WordFromUniqueFrequenciesSet::WordFromUniqueFrequenciesSet(const WordAlphabet* pWA,
+                                                           FrequenciesSet* pabsfreq,
+                                                           const string& prefix,
+                                                           const string& name) :
+  AbstractWordFrequenciesSet(pWA->getSize(), pWA, prefix, name),
+  pFreq_(pabsfreq),
+  NestedPrefix_(pabsfreq->getNamespace()),
+  length_(pWA->getLength())
+{
+  size_t i;
+
+  string st = "";
+  for (i = 0; i < length_; i++)
+  {
+    st += TextTools::toString(i + 1);
+  }
+
+  pFreq_->setNamespace(prefix+ st + "_" + NestedPrefix_);
+  addParameters_(pFreq_->getParameters());
+
+  updateFrequencies();
+}
+
+WordFromUniqueFrequenciesSet::WordFromUniqueFrequenciesSet(const WordFromUniqueFrequenciesSet& iwfs) :
+  AbstractWordFrequenciesSet(iwfs),
+  pFreq_(iwfs.pFreq_->clone()),
+  NestedPrefix_(iwfs.NestedPrefix_),
+  length_(iwfs.length_)
+{
+  updateFrequencies();
+}
+
+
+WordFromUniqueFrequenciesSet& WordFromUniqueFrequenciesSet::operator=(const WordFromUniqueFrequenciesSet& iwfs)
+{
+  AbstractWordFrequenciesSet::operator=(iwfs);
+  delete pFreq_;
+  pFreq_ = iwfs.pFreq_->clone();
+  NestedPrefix_ = iwfs.NestedPrefix_;
+  length_ = iwfs.length_;
+
+  updateFrequencies();
+  return *this;
+}
+
+WordFromUniqueFrequenciesSet::~WordFromUniqueFrequenciesSet()
+{
+  if (pFreq_)
+    delete pFreq_;
+  pFreq_ = 0;
+}
+
+void WordFromUniqueFrequenciesSet::fireParameterChanged(const ParameterList& pl)
+{
+  if (pFreq_->matchParametersValues(pl))
+    updateFrequencies();
+}
+
+void WordFromUniqueFrequenciesSet::updateFrequencies()
+{
+  size_t s = getAlphabet()->getSize();
+  vector<double> f;
+  int letsi = pFreq_->getAlphabet()->getSize();
+
+  size_t i, p, i2;
+
+  f = pFreq_->getFrequencies();
+
+  for (i = 0; i < s; i++)
+  {
+    i2 = i;
+    getFreq_(i2) = 1;
+    for (p = length_; p > 0; p--)
+    {
+      getFreq_(i) *= f[i2 % letsi];
+      i2 /= letsi;
+    }
+  }
+}
+
+void WordFromUniqueFrequenciesSet::setFrequencies(const vector<double>& frequencies) 
+{
+  if (frequencies.size() != getAlphabet()->getSize())
+    throw DimensionException("WordFromUniqueFrequenciesSet::setFrequencies", frequencies.size(), getAlphabet()->getSize());
+  double sum = 0.0;
+  size_t size = frequencies.size();
+  for (size_t i = 0; i < size; i++)
+  {
+    sum += frequencies[i];
+  }
+  if (fabs(1. - sum) > 0.000001)
+    throw Exception("WordFromUniqueFrequenciesSet::setFrequencies. Frequencies must equal 1 (sum = " + TextTools::toString(sum) + ").");
+
+  size_t d, i, j;
+  int k;
+  vector<double> freq;
+
+  size_t letsi = pFreq_->getAlphabet()->getSize();
+  freq.resize(letsi);
+
+  for (j = 0; j < letsi; j++)
+  {
+    freq[j] = 0;
+  }
+
+  d = size;
+  for (i = 0; i < length_; i++)
+  {
+    d /= letsi;
+    for (k = 0; k < (int)size; k++)
+    {
+      freq[(k / d) % letsi] += frequencies[k];
+    }
+  }
+  for (j = 0; j < letsi; j++)
+  {
+    freq[j] /= static_cast<double>(length_);
+  }
+
+  pFreq_->setFrequencies(freq);
+  matchParametersValues(pFreq_->getParameters());
+  updateFrequencies();
+}
+
+
+void WordFromUniqueFrequenciesSet::setNamespace(const string& prefix)
+{
+  AbstractFrequenciesSet::setNamespace(prefix);
+  string st = "";
+  for (unsigned i = 0; i < length_; i++)
+  {
+    st += TextTools::toString(i + 1);
+  }
+  pFreq_->setNamespace(prefix + st + "_" + NestedPrefix_);
+}
+
+
+string WordFromUniqueFrequenciesSet::getDescription() const
+{
+  return getName() + " : " + pFreq_->getName() + " * " + TextTools::toString(length_);
+}
+
+
diff --git a/src/Bpp/Phyl/Model/FrequenciesSet/WordFrequenciesSet.h b/src/Bpp/Phyl/Model/FrequenciesSet/WordFrequenciesSet.h
new file mode 100644
index 0000000..0f31b67
--- /dev/null
+++ b/src/Bpp/Phyl/Model/FrequenciesSet/WordFrequenciesSet.h
@@ -0,0 +1,243 @@
+//
+// File: WordFrequenciesSet.h
+// Created by: Laurent Gueguen
+// Created on: lundi 2 avril 2012, à 13h 59
+//
+
+/*
+   Copyright or (c) or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _WORDFREQUENCIESSET_H_
+#define _WORDFREQUENCIESSET_H_
+
+#include <Bpp/Seq/Alphabet/WordAlphabet.h>
+#include "FrequenciesSet.h"
+
+namespace bpp
+{
+
+  /*********************************************************************/
+/****   Frequencies Set in Words *****/
+/*********************************************************************/
+
+
+/**
+ * @brief Frequencies in words computed from the  frequencies on
+ * letters. The parameters are the parameters of the Frequencies on
+ * letters.
+ * The WordFrequenciesSet owns the FrequenciesSet* it is built on.
+ * Interface class.
+ * @author Laurent Guéguen
+ */
+
+class WordFrequenciesSet :
+  public virtual FrequenciesSet
+{
+protected:
+  
+  virtual size_t getSizeFromVector(const std::vector<FrequenciesSet*>& freqVector) = 0;
+  
+public:
+#ifndef NO_VIRTUAL_COV
+  WordFrequenciesSet* clone() const = 0;
+
+  const WordAlphabet* getAlphabet() const = 0;
+#endif
+
+  /**
+   *@ brief Returns the n-th FrequenciesSet&
+   **/
+
+  virtual const FrequenciesSet& getFrequenciesSetForLetter(size_t i) const = 0;
+
+  /**
+   *@ brief Returns the length of the words
+   **/
+
+  virtual size_t getLength() const = 0;
+};
+
+
+class AbstractWordFrequenciesSet :
+  public virtual WordFrequenciesSet,
+  public AbstractFrequenciesSet
+{
+protected:
+  size_t getSizeFromVector(const std::vector<FrequenciesSet*>& freqVector);
+  
+public:
+  AbstractWordFrequenciesSet(size_t size, const Alphabet* palph, const std::string& prefix = "", const std::string& name="");
+
+#ifndef NO_VIRTUAL_COV
+  AbstractWordFrequenciesSet*
+#else
+  Clonable*
+#endif
+  clone() const = 0;
+
+  AbstractWordFrequenciesSet(const AbstractWordFrequenciesSet& af) :
+    AbstractFrequenciesSet(af) {}
+
+  AbstractWordFrequenciesSet & operator=(const AbstractWordFrequenciesSet& af)
+  {
+    AbstractFrequenciesSet::operator=(af);
+    return *this;
+  }
+
+#ifndef NO_VIRTUAL_COV
+  const WordAlphabet* getAlphabet() const
+  {
+    return dynamic_cast<const WordAlphabet*>(AbstractFrequenciesSet::getAlphabet());
+  }
+#endif
+
+  virtual ~AbstractWordFrequenciesSet();
+  
+  /**
+   *@ brief Return the length of the words
+   **/
+  
+  size_t getLength() const;
+};
+
+
+/**
+ * @brief the Frequencies in words are the product of Independent Frequencies in letters
+ * @author Laurent Guéguen
+ */
+
+class WordFromIndependentFrequenciesSet :
+    public AbstractWordFrequenciesSet
+{
+protected:
+  std::vector<FrequenciesSet*> vFreq_;
+  std::vector<std::string> vNestedPrefix_;
+
+public:
+  /**
+   * @brief Constructor from a WordAlphabet* and a vector of different FrequenciesSet*.
+   * Throws an Exception if their lengths do not match.
+   */
+  WordFromIndependentFrequenciesSet(const WordAlphabet* pWA, const std::vector<FrequenciesSet*>& freqVector, const std::string& prefix = "", const std::string& name="WordFromIndependent");
+
+  WordFromIndependentFrequenciesSet(const WordFromIndependentFrequenciesSet& iwfs);
+
+  ~WordFromIndependentFrequenciesSet();
+
+  WordFromIndependentFrequenciesSet& operator=(const WordFromIndependentFrequenciesSet& iwfs);
+
+  WordFromIndependentFrequenciesSet* clone() const { return new WordFromIndependentFrequenciesSet(*this); }
+
+public:
+  void fireParameterChanged(const ParameterList& pl);
+
+  virtual void updateFrequencies();
+
+  /**
+   *@ brief Independent letter frequencies from given word frequencies.
+   * The frequencies of a letter at a position is the sum of the
+   *    frequencies of the words that have this letter at this
+   *    position.
+   */
+  virtual void setFrequencies(const std::vector<double>& frequencies);
+
+  /**
+   *@ brief Return the n-th FrequenciesSet&
+   **/
+  const FrequenciesSet& getFrequenciesSetForLetter(size_t i) const { return *vFreq_[i]; }
+
+  /**
+   *@ brief Return the length of the words
+   **/
+
+  virtual size_t getLength() const;
+
+  void setNamespace(const std::string& prefix);
+
+  std::string getDescription() const;
+};
+
+class WordFromUniqueFrequenciesSet :
+  public AbstractWordFrequenciesSet
+{
+protected:
+  FrequenciesSet* pFreq_;
+  std::string NestedPrefix_;
+  size_t length_;
+
+public:
+  /**
+   * @brief Constructor from a WordAlphabet* and a FrequenciesSet*
+   *  repeated as many times as the length of the words.
+   */
+  WordFromUniqueFrequenciesSet(const WordAlphabet* pWA, FrequenciesSet* pabsfreq, const std::string& prefix = "", const std::string& name = "WordFromUnique");
+
+  WordFromUniqueFrequenciesSet(const WordFromUniqueFrequenciesSet& iwfs);
+
+  WordFromUniqueFrequenciesSet& operator=(const WordFromUniqueFrequenciesSet& iwfs);
+
+  ~WordFromUniqueFrequenciesSet();
+
+  WordFromUniqueFrequenciesSet* clone() const { return new WordFromUniqueFrequenciesSet(*this); }
+
+public:
+  virtual void fireParameterChanged(const ParameterList& pl);
+
+  /**
+   *@ brief letter frequencies from given word frequencies. The
+   * frequencies of a letter at a position is the sum of the
+   * frequencies of the words that have this letter at this position.
+   * The frequencies of each letter is the average of the frequencies
+   * of that letter at all positions.
+   */
+  virtual void setFrequencies(const std::vector<double>& frequencies);
+
+  virtual void updateFrequencies();
+
+  /**
+   *@ brief Return the n-th FrequenciesSet&
+   **/
+  const FrequenciesSet& getFrequenciesSetForLetter(size_t i) const { return *pFreq_; }
+
+  size_t getLength() const { return length_; }
+
+  void setNamespace(const std::string& prefix);
+
+  std::string getDescription() const;
+};
+
+} // end of namespace bpp.
+
+#endif // _WORDFREQUENCIESSET_H_
+
+
diff --git a/src/Bpp/Phyl/Model/G2001.h b/src/Bpp/Phyl/Model/G2001.h
new file mode 100644
index 0000000..cd0f3b0
--- /dev/null
+++ b/src/Bpp/Phyl/Model/G2001.h
@@ -0,0 +1,172 @@
+//
+// File: G2001.h
+// Created by: Julien Dutheil
+// Created on: Mon Aug 07 18:31 2006
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _G2001_H_
+#define _G2001_H_
+
+#include "MarkovModulatedSubstitutionModel.h"
+
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+#include <Bpp/Numeric/Parameter.h>
+
+namespace bpp
+{
+/**
+ * @brief Galtier's 2001 covarion model.
+ *
+ * This model is a subclass of the so-called Markov-modulated substitution models,
+ * with a Jukes-Cantor rate matrix, of parameter @f$\nu at f$.
+ * the original version uses a discrete @f$\Gamma at f$ distribution for rates, but you can
+ * use it with virtually any rate distribution.
+ *
+ * @see MarkovModulatedSubstitutionModel
+ *
+ * Galtier N., Maximum-likelihood phylogenetic analysis under a covarion-like model (2001).
+ * _Molecular Biology and Evolution_, 18:866-73.
+ */
+class G2001 :
+  public MarkovModulatedSubstitutionModel
+{
+private:
+  DiscreteDistribution* rDist_;
+
+  std::string nestedRatePrefix_;
+
+public:
+  /**
+   * @brief Build a new G2001 substitution model.
+   *
+   * @param model The substitution model to use. May be of any alphabet type.
+   * @param rDist The discrete distribution for rates. The class will own the DiscreteDistribution object,
+   * which will be deleted together with this instance.
+   * @param nu    The rate matrix parameter.
+   * @param normalizeRateChanges Tell if the rate transition matrix should be normalized.
+   */
+  G2001(ReversibleSubstitutionModel* model, DiscreteDistribution* rDist, double nu = 1., bool normalizeRateChanges = false) :
+    MarkovModulatedSubstitutionModel(model, normalizeRateChanges, "G01."),
+    rDist_(rDist),
+    nestedRatePrefix_("rdist_" + rDist->getNamespace())
+  {
+    nbRates_ = rDist_->getNumberOfCategories();
+    ratesExchangeability_.resize(nbRates_, nbRates_);
+    rates_.resize(nbRates_, nbRates_);
+    ratesFreq_ = std::vector<double>(nbRates_, 1. / static_cast<double>(nbRates_));
+    rDist_->setNamespace(getNamespace() + nestedRatePrefix_);
+    addParameters_(rDist_->getIndependentParameters());
+    addParameter_(new Parameter("G01.nu", nu, &Parameter::R_PLUS));
+    updateRatesModel();
+    updateMatrices();
+  }
+
+  G2001(const G2001& model) :
+    MarkovModulatedSubstitutionModel(model),
+    rDist_(dynamic_cast<DiscreteDistribution*>(model.rDist_->clone())),
+    nestedRatePrefix_(model.nestedRatePrefix_)
+  {}
+
+  G2001& operator=(const G2001& model)
+  {
+    MarkovModulatedSubstitutionModel::operator=(model);
+    rDist_ = dynamic_cast<DiscreteDistribution*>(model.rDist_->clone());
+    nestedRatePrefix_ = model.nestedRatePrefix_;
+    return *this;
+  }
+
+  virtual ~G2001() { delete rDist_; }
+
+  G2001* clone() const { return new G2001(*this); }
+
+public:
+  std::string getName() const { return "G01"; }
+
+  /**
+   * @brief Re-definition of the super-class method to update the rate distribution too.
+   *
+   * @param parameters The parameters that have been modified.
+   */
+  void fireParameterChanged(const ParameterList& parameters)
+  {
+    rDist_->matchParametersValues(parameters);
+    MarkovModulatedSubstitutionModel::fireParameterChanged(parameters);
+  }
+
+  /**
+   * @return The rate distribution associated to this instance.
+   */
+  const DiscreteDistribution* getRateDistribution() const { return rDist_; }
+
+  void setNamespace(const std::string& prefix)
+  {
+    MarkovModulatedSubstitutionModel::setNamespace(prefix);
+    // We also need to update the namespace of the nested distribution:
+    rDist_->setNamespace(prefix + nestedRatePrefix_);
+  }
+
+
+  double getRate() const {  return 1.; }
+
+  void setRate(double rate) {}
+
+  void addRateParameter() {}
+
+protected:
+  void updateRatesModel()
+  {
+    double nu = getParameterValue("nu");
+    for (size_t i = 0; i < nbRates_; i++)
+    {
+      rates_(i, i) = rDist_->getCategory(i);
+      for (size_t j = 0; j < nbRates_; j++)
+      {
+        if (i == j)
+        {
+          ratesExchangeability_(i, j) = -static_cast<double>(nbRates_) * nu;
+        }
+        else
+        {
+          ratesExchangeability_(i, j) = static_cast<double>(nbRates_) * nu / static_cast<double>(nbRates_ - 1);
+        }
+      }
+    }
+  }
+};
+} // end of namespace bpp.
+
+#endif // _G2001_H_
+
diff --git a/src/Bpp/Phyl/Model/MarkovModulatedSubstitutionModel.cpp b/src/Bpp/Phyl/Model/MarkovModulatedSubstitutionModel.cpp
new file mode 100644
index 0000000..b5abb07
--- /dev/null
+++ b/src/Bpp/Phyl/Model/MarkovModulatedSubstitutionModel.cpp
@@ -0,0 +1,229 @@
+//
+// File: MarkovModulatedSubstitutionModel.cpp
+// Created by: Julien Dutheil
+// Created on: Sat Aug 05 08:21 2006
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "MarkovModulatedSubstitutionModel.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Numeric/Matrix/EigenValue.h>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+MarkovModulatedSubstitutionModel::MarkovModulatedSubstitutionModel(
+  const MarkovModulatedSubstitutionModel& model) :
+  AbstractParameterAliasable(model),
+  model_               (dynamic_cast<ReversibleSubstitutionModel*>(model.model_->clone())),
+  nbStates_            (model.nbStates_),
+  nbRates_             (model.nbRates_),
+  rates_               (model.rates_),
+  ratesExchangeability_(model.ratesExchangeability_),
+  ratesFreq_           (model.ratesFreq_),
+  ratesGenerator_      (model.ratesGenerator_),
+  chars_               (model.chars_),
+  generator_           (model.generator_),
+  exchangeability_     (model.exchangeability_),
+  leftEigenVectors_    (model.leftEigenVectors_),
+  rightEigenVectors_   (model.rightEigenVectors_),
+  eigenValues_         (model.eigenValues_),
+  iEigenValues_        (model.iEigenValues_),
+  eigenDecompose_      (model.eigenDecompose_),
+  pijt_                (model.pijt_),
+  dpijt_               (model.dpijt_),
+  d2pijt_              (model.d2pijt_),
+  freq_                (model.freq_),
+  normalizeRateChanges_(model.normalizeRateChanges_),
+  nestedPrefix_        (model.nestedPrefix_)
+{}
+
+MarkovModulatedSubstitutionModel& MarkovModulatedSubstitutionModel::operator=(
+  const MarkovModulatedSubstitutionModel& model)
+{
+  AbstractParametrizable::operator=(model);
+  model_                = dynamic_cast<ReversibleSubstitutionModel*>(model.model_->clone());
+  nbStates_             = model.nbStates_;
+  nbRates_              = model.nbRates_;
+  rates_                = model.rates_;
+  ratesExchangeability_ = model.ratesExchangeability_;
+  ratesFreq_            = model.ratesFreq_;
+  ratesGenerator_       = model.ratesGenerator_;
+  chars_                = model.chars_;
+  generator_            = model.generator_;
+  exchangeability_      = model.exchangeability_;
+  leftEigenVectors_     = model.leftEigenVectors_;
+  rightEigenVectors_    = model.rightEigenVectors_;
+  eigenValues_          = model.eigenValues_;
+  iEigenValues_         = model.iEigenValues_;
+  eigenDecompose_       = model.eigenDecompose_;
+  pijt_                 = model.pijt_;
+  dpijt_                = model.dpijt_;
+  d2pijt_               = model.d2pijt_;
+  freq_                 = model.freq_;
+  normalizeRateChanges_ = model.normalizeRateChanges_;
+  nestedPrefix_         = model.nestedPrefix_;
+  return *this;
+}
+
+/******************************************************************************/
+
+void MarkovModulatedSubstitutionModel::updateMatrices()
+{
+  // ratesGenerator_ and rates_ must be initialized!
+  nbStates_        = model_->getNumberOfStates();
+  nbRates_         = rates_.getNumberOfColumns();
+  chars_           = VectorTools::rep(model_->getAlphabetChars(), nbRates_);
+  RowMatrix<double> Tmp1, Tmp2;
+  MatrixTools::diag(ratesFreq_, Tmp1);
+  MatrixTools::mult(ratesExchangeability_, Tmp1, ratesGenerator_);
+  MatrixTools::kroneckerMult(rates_, model_->getGenerator(), generator_);
+
+  MatrixTools::MatrixTools::getId< RowMatrix<double> >(nbStates_, Tmp1);
+  MatrixTools::kroneckerMult(ratesGenerator_, Tmp1, Tmp2);
+  MatrixTools::add(generator_, Tmp2);
+
+  MatrixTools::diag(1. / ratesFreq_, Tmp1);
+  MatrixTools::mult(rates_, Tmp1, Tmp2);
+  MatrixTools::kroneckerMult(Tmp2, model_->getExchangeabilityMatrix(), exchangeability_);
+
+  MatrixTools::diag(1 / model_->getFrequencies(), Tmp1);
+  MatrixTools::kroneckerMult(ratesExchangeability_, Tmp1, Tmp2);
+  MatrixTools::add(exchangeability_, Tmp2);
+  freq_ = VectorTools::kroneckerMult(ratesFreq_, model_->getFrequencies());
+  if (normalizeRateChanges_)
+  {
+    // Normalization:
+    Vdouble Tmp;
+    MatrixTools::diag(generator_, Tmp);
+    double scale = -VectorTools::scalar<double, double>(Tmp, freq_);
+    MatrixTools::scale(generator_, 1. / scale);
+
+    // Normalize exchangeability matrix too:
+    MatrixTools::scale(exchangeability_, 1. / scale);
+  }
+
+  // Compute eigen values and vectors:
+  eigenValues_.resize(nbRates_ * nbStates_);
+  iEigenValues_.resize(nbRates_ * nbStates_);
+  rightEigenVectors_.resize(nbStates_ * nbRates_, nbStates_ * nbRates_);
+  pijt_.resize(nbStates_ * nbRates_, nbStates_ * nbRates_);
+  dpijt_.resize(nbStates_ * nbRates_, nbStates_ * nbRates_);
+  d2pijt_.resize(nbStates_ * nbRates_, nbStates_ * nbRates_);
+
+  vector<double>    modelEigenValues       = model_->getEigenValues();
+  RowMatrix<double> modelRightEigenVectors = model_->getColumnRightEigenVectors();
+  for (unsigned int i = 0; i < nbStates_; i++)
+  {
+    RowMatrix<double> tmp = rates_;
+    MatrixTools::scale(tmp, modelEigenValues[i]);
+    MatrixTools::add(tmp, ratesGenerator_);
+    EigenValue<double> ev(tmp);
+    vector<double>    values  = ev.getRealEigenValues();
+    RowMatrix<double> vectors = ev.getV();
+    for (size_t j = 0; j < nbRates_; j++)
+    {
+      size_t c = i * nbRates_ + j; // Current eigen value index.
+      eigenValues_[c] = values[j];
+      // Compute the Kronecker product of the jth vector and the ith modelRightEigenVector.
+      for (unsigned int ii = 0; ii < nbRates_; ii++)
+      {
+        double vii = vectors(ii, j);
+        for (unsigned int jj = 0; jj < nbStates_; jj++)
+        {
+          rightEigenVectors_(ii * nbStates_ + jj, c) = vii * modelRightEigenVectors(jj, i);
+        }
+      }
+    }
+  }
+  // Now compute left eigen vectors by inversion:
+  MatrixTools::inv(rightEigenVectors_, leftEigenVectors_);
+}
+
+/******************************************************************************/
+
+const Matrix<double>& MarkovModulatedSubstitutionModel::getPij_t(double t) const
+{
+  if (t == 0)
+    MatrixTools::getId< RowMatrix<double> >(nbStates_ * nbRates_, pijt_);
+  else
+    MatrixTools::mult(rightEigenVectors_, VectorTools::exp(eigenValues_ * t), leftEigenVectors_, pijt_);
+  return pijt_;
+}
+
+const Matrix<double>& MarkovModulatedSubstitutionModel::getdPij_dt(double t) const
+{
+  MatrixTools::mult(rightEigenVectors_, eigenValues_ * VectorTools::exp(eigenValues_ * t), leftEigenVectors_, dpijt_);
+  return dpijt_;
+}
+
+const Matrix<double>& MarkovModulatedSubstitutionModel::getd2Pij_dt2(double t) const
+{
+  MatrixTools::mult(rightEigenVectors_, NumTools::sqr(eigenValues_) * VectorTools::exp(eigenValues_ * t), leftEigenVectors_, d2pijt_);
+  return d2pijt_;
+}
+
+/******************************************************************************/
+
+double MarkovModulatedSubstitutionModel::getInitValue(size_t i, int state) const throw (IndexOutOfBoundsException, BadIntException)
+{
+  if (i >= (nbStates_ * nbRates_))
+    throw IndexOutOfBoundsException("MarkovModulatedSubstitutionModel::getInitValue", i, 0, nbStates_ * nbRates_ - 1);
+  if (state < 0 || !model_->getAlphabet()->isIntInAlphabet(state))
+    throw BadIntException(state, "MarkovModulatedSubstitutionModel::getInitValue. Character " + model_->getAlphabet()->intToChar(state) + " is not allowed in model.");
+  vector<int> states = model_->getAlphabet()->getAlias(state);
+  for (size_t j = 0; j < states.size(); j++)
+  {
+    if (getAlphabetChar(i) == states[j])
+      return 1.;
+  }
+  return 0.;
+}
+
+/******************************************************************************/
+
+void MarkovModulatedSubstitutionModel::setNamespace(const string& prefix)
+{
+  AbstractParameterAliasable::setNamespace(prefix);
+  // We also need to update the namespace of the nested model:
+  model_->setNamespace(prefix + nestedPrefix_);
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/MarkovModulatedSubstitutionModel.h b/src/Bpp/Phyl/Model/MarkovModulatedSubstitutionModel.h
new file mode 100644
index 0000000..c022589
--- /dev/null
+++ b/src/Bpp/Phyl/Model/MarkovModulatedSubstitutionModel.h
@@ -0,0 +1,316 @@
+//
+// File: MarkovModulatedSubstitutionModel.h
+// Created by: Julien Dutheil
+// Created on: Sat Aug 05 08:21 2006
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _MARKOVMODULATEDSUBSTITUTIONMODEL_H_
+#define _MARKOVMODULATEDSUBSTITUTIONMODEL_H_
+
+#include "SubstitutionModel.h"
+
+#include <Bpp/Numeric/AbstractParameterAliasable.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+namespace bpp
+{
+
+  /**
+   * @brief Partial implementation of the Markov-modulated class of substitution
+   * models.
+   *
+   * This class wraps a substitution model and provide a matrix describing rate changes.
+   * The rate matrix must be initialized by derived classes of this class.
+   * Using these matrices, the diagonalization procedure of Galtier and Jean-Marie is used.
+   *
+   * Such models can be described using two matrices:
+   * a substitution matrix, @f$M at f$, with size @f$m at f$, which is a "standard" substitution model of any alphabet type,
+   * and a rate matrix @f$G at f$ of size @f$g at f$.
+   * The generator of the markov-modulated model, @f$Q at f$ can be written using Kronecker matrix operands:
+   * @f[
+   * Q=D_R \otimes M + G \otimes I_m,
+   * @f]
+   * where @f$D_R at f$ is the diagonal matrix of all rates, and @f$I_m at f$ is the identity matrix of size @f$m at f$.
+   *
+   * This generator is normalized so that branch lengths are measured in unit of mean number of substitutions per site,
+   * where susbstitution here means "change of alphabet state".
+   * Rate changes are not counted.
+   *
+   * Galtier N. and Jean-Marie A., Markov-modulated Markov chains and the covarion process of molecular evolution (2004).
+   * _Journal of Computational Biology_, 11:727-33.
+   */
+  class MarkovModulatedSubstitutionModel:
+    public virtual ReversibleSubstitutionModel,
+    public AbstractParameterAliasable
+  {
+
+  protected:
+    ReversibleSubstitutionModel* model_;
+    size_t nbStates_; //Number of states in model
+    size_t nbRates_; //Number of rate classes
+
+    /**
+     * @name Rate generator.
+     *
+     * These variables must be initialized in the constructor of the derived class.
+     * @{
+     */
+    RowMatrix<double> rates_;                //All rates values
+    RowMatrix<double> ratesExchangeability_; //All rates transitions
+    Vdouble           ratesFreq_;            //All rates equilibrium frequencies
+    /**@}*/
+    RowMatrix<double> ratesGenerator_;       //All rates transitions
+    
+    /**
+     * @brief The list of supported chars.
+     */
+    std::vector<int> chars_;
+
+    /**
+     * @brief The generator matrix \f$Q\f$ of the model.
+     */
+    RowMatrix<double> generator_;
+
+    /**
+     * @brief The exchangeability matrix \f$S\f$ of the model.
+     */
+    RowMatrix<double> exchangeability_;
+
+    /**
+     * @brief The \f$U\f$ matrix made of left eigen vectors (by row).
+     */
+    RowMatrix<double> leftEigenVectors_;
+
+    /**
+     * @brief The \f$U^-1\f$ matrix made of right eigen vectors (by column).
+     */
+    RowMatrix<double> rightEigenVectors_;
+
+    /**
+     * @brief The vector of real parts of eigen values.
+     */
+    Vdouble eigenValues_;
+
+    /**
+     * @brief The vector of imaginary parts of the eigen values (zero
+     * in case of reversible pmodel).
+     */
+    Vdouble iEigenValues_;
+
+    /**
+     * @brief Tell if the eigen decomposition should be performed.
+     */
+    bool eigenDecompose_;
+
+    /**
+     * @brief These ones are for bookkeeping:
+     */
+    mutable RowMatrix<double> pijt_;
+    mutable RowMatrix<double> dpijt_;
+    mutable RowMatrix<double> d2pijt_;
+
+    /**
+     * @brief The vector of equilibrium frequencies.
+     */
+    Vdouble freq_;
+
+    bool normalizeRateChanges_;
+
+    std::string nestedPrefix_;
+
+  public:
+    /**
+     * @brief Build a new MarkovModulatedSubstitutionModel object.
+     *
+     * @param model The substitution model to use. Can be of any alphabet type, and will be owned by this instance.
+     * @param normalizeRateChanges Tells if the branch lengths must be computed in terms of rate and state
+     * @param prefix The parameter namespace to be forwarded to the AbstractParametrizable constructor.
+     * changes instead of state change only.
+     * NB: In most cases, this parameter should be set to false.
+     */
+    MarkovModulatedSubstitutionModel(ReversibleSubstitutionModel* model, bool normalizeRateChanges, const std::string& prefix) :
+      AbstractParameterAliasable(prefix),
+      model_(model), nbStates_(model->getNumberOfStates()), nbRates_(0), rates_(), ratesExchangeability_(),
+      ratesFreq_(), ratesGenerator_(), chars_(), generator_(), exchangeability_(),
+      leftEigenVectors_(), rightEigenVectors_(), eigenValues_(), iEigenValues_(), eigenDecompose_(true), 
+      pijt_(), dpijt_(), d2pijt_(), freq_(),
+      normalizeRateChanges_(normalizeRateChanges),
+      nestedPrefix_("model_" + model->getNamespace())
+    {
+      model_->setNamespace(prefix + nestedPrefix_);
+      addParameters_(model_->getIndependentParameters());
+    }
+    
+    MarkovModulatedSubstitutionModel(const MarkovModulatedSubstitutionModel& model);
+    MarkovModulatedSubstitutionModel& operator=(const MarkovModulatedSubstitutionModel& model);
+
+    virtual ~MarkovModulatedSubstitutionModel() { delete model_; }
+
+#ifndef NO_VIRTUAL_COV
+    MarkovModulatedSubstitutionModel*
+#else
+    Clonable*
+#endif
+    clone() const = 0;
+
+  public:
+	  
+    const Alphabet* getAlphabet() const { return model_->getAlphabet(); }
+
+    size_t getNumberOfStates() const { return nbStates_ * nbRates_; }
+
+    const Vdouble& getFrequencies() const { return freq_; }
+    
+    const Matrix<double>& getExchangeabilityMatrix() const { return exchangeability_; }
+    
+    const Matrix<double>& getGenerator() const { return generator_; }
+    
+    const Matrix<double>& getPij_t(double t) const;
+    const Matrix<double>& getdPij_dt(double t) const;
+    const Matrix<double>& getd2Pij_dt2(double t) const;
+    
+    const Vdouble& getEigenValues() const { return eigenValues_; }
+    const Vdouble& getIEigenValues() const { return iEigenValues_; }
+
+    bool isDiagonalizable() const { return true; }
+    bool isNonSingular() const { return true; }
+
+    const Matrix<double>& getRowLeftEigenVectors() const { return leftEigenVectors_; }
+    const Matrix<double>& getColumnRightEigenVectors() const { return rightEigenVectors_; }
+    
+    double freq(size_t i) const { return freq_[i]; }
+    double Sij(size_t i, size_t j) const { return exchangeability_(i, j); }
+    double Qij(size_t i, size_t j) const { return generator_(i, j); }
+    
+    double Pij_t    (size_t i, size_t j, double t) const { return getPij_t(t)(i, j); }
+    double dPij_dt  (size_t i, size_t j, double t) const { return getdPij_dt(t)(i, j); }
+    double d2Pij_dt2(size_t i, size_t j, double t) const { return getd2Pij_dt2(t)(i, j); }
+    
+    double getInitValue(size_t i, int state) const throw (IndexOutOfBoundsException, BadIntException);
+    
+    void setFreqFromData(const SequenceContainer& data, double pseudoCount = 0)
+    {
+      model_->setFreqFromData(data, pseudoCount);
+      updateMatrices();
+    }
+
+    const std::vector<int>& getAlphabetChars() const
+    {
+      return chars_;
+    }
+
+    int getAlphabetChar(size_t i) const
+    {
+      return chars_[i]; 
+    }
+   
+    std::vector<size_t> getModelStates(int i) const
+    {
+      std::vector<size_t> states(nbRates_ * nbStates_);
+      std::vector<size_t> nestedStates = model_->getModelStates(i);
+      for(size_t j = 0; j < nbRates_; j++)
+        for(size_t k = 0; k < nestedStates.size(); k++)
+          states.push_back(j * nbRates_ + states[k]);
+      return states;
+    }
+
+    const ReversibleSubstitutionModel* getNestedModel() const { return model_; }
+
+    /**
+     * @brief Get the rate category corresponding to a particular state in the compound model.
+     *
+     * @param i The state.
+     * @return The corresponding rate category.
+     * @see getState;
+     */
+    size_t getRate(size_t i) const
+    {
+      return i / nbStates_; 
+    }
+
+    double getRate() const { return model_->getRate(); }
+
+    void setRate(double rate) { model_->setRate(rate); }
+
+    double getScale() const
+    {
+      std::vector<double> v;
+      MatrixTools::diag(generator_, v);
+      return -VectorTools::scalar<double, double>(v, freq_);
+    }
+
+    void setScale(double scale) {
+      model_->setScale(scale);
+      updateMatrices();
+    } 
+
+    void enableEigenDecomposition(bool yn) { eigenDecompose_ = yn; }
+
+    bool enableEigenDecomposition() { return eigenDecompose_; }
+	
+    /**
+     * @brief Tells the model that a parameter value has changed.
+     *
+     * This updates the matrices consequently.
+     */
+    virtual void fireParameterChanged(const ParameterList& parameters)
+    {
+      AbstractParameterAliasable::fireParameterChanged(parameters);
+      model_->matchParametersValues(parameters);
+      updateRatesModel();
+      updateMatrices();
+    }
+   
+    void setNamespace(const std::string& prefix);
+
+  protected:
+    
+    virtual void updateMatrices();
+
+    /**
+     * @brief Update the rates vector, generator and equilibrium frequencies.
+     *
+     * This method must be implemented by the derived class.
+     * It is called by the fireParameterChanged() method.
+     */
+    virtual void updateRatesModel() = 0;
+
+  };
+
+} //end of namespace bpp.
+
+#endif //_MARKOVMODULATEDSUBSTITUTIONMODEL_H_
+
diff --git a/src/Bpp/Phyl/Model/MixedSubstitutionModel.h b/src/Bpp/Phyl/Model/MixedSubstitutionModel.h
new file mode 100644
index 0000000..1c8c880
--- /dev/null
+++ b/src/Bpp/Phyl/Model/MixedSubstitutionModel.h
@@ -0,0 +1,137 @@
+//
+// File: MixedSubstitutionModel.h
+// Created by: Laurent Gueguen
+//
+
+/*
+  Copyright or © or Copr. CNRS, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _MIXEDSUBSTITUTIONMODEL_H_
+#define _MIXEDSUBSTITUTIONMODEL_H_
+
+#include "SubstitutionModel.h"
+// #include <Bpp/Seq/Alphabet.all>
+
+#include <vector>
+#include <string>
+#include <map>
+#include <cstring> // C lib for string copy
+
+namespace bpp
+{
+  /**
+   * @brief Interface for Substitution models, defined as a mixture
+   * of "simple" substitution models.
+   * @author Laurent Guéguen
+   *
+   */
+
+  class MixedSubstitutionModel :
+    public virtual SubstitutionModel
+  {
+  public:
+    MixedSubstitutionModel() {};
+
+    virtual ~MixedSubstitutionModel(){};
+
+    virtual MixedSubstitutionModel* clone() const = 0;
+
+  public:
+
+    /**
+     * @brief Returns a specific model from the mixture
+     */
+    virtual const SubstitutionModel* getNModel(size_t i) const = 0;
+
+    virtual SubstitutionModel* getNModel(size_t i) = 0;
+
+    /**
+     * @brief Returns the  probability of a specific model from the mixture
+     */
+  
+    virtual double getNProbability(size_t i) const = 0;
+
+    virtual const std::vector<double>& getProbabilities() const = 0;
+
+    /**
+     * @brief Sets the  probability of a specific model from the mixture
+     */
+  
+    virtual void setNProbability(size_t i, double prob) = 0;
+
+    virtual size_t getNumberOfModels() const = 0;
+
+    /**
+     * @brief Returns the rates of the submodels.
+     */
+
+    virtual const std::vector<double>& getVRates() const = 0;
+
+    /**
+     * @brief Returns the rate of a specific submodel.
+     */
+
+    virtual double getNRate(size_t i) const = 0;
+
+    /**
+     * @brief Sets the rates of the submodels to be proportional to a
+     * given vector, and normalizes them so that the mean rate of the
+     * mixture equals rate_.
+     
+     * @param vd a vector of positive values such that the rates of
+     * the respective submodels are in the same proportions (ie this
+     * vector does not need to be normalized).
+     */
+
+    virtual void setVRates(const Vdouble& vd) = 0;
+
+    /**
+     * @brief Normalizes the rates of the submodels so that the mean
+     * rate of the mixture equals rate_.
+     */
+
+    virtual void normalizeVRates() = 0;
+
+    /*
+     *@brief Returns the vector of numbers of the submodels in the
+     *mixture that match a description.
+     *
+     */
+  
+    virtual Vint getSubmodelNumbers(std::string& desc) const = 0;
+
+
+  };
+} // end of namespace bpp.
+
+#endif  // _MIXEDSUBSTITUTIONMODEL_H_
diff --git a/src/Bpp/Phyl/Model/MixedSubstitutionModelSet.cpp b/src/Bpp/Phyl/Model/MixedSubstitutionModelSet.cpp
new file mode 100644
index 0000000..6516f42
--- /dev/null
+++ b/src/Bpp/Phyl/Model/MixedSubstitutionModelSet.cpp
@@ -0,0 +1,482 @@
+//
+// File: MixedSubstitutionModelSet.cpp
+// Created by: Laurent Guéguen
+// Created on: mercredi 25 mai 2011, à 22h 12
+//
+
+/*
+   Copyright or <A9> or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "MixedSubstitutionModelSet.h"
+#include "MixedSubstitutionModel.h"
+#include "MixtureOfASubstitutionModel.h"
+
+using namespace bpp;
+using namespace std;
+
+MixedSubstitutionModelSet::MixedSubstitutionModelSet(const MixedSubstitutionModelSet& set) :
+  SubstitutionModelSet(set),
+  vpHyperNodes_()
+{
+  for (size_t i = 0; i < set.vpHyperNodes_.size(); i++)
+  {
+    vpHyperNodes_.push_back(new HyperNode(*set.vpHyperNodes_[i]));
+  }
+}
+
+MixedSubstitutionModelSet::MixedSubstitutionModelSet(const SubstitutionModelSet& set) :
+  SubstitutionModelSet(set),
+  vpHyperNodes_()
+{}
+
+MixedSubstitutionModelSet::~MixedSubstitutionModelSet()
+{
+  for (size_t i = 0; i < vpHyperNodes_.size(); i++)
+  {
+    delete vpHyperNodes_[i];
+  }
+}
+
+void MixedSubstitutionModelSet::clear()
+{
+  SubstitutionModelSet::clear();
+  for (size_t i = 0; i < vpHyperNodes_.size(); i++)
+  {
+    delete vpHyperNodes_[i];
+  }
+}
+
+MixedSubstitutionModelSet& MixedSubstitutionModelSet::operator=(const MixedSubstitutionModelSet& set)
+{
+  SubstitutionModelSet::operator=(set);
+  for (size_t i = 0; i < vpHyperNodes_.size(); i++)
+  {
+    if (vpHyperNodes_[i] != NULL)
+      delete vpHyperNodes_[i];
+  }
+  vpHyperNodes_.clear();
+
+  for (size_t i = 0; i < set.vpHyperNodes_.size(); i++)
+  {
+    vpHyperNodes_.push_back(new HyperNode(*set.vpHyperNodes_[i]));
+  }
+
+  return *this;
+}
+
+void MixedSubstitutionModelSet::addEmptyHyperNode()
+{
+  vpHyperNodes_.push_back(new HyperNode(this));
+}
+
+void MixedSubstitutionModelSet::addHyperNode(const HyperNode& hn)
+{
+  vpHyperNodes_.push_back(new HyperNode(hn));
+}
+
+bool MixedSubstitutionModelSet::complete()
+{
+  MixedSubstitutionModelSet::HyperNode nhn(this);
+  size_t i;
+  for (i = 0; i < vpHyperNodes_.size(); i++)
+  {
+    nhn += *vpHyperNodes_[i];
+  }
+
+  size_t nbm = getNumberOfModels();
+  for (i = 0; i < nbm; i++)
+  {
+    const MixedSubstitutionModel* pSM = dynamic_cast<const MixedSubstitutionModel*>(getModel(i));
+    if (pSM)
+    {
+      if (nhn.getNode(i).size() != pSM->getNumberOfModels())
+        break;
+    }
+  }
+
+  if (i == nbm)
+    return false;
+
+  addEmptyHyperNode();
+  for (i = 0; i < nbm; i++)
+  {
+    const MixedSubstitutionModel* pSM = dynamic_cast<const MixedSubstitutionModel*>(getModel(i));
+    if (pSM)
+    {
+      const MixedSubstitutionModelSet::HyperNode::Node& nd = nhn.getNode(i);
+      int snd = static_cast<int>(nd.size());
+      int vs = static_cast<int>(pSM->getNumberOfModels());
+      Vint an;
+
+      int j(0), k(0);
+      while (j < vs)
+      {
+        while ((k < snd) && (nd[k] < j))
+          k++;
+        if ((k >= snd) || (nd[k] > j))
+          an.push_back(j);
+        j++;
+      }
+      addToHyperNode(i, an);
+    }
+  }
+
+  return true;
+}
+
+void MixedSubstitutionModelSet::addToHyperNode(size_t nM, const Vint& vnS, int nH)
+{
+  if (nH >= static_cast<int>(vpHyperNodes_.size()))
+    throw BadIntegerException("MixedSubstitutionModelSet::addToHyperNode. Bad HyperNode number", nH);
+  if (nH < 0)
+    nH = static_cast<int>(vpHyperNodes_.size() - 1);
+
+  if (nM >= getNumberOfModels())
+    throw IndexOutOfBoundsException("MixedSubstitutionModelSet::addToHyperNode. Bad Mixed Model number", nM, 0, getNumberOfModels());
+
+  vpHyperNodes_[nH]->addToModel(nM, vnS);
+}
+
+bool MixedSubstitutionModelSet::hasExclusivePaths() const
+{
+  HyperNode tthn(this);
+
+  size_t nhn = getNumberOfHyperNodes();
+  for (size_t i = 0; i < nhn; i++)
+  {
+    if (tthn.intersects(getHyperNode(i)))
+      return false;
+    else
+      tthn += getHyperNode(i);
+  }
+
+  return true;
+}
+
+void MixedSubstitutionModelSet::fireParameterChanged(const ParameterList& parameters)
+{
+  SubstitutionModelSet::fireParameterChanged(parameters);
+
+  // should be restricted only when probability related parameters are changed
+  computeHyperNodesProbabilities();
+}
+
+
+void MixedSubstitutionModelSet::computeHyperNodesProbabilities()
+{
+  size_t nbm = getNumberOfModels();
+
+  // Looking for the first Mixed model
+
+  size_t fmM = 0;
+
+  MixedSubstitutionModel* pfSM = 0;
+  for (fmM = 0; fmM < nbm; fmM++)
+  {
+    pfSM = dynamic_cast<MixedSubstitutionModel*>(getModel(fmM));
+    if (pfSM != NULL)
+      break;
+  }
+  if (fmM == nbm)
+    return;
+
+  // Compute the probabilities of the hypernodes from the first mixed
+  // model
+
+  size_t nbh = getNumberOfHyperNodes();
+
+
+  for (size_t nh = 0; nh < nbh; nh++)
+  {
+    MixedSubstitutionModelSet::HyperNode& h = getHyperNode(nh);
+    const MixedSubstitutionModelSet::HyperNode::Node& fnd = h.getNode(fmM);
+
+    double fprob = 0;
+    for (size_t i = 0; i < fnd.size(); i++)
+    {
+      fprob += pfSM->getNProbability(fnd[i]);
+    }
+    h.setProbability(fprob);
+  }
+
+  // Sets the new probabilities & rates of the mixmodels
+
+  for (size_t iM = fmM + 1; iM < nbm; iM++)
+  {
+    pfSM = dynamic_cast<MixedSubstitutionModel*>(getModel(iM));
+    if (pfSM != NULL)
+    {
+      for (size_t nh = 0; nh < nbh; nh++)
+      {
+        MixedSubstitutionModelSet::HyperNode& h = getHyperNode(nh);
+        const MixedSubstitutionModelSet::HyperNode::Node& fnd = h.getNode(iM);
+        double prob = 0;
+        for (size_t j = 0; j < fnd.size(); j++)
+        {
+          prob += pfSM->getNProbability(fnd[j]);
+        }
+
+        // sets the real probabilities
+        for (size_t j = 0; j < fnd.size(); j++)
+        {
+          pfSM->setNProbability(fnd[j], h.getProbability() * pfSM->getNProbability(fnd[j]) / prob);
+        }
+      }
+
+      // normalizes Vrates with the real probabilities
+
+      pfSM->normalizeVRates();
+
+      // sets the conditional probabilities
+
+      for (size_t nh = 0; nh < nbh; nh++)
+      {
+        MixedSubstitutionModelSet::HyperNode& h = getHyperNode(nh);
+        const MixedSubstitutionModelSet::HyperNode::Node& fnd = h.getNode(iM);
+        for (size_t j = 0; j < fnd.size(); j++)
+        {
+          pfSM->setNProbability(fnd[j], pfSM->getNProbability(fnd[j]) / h.getProbability());
+        }
+      }
+    }
+  }
+}
+
+double MixedSubstitutionModelSet::getHyperNodeProbability(const HyperNode& hn) const
+{
+  size_t nbm = getNumberOfModels();
+  double fprob = 1;
+
+  for (size_t fmM = 0; fmM < nbm; fmM++)
+  {
+    const MixedSubstitutionModelSet::HyperNode::Node& fnd = hn.getNode(fmM);
+    const MixedSubstitutionModel* pfSM = dynamic_cast<const MixedSubstitutionModel*>(getModel(fmM));
+    if (pfSM != NULL)
+    {
+      double x = 0;
+
+      for (size_t i = 0; i < fnd.size(); i++)
+      {
+        x += pfSM->getNProbability(fnd[i]);
+      }
+
+      fprob *= x;
+    }
+  }
+
+  return fprob;
+}
+
+/**********************************************************/
+/*************** HYPERNODE ********************************/
+/***********************************************************/
+
+
+MixedSubstitutionModelSet::HyperNode::HyperNode(const MixedSubstitutionModelSet* pMSMS) : vNumbers_(pMSMS->getNumberOfModels()),
+  vUnused_(),
+  proba_(1)
+{
+  for (size_t i = 0; i < pMSMS->getNumberOfModels(); i++)
+  {
+    const MixedSubstitutionModel* pSM = dynamic_cast<const MixedSubstitutionModel*>(pMSMS->getModel(i));
+    if (!pSM)
+      vUnused_.push_back(static_cast<int>(i));
+  }
+}
+
+MixedSubstitutionModelSet::HyperNode::HyperNode(const HyperNode& hn) : vNumbers_(hn.vNumbers_),
+  vUnused_(hn.vUnused_),
+  proba_(hn.proba_)
+{}
+
+
+MixedSubstitutionModelSet::HyperNode& MixedSubstitutionModelSet::HyperNode::operator=(const MixedSubstitutionModelSet::HyperNode& hn)
+{
+  vNumbers_.clear();
+  vNumbers_.resize(hn.vNumbers_.size());
+  for (size_t i = 0; i < hn.vNumbers_.size(); i++)
+  {
+    vNumbers_[i] = hn.vNumbers_[i];
+  }
+  vUnused_.clear();
+  vUnused_.resize(hn.vUnused_.size());
+  for (size_t i = 0; i < hn.vUnused_.size(); i++)
+  {
+    vUnused_[i] = hn.vUnused_[i];
+  }
+
+  proba_ = hn.proba_;
+
+  return *this;
+}
+
+void MixedSubstitutionModelSet::HyperNode::addToModel(size_t nM, const Vint& vnS)
+{
+  if (nM >= vNumbers_.size())
+    throw IndexOutOfBoundsException("MixedSubstitutionModelSet::HyperNode::addToModel. Bad Mixed model Number", nM, 0, vNumbers_.size());
+
+  vNumbers_[nM].insertN(vnS);
+}
+
+void MixedSubstitutionModelSet::HyperNode::setModel(size_t nM, const Vint& vnS)
+{
+  if (nM >= vNumbers_.size())
+    throw IndexOutOfBoundsException("MixedSubstitutionModelSet::HyperNode::setModel. Bad Mixed model Number", nM, 0, vNumbers_.size());
+
+  vNumbers_[nM] = vnS;
+}
+
+bool MixedSubstitutionModelSet::HyperNode::isComplete() const
+{
+  int k;
+  int vUs = (int)vUnused_.size();
+  for (int i = 0; i < (int)vNumbers_.size(); i++)
+  {
+    for (k = 0; k < vUs; k++)
+    {
+      if (vUnused_[k] == i)
+        break;
+    }
+    if ((k == vUs) && vNumbers_[i].size() == 0)
+      return false;
+  }
+  return true;
+}
+
+bool MixedSubstitutionModelSet::HyperNode::operator<=(const HyperNode& hn) const
+{
+  for (size_t i = 0; i < vNumbers_.size(); i++)
+  {
+    if (!( vNumbers_[i] <= hn.vNumbers_[i]))
+      return false;
+  }
+
+  return true;
+}
+
+bool MixedSubstitutionModelSet::HyperNode::intersects(const HyperNode& hn) const
+{
+  for (size_t i = 0; i < vNumbers_.size(); i++)
+  {
+    if (vNumbers_[i].intersects(hn.vNumbers_[i]))
+      return true;
+  }
+
+  return false;
+}
+
+bool MixedSubstitutionModelSet::HyperNode::operator>=(const HyperNode& hn) const
+{
+  return hn >= *this;
+}
+
+MixedSubstitutionModelSet::HyperNode& MixedSubstitutionModelSet::HyperNode::operator+=(const HyperNode& hn)
+{
+  for (size_t i = 0; i < vNumbers_.size(); i++)
+  {
+    vNumbers_[i] += hn.vNumbers_[i];
+  }
+
+  return *this;
+}
+
+/**********************************************************/
+/******************** NODE ********************************/
+/***********************************************************/
+
+void MixedSubstitutionModelSet::HyperNode::Node::insertN(const Vint& vn)
+{
+  vector<int>::iterator it;
+  vector<int>::const_iterator it2;
+
+  for (it2 = vn.begin(); it2 != vn.end(); it2++)
+  {
+    for (it = vNumb_.begin(); it != vNumb_.end(); it++)
+    {
+      if (*it >= *it2)
+        break;
+    }
+    if (it == vNumb_.end())
+      vNumb_.push_back(*it2);
+    else if (*it != *it2)
+      vNumb_.insert(it, *it2);
+  }
+}
+
+MixedSubstitutionModelSet::HyperNode::Node& MixedSubstitutionModelSet::HyperNode::Node::operator+=(const Node& n)
+{
+  insertN(n.vNumb_);
+
+  return *this;
+}
+
+bool MixedSubstitutionModelSet::HyperNode::Node::operator<=(const Node& n) const
+{
+  vector<int>::const_iterator it(vNumb_.begin());
+  vector<int>::const_iterator it2(n.vNumb_.begin());
+
+  for ( ; it != vNumb_.end(); it++)
+  {
+    while (it2 != n.vNumb_.end()  && (*it2 < *it))
+      it2++;
+    if (it2 == n.vNumb_.end() || (*it2 > *it))
+      return false;
+    it++;
+  }
+  return true;
+}
+
+bool MixedSubstitutionModelSet::HyperNode::Node::operator>=(const Node& n) const
+{
+  return n <= *this;
+}
+
+bool MixedSubstitutionModelSet::HyperNode::Node::intersects(const Node& n) const
+{
+  vector<int>::const_iterator it(vNumb_.begin());
+  vector<int>::const_iterator it2(n.vNumb_.begin());
+
+  for ( ; it != vNumb_.end(); it++)
+  {
+    while (it2 != n.vNumb_.end()  && (*it2 < *it))
+      it2++;
+
+    if (it2 == n.vNumb_.end())
+      return false;
+    if (*it2 == *it)
+      return true;
+    it++;
+  }
+  return false;
+}
+
diff --git a/src/Bpp/Phyl/Model/MixedSubstitutionModelSet.h b/src/Bpp/Phyl/Model/MixedSubstitutionModelSet.h
new file mode 100644
index 0000000..af90dc6
--- /dev/null
+++ b/src/Bpp/Phyl/Model/MixedSubstitutionModelSet.h
@@ -0,0 +1,400 @@
+//
+// File: MixedSubstitutionModelSet.h
+// Created by: Laurent Guéguen
+// Created on: mercredi 25 mai 2011, à 22h 04
+//
+
+/*
+   Copyright or (c) or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _MIXEDSUBSTITUTIONMODELSET_H_
+#define _MIXEDSUBSTITUTIONMODELSET_H_
+
+
+#include "SubstitutionModelSet.h"
+#include "AbstractSubstitutionModel.h"
+
+#include <Bpp/Exceptions.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+namespace bpp
+{
+  /**
+   * @brief Substitution models manager for Mixed Substitution Models.
+   * This class inherits from SubstitutionModelSet.
+   *
+   * This class is done to handle specific cases of choices among the
+   * submodels of mixed substitution models. Each branch of the tree
+   * is labelled by a mixed model, and a site may be restricted to a
+   * set of submodels it is allowed to follow. These sets are defined
+   * through an hypergrap, ie a list of hypernodes.
+   *
+   * For example, suppose there are 3 mixed models (M1,M2 and M3),
+   * with 2, 3, 4 submodels (S1, S2, ...) each.
+   *
+   * If the sites are allowed to follow any combination of submodels
+   * (12 combinations) the corresponding hypergraph has only one
+   * hypernode: (<1,2>,<1,2,3>,<1,2,3,4>).
+   *
+   * The hypergraph with hypernodes
+   * ((<1>,<1,2>,<1,2>),(<2>,<3>,<3,4>)) means that a site either
+   * follows 6 combinations:
+   *
+   * M1:S1, M2:S1 or M2:S2, and M3:S1 or M3:S2.
+   *
+   * or
+   *
+   * M1:S2, M2:S3, and M3:S3 or M3:S4.
+   *
+   *
+   * Actually, additional coordinates are set when there are non mixed
+   * models, with no value in them, and not used in practice.
+   *
+   * An hypernode is valid only if each mixed model is represented at
+   * least by one submodel.
+   *
+   * Dependency of the submodels entails constraints in the
+   * probabilities of the submodels, and definition of the hypernodes
+   * must be taken with care for the whole modelling to be possible.
+   *
+   *
+   *
+   * In this implementation, for sake of simplification (and for
+   * reason of time), all the submodels must belong to exactly one
+   * given hypernode, but in theory more complex dependencies are 
+   * possible.
+   *
+   * Concerning the probabilities of the submodels in each hypernode,
+   * the first coordinate (ie set of submodels inside a mixed model)
+   * in the list defines the probability of each hypernode. For each
+   * coordinate (the first included), when there are several
+   * submodels, their probabilities are conditional probabilities,
+   * which means that they sum 1 and their ratio are unchanged.
+   *
+   * For instance, for hypergraph ((<1>,<1,2>,<1,2>),(<2>,<3>,<3,4>)),
+   * the probabilities of hypernodes are the probabilities of M1:S1
+   * and M1:S2. In the first hypernode, the probabilities of M2:S1 and
+   * M2:S2 are P(M2:S1)/(P(M2:S1)+P(M2:S2)) and
+   * P(M2:S2)/(P(M2:S1)+P(M2:S2)).
+   *
+   * We do not certify that the probability parameters of the mixed
+   * models are all useful, and then identifiability problems may be
+   * encountered. 
+   *
+   * There is a method ("complete") that creates an additional
+   * hypernode to ensure that all submodels belong to at least an
+   * hypernode.
+   * 
+   *
+   */
+  
+  class MixedSubstitutionModelSet :
+    public SubstitutionModelSet
+  {
+  public:
+     class HyperNode
+     {
+     public: 
+       class Node {
+
+         /**
+          * A vector<int> where all elements are different and in
+          * increasing order.
+          *
+          */
+
+         Vint vNumb_;
+
+       public:
+         Node() : vNumb_() {};
+         Node(const Node& n): vNumb_(n.vNumb_){};
+         Node& operator=(const Node& n){
+           vNumb_=n.vNumb_;
+           return *this;
+         }
+         
+         ~Node(){};
+
+         Node& operator=(const Vint& n) {
+           vNumb_=n;
+           return *this;
+         }
+
+         void insertN(const Vint& vn);
+
+         size_t size() const{
+           return vNumb_.size();
+         }
+
+         /*
+          *@brief Cumulates the elements of the given Node into this one.
+          *
+          */
+
+         Node& operator+=(const Node&);
+         
+         /*
+          *@brief checks if this Node is included in another one.
+          *
+          */
+
+         bool operator<=(const Node&) const;
+
+         /*
+          *@brief checks if this HyperNode includes another one.
+          *
+          */
+
+         bool operator>=(const Node&) const;
+
+         /*
+          *@brief checks if this Node intersects another one.
+          *
+          */
+       
+         bool intersects(const Node&) const;
+
+         int operator[](size_t i) const { return vNumb_[i]; }
+
+       };
+
+     private:
+       
+       std::vector<Node> vNumbers_;
+
+       /*
+        *@brief the coordinates of the Nodes that are not used.
+        *
+        */
+       
+       Vint vUnused_;
+
+       /*
+        *@brief probability of this HyperNode.
+        *
+        */
+
+       double proba_;
+       
+     public:
+       HyperNode(const MixedSubstitutionModelSet*);
+       HyperNode(const HyperNode&);
+       HyperNode& operator=(const HyperNode&);
+       ~HyperNode(){};
+
+       /*
+        *@brief sets submodel numbers in the nMth mixed model. Checks
+        *  if all the numbers are valid.
+        *
+        *@param nM number of the mixed model
+        *@param vnS vector of numbers of the submodel
+        */
+    
+       void setModel(size_t nM, const Vint& vnS);
+
+       /*
+        *@brief adds submodel numbers to the nMth mixed model. Checks
+        *  if all the numbers are valid.
+        *
+        *@param nM number of the mixed model
+        *@param vnS vector of numbers of the submodel
+        */
+    
+       void addToModel(size_t nM, const Vint& vnS);
+       /*
+        *@brief Cumulates the Nodes of the given HyperNode into this one.
+        *
+        */
+
+       HyperNode& operator+=(const HyperNode&);
+         
+       /*
+        *@brief checks if this HyperNode is included in another one.
+        *
+        */
+       
+       bool operator<=(const HyperNode&) const;
+
+       /*
+        *@brief checks if this HyperNode includes at least a submodel of each mixed model
+        *
+        */
+       bool isComplete() const;
+       /*
+        *@brief checks if this HyperNode includes another one.
+        *
+        */
+       bool operator>=(const HyperNode&) const;
+
+       /*
+        *@brief checks if this HyperNode intersects another one.
+        *
+        */       
+       bool intersects(const HyperNode&) const;
+
+       /*
+        *@brief returns the probability
+        *
+        */
+
+       double getProbability() const {return proba_;}
+
+       /*
+        *@brief sets the probability
+        *
+        */
+
+       void setProbability(double x) { proba_ = x; }
+       
+       const Node& getNode(size_t i) const { return vNumbers_[i]; }
+
+     };
+
+  private:
+    
+    std::vector<HyperNode*> vpHyperNodes_;
+
+  public:
+    /**
+     * @brief Create a model set according to the specified alphabet.
+     *
+     * @param alpha The alphabet to use for this set.
+     */
+    MixedSubstitutionModelSet(const Alphabet* alpha): 
+      SubstitutionModelSet(alpha), vpHyperNodes_() {}
+    
+    ~MixedSubstitutionModelSet();
+    
+    MixedSubstitutionModelSet(const MixedSubstitutionModelSet& set);
+    
+    MixedSubstitutionModelSet(const SubstitutionModelSet& set);
+
+    MixedSubstitutionModelSet& operator=(const MixedSubstitutionModelSet& set);
+    
+#ifndef NO_VIRTUAL_COV
+    MixedSubstitutionModelSet*
+#else
+    Clonable*
+#endif
+    clone() const { return new MixedSubstitutionModelSet(*this); }
+
+    /**
+     * @brief Resets the list of the HyperNodes
+     */
+    
+    void clear();
+
+    /*
+     *@brief adds a new empty HyperNode to the end of the HyperNodes
+     * list.
+     */
+    
+    void addEmptyHyperNode();
+
+    /*
+     *@brief adds the copy of an HyperNode to the end of the
+     * HyperNodes list.
+     */
+    
+    void addHyperNode(const HyperNode& hn);
+
+    /*
+     *@brief If necessary, adds a new HyperNode such that all
+     *       submodels of the mixture models are at least in an
+     *       HyperNode.
+     *
+     * Returns true iff a new path has been built.
+     * 
+     */
+
+    bool complete();
+    
+    /*
+     *@brief adds a submodel number to the nMth mixed model of the
+     *  nHth HyperNode of the list (default nH=0). Checks if all the
+     *  numbers are valid.
+     *
+     *@param nM number of the mixed model
+     *@param vnS number of the submodel
+     *@param nH number of the concerned HyperNode (default the last element of
+     *     the list)
+     */
+    
+    void addToHyperNode(size_t nM, const Vint& vnS, int nH = -1);
+
+    size_t getNumberOfHyperNodes() const{ return vpHyperNodes_.size();}
+
+    HyperNode& getHyperNode(size_t i) {return *vpHyperNodes_[i];} 
+
+    const HyperNode& getHyperNode(size_t i) const {return *vpHyperNodes_[i];} 
+
+    /*
+     *@brief Checks if all the path (ie hypernodes) are exclusive.
+     *
+     */
+    
+    bool hasExclusivePaths() const;
+
+    void fireParameterChanged(const ParameterList& parameters);
+
+    /*
+     *@brief compute the probabilities in all the HyperNodes
+     *
+     */
+
+    void computeHyperNodesProbabilities();
+
+    /*
+     *@brief computes the probability of an HyperNode, given
+     *     the conditional probabilities of the submodels computed
+     *     from the hypernodes of this MixedSubstitutionModelSet
+     *     object. If the HyperNode does not match the structure of
+     *     allowed by this MixedSubstitutionModelSet, an Exception
+     *     is thrown.
+     *
+     *     The probability of an HyperNode is the product -- on the
+     *     set of the mixed models -- of the sums of the
+     *     conditional probabilities of the submodels that belon to
+     *     this hypernode for each mixed model.
+     *
+     *@param hn the HyperNode which conditional probability is computed.
+     */
+
+    double getHyperNodeProbability(const HyperNode& hn) const;
+
+  };
+  
+} // end of namespace bpp.
+
+#endif // _MIXEDSUBSTITUTIONMODELSET_H_
+
diff --git a/src/Bpp/Phyl/Model/MixtureOfASubstitutionModel.cpp b/src/Bpp/Phyl/Model/MixtureOfASubstitutionModel.cpp
new file mode 100644
index 0000000..f3cd0a3
--- /dev/null
+++ b/src/Bpp/Phyl/Model/MixtureOfASubstitutionModel.cpp
@@ -0,0 +1,325 @@
+//
+// File: MixtureOfASubstitutionModel.cpp
+// Created by: David Fournier, Laurent Gueguen
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "MixtureOfASubstitutionModel.h"
+
+#include <Bpp/Numeric/NumConstants.h>
+
+#include <Bpp/Numeric/Prob/ConstantDistribution.h>
+
+#include <Bpp/Exceptions.h>
+
+#include <string>
+
+using namespace bpp;
+using namespace std;
+
+
+MixtureOfASubstitutionModel::MixtureOfASubstitutionModel(
+  const Alphabet* alpha,
+  SubstitutionModel* model,
+  std::map<std::string, DiscreteDistribution*> parametersDistributionsList,
+  int ffrom,
+  int tto) throw (Exception) :
+  AbstractParameterAliasable(model->getNamespace()),
+  AbstractMixedSubstitutionModel(alpha, model->getNamespace()),
+  distributionMap_(),
+  from_(ffrom),
+  to_(tto)
+{
+  if (to_ >= int(alpha->getSize()))
+    throw BadIntegerException("Bad state in alphabet", to_);
+  if (from_ >= int(alpha->getSize()))
+    throw BadIntegerException("Bad state in alphabet", from_);
+
+  size_t c, i;
+  string s1, s2, t;
+  map<string, DiscreteDistribution*>::iterator it;
+
+  // Initialization of distributionMap_.
+
+  vector<string> parnames = model->getParameters().getParameterNames();
+
+  for (i = 0; i < model->getNumberOfParameters(); i++)
+  {
+    s1 = parnames[i];
+    s2 = model->getParameterNameWithoutNamespace(s1);
+
+    if (parametersDistributionsList.find(s2) != parametersDistributionsList.end())
+      distributionMap_[s1] = parametersDistributionsList.find(s2)->second->clone();
+    else
+      distributionMap_[ s1] = new ConstantDistribution(model->getParameterValue(s2));
+
+
+    if (dynamic_cast<ConstantDistribution*>(distributionMap_[s1]) == 0)
+      distributionMap_[s1]->setNamespace(s1 + "_" + distributionMap_[s1]->getNamespace());
+    else
+      distributionMap_[s1]->setNamespace(s1 + "_");
+  }
+
+  // Initialization of modelsContainer_.
+
+  c = 1;
+
+  for (it = distributionMap_.begin(); it != distributionMap_.end(); it++)
+  {
+    c *= it->second->getNumberOfCategories();
+  }
+
+  for (i = 0; i < c; i++)
+  {
+    modelsContainer_.push_back(model->clone());
+    modelsContainer_[i]->addRateParameter();
+    modelsContainer_[i]->setNamespace(model->getNamespace());
+
+    vProbas_.push_back(1.0 / static_cast<double>(c));
+    vRates_.push_back(1.0);
+  }
+
+  // Initialization of parameters_.
+
+  Parameter pm;
+  DiscreteDistribution* pd;
+
+  for (it = distributionMap_.begin(); it != distributionMap_.end(); it++)
+  {
+    pm = model->getParameter(model->getParameterNameWithoutNamespace(getParameterNameWithoutNamespace(it->first)));
+    pd = it->second;
+
+    if (pm.hasConstraint())
+      pd->restrictToConstraint(*pm.getConstraint());
+
+    if (!dynamic_cast<ConstantDistribution*>(it->second))
+    {
+      const ParameterList pl = pd->getParameters();
+      for (i = 0; i != it->second->getNumberOfParameters(); i++)
+      {
+        addParameter_(pl[i].clone());
+      }
+    }
+    else
+      addParameter_(new Parameter(it->first, pd->getCategory(0), (pd->getParameter("value").getConstraint()) ? pd->getParameter("value").getConstraint()->clone() : 0, true));
+  }
+  updateMatrices();
+}
+
+MixtureOfASubstitutionModel::MixtureOfASubstitutionModel(const MixtureOfASubstitutionModel& msm) :
+  AbstractParameterAliasable(msm),
+  AbstractMixedSubstitutionModel(msm),
+  distributionMap_(),
+  from_(msm.from_),
+  to_(msm.to_)
+{
+  map<string, DiscreteDistribution*>::const_iterator it;
+
+  for (it = msm.distributionMap_.begin(); it != msm.distributionMap_.end(); it++)
+  {
+    distributionMap_[it->first] = it->second->clone();
+  }
+}
+
+MixtureOfASubstitutionModel& MixtureOfASubstitutionModel::operator=(const MixtureOfASubstitutionModel& msm)
+{
+  AbstractParameterAliasable::operator=(msm);
+  AbstractMixedSubstitutionModel::operator=(msm);
+  from_ = msm.from_;
+  to_ = msm.to_;
+
+  // Clear existing containers:
+  distributionMap_.clear();
+
+  // Now copy new containers:
+  map<string, DiscreteDistribution*>::const_iterator it;
+  for (it = msm.distributionMap_.begin(); it != msm.distributionMap_.end(); it++)
+  {
+    distributionMap_[it->first] = it->second->clone();
+  }
+  return *this;
+}
+
+
+MixtureOfASubstitutionModel::~MixtureOfASubstitutionModel()
+{
+  map<string, DiscreteDistribution*>::iterator it;
+
+  for (it = distributionMap_.begin(); it != distributionMap_.end(); it++)
+  {
+    delete it->second;
+  }
+}
+
+const DiscreteDistribution* MixtureOfASubstitutionModel::getDistribution(std::string& parName) const
+{
+  if (distributionMap_.find(parName)!=distributionMap_.end())
+    return distributionMap_.find(parName)->second;
+  else
+    return NULL;
+}
+
+void MixtureOfASubstitutionModel::updateMatrices()
+{
+  string s, t;
+  size_t i, j, l;
+  double d;
+  ParameterList pl;
+  map<string, DiscreteDistribution*>::iterator it;
+
+  // Update of distribution parameters from the parameters_ member
+  // data. (reverse operation compared to what has been done in the
+  // constructor).
+  //  vector<string> v=getParameters().getParameterNames();
+
+  for (it = distributionMap_.begin(); it != distributionMap_.end(); it++)
+  {
+    if (dynamic_cast<ConstantDistribution*>(it->second) == NULL)
+    {
+      vector<string> vDistnames = it->second->getParameters().getParameterNames();
+      for (i = 0; i < it->second->getNumberOfParameters(); i++)
+      {
+        d = getParameterValue(getParameterNameWithoutNamespace(vDistnames[i]));
+        pl.addParameter(Parameter(vDistnames[i], d));
+      }
+      it->second->matchParametersValues(pl);
+      pl.reset();
+    }
+    else
+    {
+      t = it->second->getNamespace();
+      d = getParameter(getParameterNameWithoutNamespace(t.substr(0, t.length() - 1))).getValue();
+      it->second->setParameterValue("value", d);
+    }
+  }
+
+  for (i = 0; i < modelsContainer_.size(); i++)
+  {
+    vProbas_[i] = 1;
+    j = i;
+    for (it = distributionMap_.begin(); it != distributionMap_.end(); it++)
+    {
+      s = it->first;
+      l = j % it->second->getNumberOfCategories();
+
+      d = it->second->getCategory(l);
+      vProbas_[i] *= it->second->getProbability(l);
+      if (pl.hasParameter(s))
+        pl.setParameterValue(s, d);
+      else
+        pl.addParameter(Parameter(s, d));
+
+      j = j / it->second->getNumberOfCategories();
+    }
+
+    modelsContainer_[i]->matchParametersValues(pl);
+  }
+
+  //  setting the equilibrium freqs
+  for (i = 0; i < getNumberOfStates(); i++)
+  {
+    freq_[i] = 0;
+    for (j = 0; j < modelsContainer_.size(); j++)
+    {
+      freq_[i] += vProbas_[j] * modelsContainer_[j]->freq(i);
+    }
+  }
+
+  // setting the rates, if to_ & from_ are different from -1
+
+  if (to_ >= 0 && from_ >= 0)
+  {
+    Vdouble vd;
+
+    for (j = 0; j < modelsContainer_.size(); j++)
+    {
+      vd.push_back(1 / getNModel(j)->Qij(from_, to_));
+    }
+
+    setVRates(vd);
+  }
+}
+
+void MixtureOfASubstitutionModel::setFreq(std::map<int, double>& m)
+{
+  modelsContainer_[0]->setFreq(m);
+  matchParametersValues(modelsContainer_[0]->getParameters());
+}
+
+Vint MixtureOfASubstitutionModel::getSubmodelNumbers(string& desc) const
+{
+  vector<string> parnames = modelsContainer_[0]->getParameters().getParameterNames();
+  std::map<std::string, size_t> msubn;
+  map<string, DiscreteDistribution*>::const_iterator it;
+
+  StringTokenizer st(desc, ",");
+  while (st.hasMoreToken())
+  {
+    string param = st.nextToken();
+    string::size_type index = param.rfind("_");
+    if (index == string::npos)
+      throw Exception("MixtureOfASubstitutionModel::getSubmodelNumbers parameter description should contain a number" + param);
+    msubn[param.substr(0, index)] = TextTools::toInt(param.substr(index + 1, 4)) - 1;
+  }
+
+  Vint submodnb;
+  size_t i, j, l;
+  string s;
+
+  bool nameok=false;
+  
+  for (i = 0; i < modelsContainer_.size(); i++)
+  {
+    j = i;
+    for (it = distributionMap_.begin(); it != distributionMap_.end(); it++)
+    {
+      s = it->first;
+      l = j % it->second->getNumberOfCategories();
+
+      if (msubn.find(s) != msubn.end()){
+        nameok = true;
+        if (msubn[s] != l)
+          break;
+      }
+      
+      j = j / it->second->getNumberOfCategories();
+    }
+    if (nameok && it == distributionMap_.end())
+      submodnb.push_back(static_cast<int>(i));
+  }
+
+  return submodnb;
+}
+
diff --git a/src/Bpp/Phyl/Model/MixtureOfASubstitutionModel.h b/src/Bpp/Phyl/Model/MixtureOfASubstitutionModel.h
new file mode 100644
index 0000000..889c7a9
--- /dev/null
+++ b/src/Bpp/Phyl/Model/MixtureOfASubstitutionModel.h
@@ -0,0 +1,169 @@
+//
+// File: MixtureOfASubstitutionModel.h
+// Created by: David Fournier, Laurent Gueguen
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _MIXTUREOFASUBSTITUTIONMODEL_H_
+#define _MIXTUREOFASUBSTITUTIONMODEL_H_
+
+#include "AbstractMixedSubstitutionModel.h"
+
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+#include <vector>
+#include <string>
+#include <map>
+#include <cstring> // C lib for string copy
+
+namespace bpp
+{
+/**
+ * @brief Substitution models defined as a mixture of nested
+ * substitution models.
+ * @author Laurent Guéguen
+ *
+ * All the nested models are of the same type (for example T92 or
+ * GY94), and their parameter values can follow discrete
+ * distributions.
+ *
+ * In this kind of model, there is no generator.
+ *
+ * There is a map with connection from parameter names to discrete
+ * distributions, and then a related vector of "simple" substitution
+ * models for all the combinations of parameter values.
+ *
+ * For example:
+ * HKY85(kappa=Gamma(n=3,alpha=2,beta=5),
+ *       theta=TruncExponential(n=4,lambda=0.2,tp=1),
+ *       theta1=0.4,
+ *       theta2=TruncExponential(n=5,lambda=0.6,tp=1))
+ *
+ * defines 3*4*5=60 different HKY85 nested models with rate one.
+ *
+ * Optionnal arguments are used to homogeneize the rates of the nested
+ * models. Default values sets all the rates to 1, and given values
+ * are the two letters (from_ & to_) between which the substitution
+ * rates are the same in all nested models.
+ *
+ * For example:
+ * HKY85(kappa=Gamma(n=3,alpha=2,beta=5),
+ *       theta=TruncExponential(n=4,lambda=0.2,tp=1),
+ *       theta1=0.4,
+ *       theta2=TruncExponential(n=5,lambda=0.6,tp=1),
+ *       from=A, to=C)
+ *
+ * defines 3*4*5=60 different HKY85 nested models with the same A->C
+ * substitution rate.
+ *
+ * If a distribution parameter does not respect the constraints of
+ * this parameter, there is an Exception at the creation of the
+ * wrong model, if any.
+ *
+ * When used through a MixedTreeLikelihood objets, all the models have
+ * a specific probability, defined through the probabilities of the
+ * several parameter distributions. The computing of the likelihoods
+ * and probabilities are the expectation of the "simple" models
+ * values.
+ *
+ */
+class MixtureOfASubstitutionModel :
+  public AbstractMixedSubstitutionModel
+{
+private:
+  std::map<std::string, DiscreteDistribution*> distributionMap_;
+  int from_, to_;
+  
+public:
+  MixtureOfASubstitutionModel(const Alphabet* alpha,
+                              SubstitutionModel* model,
+                              std::map<std::string, DiscreteDistribution*> parametersDistributionsList,
+                              int ffrom=-1, int tto=-1) throw(Exception);
+
+  MixtureOfASubstitutionModel(const MixtureOfASubstitutionModel&);
+  
+  MixtureOfASubstitutionModel& operator=(const MixtureOfASubstitutionModel&);
+
+  ~MixtureOfASubstitutionModel();
+
+  MixtureOfASubstitutionModel* clone() const { return new MixtureOfASubstitutionModel(*this); }
+
+public:
+  std::string getName() const { return "MixedModel"; }
+
+  void updateMatrices();
+
+  /*
+   *@brief Returns the vector of numbers of the submodels in the
+   *mixture that match a description of the parameters numbers.
+   *
+   *@param desc is the description of the class indexes of the mixed
+   *parameters. Syntax is like: kappa_1,gamma_3,delta_2
+   *
+   */
+  
+  Vint getSubmodelNumbers(std::string& desc) const;
+
+  /**
+   * @brief sets the eq frequencies of the first nested model, and
+   * adapts the parameters at best to it (surely there is a better way
+   * to manage this).
+   *
+   */
+
+  void setFreq(std::map<int,double>&);
+
+  /**
+   * @brief returns the DiscreteDistribution associated with a given
+   * parameter name.
+   * @param parName name of the parameter
+   **/
+
+  const DiscreteDistribution* getDistribution(std::string& parName) const;
+
+  /**
+   *@brief Numbers of the states between which the substitution rates
+   *of all the submodels must be equal. If they are set to -1, this
+   *constraint does not exist among the submodels.
+   *
+   */
+  
+  int from() const { return from_;}
+  int to() const { return to_;}
+};
+} // end of namespace bpp.
+
+#endif  // _MIXTUREOFASUBSTITUTIONMODEL_H_
diff --git a/src/Bpp/Phyl/Model/MixtureOfSubstitutionModels.cpp b/src/Bpp/Phyl/Model/MixtureOfSubstitutionModels.cpp
new file mode 100644
index 0000000..f98761f
--- /dev/null
+++ b/src/Bpp/Phyl/Model/MixtureOfSubstitutionModels.cpp
@@ -0,0 +1,320 @@
+//
+// File: MixtureOfSubstitutionModels.cpp
+// Created by: Laurent Gueguen
+// Date: mardi 14 septembre 2010, à 20h 43
+//
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "MixtureOfSubstitutionModels.h"
+
+#include <Bpp/Numeric/NumConstants.h>
+#include <Bpp/Text/TextTools.h>
+
+#include <string>
+
+using namespace bpp;
+using namespace std;
+
+MixtureOfSubstitutionModels::MixtureOfSubstitutionModels(const Alphabet* alpha,
+                                                         vector<SubstitutionModel*> vpModel_) :
+  AbstractParameterAliasable("Mixture."),
+  AbstractMixedSubstitutionModel(alpha, "Mixture.")
+{
+  size_t i, nbmod = vpModel_.size();
+
+  for (i = 0; i < nbmod; i++)
+  {
+    if (!vpModel_[i])
+      throw Exception("Empty model number " + TextTools::toString(i) + " in MixtureOfSubstitutionModels constructor");
+    for (size_t j = i + 1; j < nbmod; j++)
+    {
+      if (vpModel_[i] == vpModel_[j])
+        throw Exception("Same model at positions " + TextTools::toString(i) + " and " +
+                        TextTools::toString(j) + " in MixtureOfSubstitutionModels constructor");
+    }
+  }
+
+  // Initialization of modelsContainer_.
+
+  for (i = 0; i < nbmod; i++)
+  {
+    modelsContainer_.push_back(vpModel_[i]);
+    vProbas_.push_back(1.0 / static_cast<double>(nbmod));
+    vRates_.push_back(1.0);
+  }
+
+  // Initialization of parameters_.
+
+  // relative rates and probas
+  for (i = 0; i < nbmod - 1; i++)
+  {
+    addParameter_(new Parameter("Mixture.relproba" + TextTools::toString(i + 1), 1.0 / static_cast<double>(nbmod - i), &Parameter::PROP_CONSTRAINT_EX));
+    addParameter_(new Parameter("Mixture.relrate" + TextTools::toString(i + 1), 1.0 / static_cast<double>(nbmod - i), &Parameter::PROP_CONSTRAINT_EX));
+  }
+
+  // models parameters
+
+  for (i = 0; i < nbmod; i++)
+  {
+    modelsContainer_[i]->setNamespace("Mixture." + TextTools::toString(i + 1) + "_" + vpModel_[i]->getNamespace());
+    addParameters_(vpModel_[i]->getParameters());
+  }
+
+  for (i = 0; i < nbmod; i++)
+  {
+    vpModel_[i]->addRateParameter();
+  }
+
+  updateMatrices();
+}
+
+MixtureOfSubstitutionModels::MixtureOfSubstitutionModels(const Alphabet* alpha,
+                                                         vector<SubstitutionModel*> vpModel_,
+                                                         Vdouble& vproba,
+                                                         Vdouble& vrate) :
+  AbstractParameterAliasable("Mixture."),
+  AbstractMixedSubstitutionModel(alpha, "Mixture.")
+{
+  size_t i, nbmod = vpModel_.size();
+
+  for (i = 0; i < nbmod; i++)
+  {
+    if (!vpModel_[i])
+      throw Exception("Empty model number " + TextTools::toString(i) + " in MixtureOfSubstitutionModels constructor");
+    for (size_t j = i + 1; j < nbmod; j++)
+    {
+      if (vpModel_[i] == vpModel_[j])
+        throw Exception("Same model at positions " + TextTools::toString(i) + " and " +
+                        TextTools::toString(j) + " in MixtureOfSubstitutionModels constructor");
+    }
+  }
+
+  double x = 0;
+  double y = 0;
+
+  for (i = 0; i < nbmod; i++)
+  {
+    if (vrate[i] <= 0)
+      throw Exception("Non positive rate: " + TextTools::toString(vrate[i]) + " in MixtureOfSubstitutionModels constructor.");
+    if (vproba[i] <= 0)
+      throw Exception("Non positive probability: " + TextTools::toString(vproba[i]) + " in MixtureOfSubstitutionModels constructor.");
+    x += vproba[i];
+    y += vproba[i] * vrate[i];
+  }
+
+  if (fabs(1. - x) > NumConstants::SMALL())
+    throw Exception("Probabilities must equal 1 (sum = " + TextTools::toString(x) + ").");
+  if (fabs(1. - y) > NumConstants::SMALL())
+    throw Exception("Expectation on rates must equal 1 (E =" + TextTools::toString(y) + ").");
+
+
+  // Initialization of modelsContainer_.
+
+  for (i = 0; i < nbmod; i++)
+  {
+    modelsContainer_.push_back(vpModel_[i]);
+  }
+
+  // rates & probas
+
+  for (i = 0; i < nbmod; i++)
+  {
+    vProbas_.push_back(1.0 / static_cast<double>(nbmod));
+    vRates_.push_back(1.0);
+  }
+
+  // Initialization of parameters_.
+
+
+  // relative rates and probas
+  x = 0; y = 0;
+
+  for (i = 0; i < nbmod - 1; i++)
+  {
+    addParameter_(new Parameter("Mixture.relproba" + TextTools::toString(i + 1), vproba[i] / (1 - x), &Parameter::PROP_CONSTRAINT_EX));
+    x += vproba[i];
+    addParameter_(new Parameter("Mixture.relrate" + TextTools::toString(i + 1), vproba[i] * vrate[i] / (1 - y), &Parameter::PROP_CONSTRAINT_EX));
+    y += vproba[i] * vrate[i];
+  }
+
+  // models parameters
+
+  for (i = 0; i < nbmod; i++)
+  {
+    modelsContainer_[i]->setNamespace("Mixture." + TextTools::toString(i + 1) + "_" + vpModel_[i]->getNamespace());
+    addParameters_(vpModel_[i]->getParameters());
+  }
+
+  for (i = 0; i < nbmod; i++)
+  {
+    vpModel_[i]->addRateParameter();
+  }
+
+  updateMatrices();
+}
+
+MixtureOfSubstitutionModels::MixtureOfSubstitutionModels(const MixtureOfSubstitutionModels& msm) :
+  AbstractParameterAliasable(msm),
+  AbstractMixedSubstitutionModel(msm)
+{}
+
+MixtureOfSubstitutionModels& MixtureOfSubstitutionModels::operator=(const MixtureOfSubstitutionModels& msm)
+{
+  AbstractMixedSubstitutionModel::operator=(msm);
+
+  return *this;
+}
+
+
+MixtureOfSubstitutionModels::~MixtureOfSubstitutionModels()
+{}
+
+
+void MixtureOfSubstitutionModels::updateMatrices()
+{
+  size_t i, j, nbmod = modelsContainer_.size();
+
+  double x, y;
+  x = 1.0;
+
+  for (i = 0; i < nbmod - 1; i++)
+  {
+    y = getParameterValue("relproba" + TextTools::toString(i + 1));
+    vProbas_[i] = x * y;
+    x *= 1 - y;
+  }
+  vProbas_[nbmod - 1] = x;
+
+  x = 1.0;
+  bool approx = false; // used when some categories are avoided
+  double s = 0;
+  for (i = 0; i < nbmod - 1; i++)
+  {
+    y = getParameterValue("relrate" + TextTools::toString(i + 1));
+    if (vProbas_[i] < NumConstants::SMALL())
+    {
+      vRates_[i] = NumConstants::SMALL();
+      approx = true;
+    }
+    else
+    {
+      vRates_[i] = x * y / vProbas_[i];
+      s += x * y;
+    }
+    x *= 1 - y;
+  }
+
+  if (vProbas_[nbmod - 1] < NumConstants::SMALL())
+  {
+    vRates_[nbmod - 1] = NumConstants::SMALL();
+    approx = true;
+  }
+  else
+  {
+    vRates_[nbmod - 1] = x / vProbas_[nbmod - 1];
+    s += x;
+  }
+
+  if (approx)
+    for (i = 0; i < nbmod; i++)
+    {
+      vRates_[i] /= s;
+    }
+
+  // / models
+
+  for (i = 0; i < nbmod; i++)
+  {
+    modelsContainer_[i]->setRate(vRates_[i]);
+    modelsContainer_[i]->matchParametersValues(getParameters());
+  }
+
+  // / freq_
+
+  for (i = 0; i < getNumberOfStates(); i++)
+  {
+    freq_[i] = 0;
+    for (j = 0; j < modelsContainer_.size(); j++)
+    {
+      freq_[i] += vProbas_[j] * modelsContainer_[j]->freq(i);
+    }
+  }
+}
+
+void MixtureOfSubstitutionModels::setFreq(std::map<int, double>& m)
+{
+  ParameterList pl;
+  for (unsigned int n = 0; n < modelsContainer_.size(); n++)
+  {
+    modelsContainer_[n]->setFreq(m);
+    pl.addParameters(modelsContainer_[n]->getParameters());
+  }
+  matchParametersValues(pl);
+}
+
+void MixtureOfSubstitutionModels::setVRates(const Vdouble& vd)
+{
+  AbstractMixedSubstitutionModel::setVRates(vd);
+
+  size_t i, nbmod = modelsContainer_.size();
+  double sP = 0;
+  for (i = 0; i < nbmod - 1; i++)
+  {
+    sP += vProbas_[i];
+  }
+
+  double y = 0;
+  for (i = 0; i < nbmod - 1; i++)
+  {
+    setParameterValue("relrate" + TextTools::toString(i + 1), vProbas_[i] / sP * vRates_[i] / (1 - y));
+    y += vProbas_[i] / sP * vRates_[i];
+  }
+}
+
+Vint MixtureOfSubstitutionModels::getSubmodelNumbers(string& desc) const
+{
+  unsigned int i;
+  for (i = 0; i < getNumberOfModels(); i++)
+  {
+    if (getNModel(i)->getName() == desc)
+      break;
+  }
+  if (i == getNumberOfModels())
+    throw Exception("MixtureOfSubstitutionModels::getSubmodelNumbers model description do not match " + desc);
+
+  Vint submodnb;
+  submodnb.push_back(i);
+
+  return submodnb;
+}
diff --git a/src/Bpp/Phyl/Model/MixtureOfSubstitutionModels.h b/src/Bpp/Phyl/Model/MixtureOfSubstitutionModels.h
new file mode 100644
index 0000000..dfbab7a
--- /dev/null
+++ b/src/Bpp/Phyl/Model/MixtureOfSubstitutionModels.h
@@ -0,0 +1,199 @@
+//
+// File: MixtureOfSubstitutionModels.h
+// Created by: Laurent Gueguen
+// Date: lundi 13 septembre 2010, à 21h 31
+//
+
+/*
+  Copyright or © or Copr. CNRS, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _MIXTUREOFSUBSTITUTIONMODELS_H_
+#define _MIXTUREOFSUBSTITUTIONMODELS_H_
+
+// #include <Bpp/Numeric/Prob.all>
+#include <Bpp/Numeric/VectorTools.h>
+#include "AbstractMixedSubstitutionModel.h"
+
+#include <vector>
+#include <string>
+#include <map>
+#include <cstring> // C lib for string copy
+
+namespace bpp
+{
+  /**
+   * @brief Substitution models defined as a mixture of several
+   * substitution models.
+   * @author Laurent Guéguen
+   *
+   * All the models can be of different types (for example T92 or
+   * GY94), and each model has a specific probability and rate. 
+   *
+   *
+   * The probabilities and rates of the models are independent
+   * parameters, handled directly, under the constraint that the
+   * expectation of the rates on the distribution of the models must
+   * equal one. 
+   *
+   * If there are @f$n at f$ models, @f$p_i at f$ is the probability of
+   * model i (@f$\sum_{i=1}^{n} p_i = 1 at f$) and the probabilities
+   * are defined by relative probabilities parameters @f$rp_i at f$
+   * (called "relprobai") with:
+   * @f[
+   * 1 <= i < n, p_i = (1-rp_1)*(1-rp_2)...(1-rp_{i-1})*rp_{i}
+   * @f]
+   * @f[
+   * p_n = (1-rp_1)*(1-rp_2)...(1-rp_{n-1})
+   * @f]
+   * and
+   * @f[
+   * \forall 1 <= i < n, rp_i = \frac{p_i}{1-(p_1+...+p_{i-1})}
+   * @f]
+   * where @f$p_i at f$ stands for the probability of model @f$i at f$.
+   *
+   *
+   * If there are @f$n at f$ models, @f$\rho_i at f$ is the rate and @f$p_i at f$
+   * is the probability of model i (@f$\sum_{i=1}^{n} p_i * \rho_i =
+   * 1 at f$), the rates are defined by relative rates parameters
+   * @f$r_i at f$ (called "relratei") with:
+   * @f[
+   * 1 <= i < n, \rho_i = (1-r_1)*(1-r_2)...(1-r_{i-1})*\frac{r_{i}}{p_i} 
+   * @f]
+   * @f[
+   * \rho_n = \frac{(1-r_1)*(1-r_2)*...*(1-r_{n-1})}{p_n}
+   * @f]
+   * and
+   * @f[
+   * \forall 1 <= i < n, r_i = \frac{\rho_i*p_i}{1-(p_1*\rho_1+...+p_{i-1}*\rho_{i-1})} < 1.
+   * @f]
+   *
+   * For example:
+   *
+   * Mixture(model1=HKY85(kappa=3), model2=T92(theta=0.1),
+   *         model2=L95(gamma=2), relrate1=0.2, relrate2=0.9,
+   *         relproba1=0.1,relproba2=0.8)
+   *
+   * define a model as a mixture of 3 different models: HKY85 has
+   * probability 0.1 and rate 2, T92 has probability 0.4 and rate 1.8,
+   * and L95 has probability 0.5 and rate 0.16.
+   *
+   *
+   * The parameters are named \c "Mixture.relrate1", \c
+   * "Mixture.relrate2", \c "Mixture.relproba1", \c
+   * "Mixture.relproba2"... in addition to the parameters of the
+   * submodels that are prefixed by "Mixture.i_", where i is the order
+   * of the model.
+
+   */
+
+  class MixtureOfSubstitutionModels :
+    public AbstractMixedSubstitutionModel
+  {
+  public:
+
+    /*
+     *@brief Constructor of a MixtureOfSubstitutionModels, where all
+     *the models have rate 1 and equal probability.
+     *
+     *@param alpha pointer to the Alphabet
+     *@param vpModel vector of pointers to SubstitutionModels. All the
+     *   SubstitutionModels are owned by the instance.
+     */
+    
+    MixtureOfSubstitutionModels(const Alphabet* alpha,
+                                std::vector<SubstitutionModel*> vpModel);
+    
+    /*
+     *@brief Constructor of a MixtureOfSubstitutionModels.
+     *
+     *@param alpha pointer to the Alphabet
+     *@param vpModel vector of pointers to SubstitutionModels. All the
+     *   SubstitutionModels are owned by the instance.
+     *@param vproba vector of the probabilities of the models
+     *@param vrate vector of the rates of the models
+     *
+     * See above the constraints on the rates and the probabilities of
+     * the vectors.
+     */
+    
+    MixtureOfSubstitutionModels(const Alphabet* alpha,
+                                std::vector<SubstitutionModel*> vpModel,
+                                Vdouble& vproba, Vdouble& vrate);
+
+    MixtureOfSubstitutionModels(const MixtureOfSubstitutionModels&);
+    
+    MixtureOfSubstitutionModels& operator=(const MixtureOfSubstitutionModels&);
+    
+    ~MixtureOfSubstitutionModels();
+    
+    MixtureOfSubstitutionModels* clone() const { return new MixtureOfSubstitutionModels(*this); }
+
+  public:
+    std::string getName() const { return "Mixture"; }
+
+    void updateMatrices();
+  
+    /**
+     * @brief Sets the rates of the submodels to follow the constraint
+     * that the mean rate of the mixture equals rate_.
+     
+     * @param vd a vector of positive values such that the rates of
+     * the respective submodels are in the same proportions (ie this
+     * vector does not need to be normalized).
+     */
+
+    virtual void setVRates(const Vdouble& vd);
+
+    /*
+     *@brief Returns the vector of numbers of the submodels in the
+     *mixture that match a description of the parameters numbers.
+     *
+     *@param desc is the description of the class indexes of the mixed
+     *parameters. Syntax is like: kappa_1,gamma_3,delta_2
+     *
+     */
+  
+    Vint getSubmodelNumbers(std::string& desc) const;
+
+    /**
+     * @brief applies setFreq to all the models of the mixture and
+     * recovers the parameters values.
+     *
+     **/
+  
+    void setFreq(std::map<int,double>&);
+
+  };
+} // end of namespace bpp.
+
+#endif  // _MIXTUREOFSUBSTITUTIONMODELS_H_
diff --git a/src/Bpp/Phyl/Model/Nucleotide/F84.cpp b/src/Bpp/Phyl/Model/Nucleotide/F84.cpp
new file mode 100644
index 0000000..11f2e49
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/F84.cpp
@@ -0,0 +1,465 @@
+//
+// File: F84.cpp
+// Created by: Julien Dutheil
+// Created on: Tue May 23 11:13 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "F84.h"
+#include "../FrequenciesSet/NucleotideFrequenciesSet.h"
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+// From the STL:
+#include <cmath>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+F84::F84(
+    const NucleicAlphabet* alpha,
+    double kappa,
+    double piA,
+    double piC,
+    double piG,
+    double piT) :
+  AbstractParameterAliasable("F84."),
+  AbstractSubstitutionModel(alpha, "F84."),
+  AbstractReversibleSubstitutionModel(alpha, "F84."),
+  kappa_(kappa), piA_(piA), piC_(piC), piG_(piG), piT_(piT), piY_(), piR_(),
+  r_(), k1_(), k2_(), theta_(piG + piC), theta1_(piA / (1. - theta_)), theta2_(piG / theta_),
+  l_(), exp1_(), exp2_(), p_(size_, size_)
+{
+  addParameter_(new Parameter("F84.kappa", kappa, &Parameter::R_PLUS));
+  addParameter_(new Parameter("F84.theta" , theta_ , &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+  addParameter_(new Parameter("F84.theta1", theta1_, &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+  addParameter_(new Parameter("F84.theta2", theta2_, &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+  updateMatrices();
+}
+
+/******************************************************************************/
+
+void F84::updateMatrices()
+{
+  kappa_ = getParameterValue("kappa");
+  theta_  = getParameterValue("theta");
+  theta1_ = getParameterValue("theta1");
+  theta2_ = getParameterValue("theta2");
+  piA_ = theta1_ * (1. - theta_);
+  piC_ = (1. - theta2_) * theta_;
+  piG_ = theta2_ * theta_;
+  piT_ = (1. - theta1_) * (1. - theta_);
+  piR_ = piA_ + piG_;
+  piY_ = piT_ + piC_;
+  r_ = 1. / (1 - piA_ * piA_ - piC_ * piC_ - piG_ * piG_ - piT_*piT_ + 2. * kappa_ * (piC_ * piT_ / piY_ + piA_ * piG_ / piR_));
+  k1_ = 1;
+  k2_ = kappa_ + 1;
+  
+  // Frequences:
+  freq_[0] = piA_;
+  freq_[1] = piC_;
+  freq_[2] = piG_;
+  freq_[3] = piT_;
+
+  //Generator:
+  generator_(0, 0) = -(                  piC_ + (1 + kappa_ / piR_) * piG_ +       piT_);
+  generator_(1, 1) = -(      piA_ +                   piG_ + (1 + kappa_ / piY_) * piT_); 
+  generator_(2, 2) = -((1 + kappa_ / piR_) * piA_ +       piC_             +       piT_);
+  generator_(3, 3) = -(      piA_ + (1 + kappa_ / piY_) * piC_ +       piG_            );
+
+  generator_(1, 0) = piA_;
+  generator_(3, 0) = piA_;
+  generator_(0, 1) = piC_;
+  generator_(2, 1) = piC_;
+  generator_(1, 2) = piG_;
+  generator_(3, 2) = piG_;
+  generator_(0, 3) = piT_;
+  generator_(2, 3) = piT_;
+  
+  generator_(2, 0) = (1 + kappa_ / piR_) * piA_;
+  generator_(3, 1) = (1 + kappa_ / piY_) * piC_;
+  generator_(0, 2) = (1 + kappa_ / piR_) * piG_;
+  generator_(1, 3) = (1 + kappa_ / piY_) * piT_;
+  
+  // Normalization:
+  MatrixTools::scale(generator_, r_);
+  
+  // Exchangeability:
+  exchangeability_(0,0) = generator_(0,0) / piA_;
+  exchangeability_(0,1) = generator_(0,1) / piC_; 
+  exchangeability_(0,2) = generator_(0,2) / piG_; 
+  exchangeability_(0,3) = generator_(0,3) / piT_;
+
+  exchangeability_(1,0) = generator_(1,0) / piA_; 
+  exchangeability_(1,1) = generator_(1,1) / piC_; 
+  exchangeability_(1,2) = generator_(1,2) / piG_; 
+  exchangeability_(1,3) = generator_(1,3) / piT_; 
+  
+  exchangeability_(2,0) = generator_(2,0) / piA_; 
+  exchangeability_(2,1) = generator_(2,1) / piC_; 
+  exchangeability_(2,2) = generator_(2,2) / piG_; 
+  exchangeability_(2,3) = generator_(2,3) / piT_; 
+  
+  exchangeability_(3,0) = generator_(3,0) / piA_;
+  exchangeability_(3,1) = generator_(3,1) / piC_; 
+  exchangeability_(3,2) = generator_(3,2) / piG_; 
+  exchangeability_(3,3) = generator_(3,3) / piT_;
+
+  // Eigen values:
+  eigenValues_[0] = 0;
+  eigenValues_[1] = -r_ * (1+kappa_);
+  eigenValues_[2] = -r_ * (1+kappa_); 
+  eigenValues_[3] = -r_;
+  
+  // Eigen vectors:
+  leftEigenVectors_(0,0) = piA_;
+  leftEigenVectors_(0,1) = piC_;
+  leftEigenVectors_(0,2) = piG_;
+  leftEigenVectors_(0,3) = piT_;
+
+  leftEigenVectors_(1,0) = 0.;
+  leftEigenVectors_(1,1) = piT_ / piY_;
+  leftEigenVectors_(1,2) = 0.;
+  leftEigenVectors_(1,3) = -piT_ / piY_;
+
+  leftEigenVectors_(2,0) = piG_ / piR_;
+  leftEigenVectors_(2,1) = 0.;
+  leftEigenVectors_(2,2) = -piG_ / piR_;
+  leftEigenVectors_(2,3) = 0.;
+
+  leftEigenVectors_(3,0) = piA_*piY_ / piR_;
+  leftEigenVectors_(3,1) = -piC_;
+  leftEigenVectors_(3,2) = piG_*piY_ / piR_;
+  leftEigenVectors_(3,3) = -piT_;
+
+  rightEigenVectors_(0,0) = 1.;
+  rightEigenVectors_(0,1) = 0.;
+  rightEigenVectors_(0,2) = 1.;
+  rightEigenVectors_(0,3) = 1.;
+  
+  rightEigenVectors_(1,0) = 1.;
+  rightEigenVectors_(1,1) = 1.;
+  rightEigenVectors_(1,2) = 0.;;
+  rightEigenVectors_(1,3) = -piR_ / piY_;
+
+  rightEigenVectors_(2,0) = 1.;
+  rightEigenVectors_(2,1) = 0.;
+  rightEigenVectors_(2,2) = -piA_ / piG_;
+  rightEigenVectors_(2,3) = 1.;
+
+  rightEigenVectors_(3,0) = 1.;
+  rightEigenVectors_(3,1) = -piC_ / piT_;
+  rightEigenVectors_(3,2) = 0.;
+  rightEigenVectors_(3,3) = -piR_ / piY_;
+}
+  
+/******************************************************************************/
+
+double F84::Pij_t(int i, int j, double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = exp(-k1_*l_);
+  exp2_ = exp(-k2_*l_);
+  
+  switch(i) {
+    //A
+    case 0 : {
+      switch(j) {
+        case 0 : return piA_ * (1. + (piY_/piR_) * exp1_) + (piG_/piR_) * exp2_; //A
+        case 1 : return piC_ * (1. -               exp1_);                       //C
+        case 2 : return piG_ * (1. + (piY_/piR_) * exp1_) - (piG_/piR_) * exp2_; //G
+        case 3 : return piT_ * (1. -               exp1_);                       //T, U
+      }
+    } 
+    //C
+    case 1 : {
+      switch(j) {
+        case 0 : return piA_ * (1. -               exp1_);                       //A
+        case 1 : return piC_ * (1. + (piR_/piY_) * exp1_) + (piT_/piY_) * exp2_; //C
+        case 2 : return piG_ * (1. -               exp1_);                       //G
+        case 3 : return piT_ * (1. + (piR_/piY_) * exp1_) - (piT_/piY_) * exp2_; //T, U
+      }
+    }
+    //G
+    case 2 : {
+      switch(j) {
+        case 0 : return piA_ * (1. + (piY_/piR_) * exp1_) - (piA_/piR_) * exp2_; //A
+        case 1 : return piC_ * (1. -               exp1_);                       //C
+        case 2 : return piG_ * (1. + (piY_/piR_) * exp1_) + (piA_/piR_) * exp2_; //G
+        case 3 : return piT_ * (1. -               exp1_);                       //T, U
+      }
+    }
+    //T, U
+    case 3 : {
+      switch(j) {
+        case 0 : return piA_ * (1. -               exp1_);                       //A
+        case 1 : return piC_ * (1. + (piR_/piY_) * exp1_) - (piC_/piY_) * exp2_; //C
+        case 2 : return piG_ * (1. -               exp1_);                       //G
+        case 3 : return piT_ * (1. + (piR_/piY_) * exp1_) + (piC_/piY_) * exp2_; //T, U
+      }
+    }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+
+double F84::dPij_dt(int i, int j, double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = exp(-k1_*l_);
+  exp2_ = exp(-k2_*l_);
+  
+  switch(i) {
+    //A
+    case 0 : {
+      switch(j) {
+        case 0 : return rate_ * r_ * (piA_ * -(piY_/piR_) * exp1_ - (piG_/piR_) * k2_ * exp2_); //A
+        case 1 : return rate_ * r_ * (piC_ *                exp1_);                             //C
+        case 2 : return rate_ * r_ * (piG_ * -(piY_/piR_) * exp1_ + (piG_/piR_) * k2_ * exp2_); //G
+        case 3 : return rate_ * r_ * (piT_ *                exp1_);                             //T, U
+      }
+    } 
+    //C
+    case 1 : {
+      switch(j) {
+        case 0 : return rate_ * r_ * (piA_ *                exp1_);                             //A
+        case 1 : return rate_ * r_ * (piC_ * -(piR_/piY_) * exp1_ - (piT_/piY_) * k2_ * exp2_); //C
+        case 2 : return rate_ * r_ * (piG_ *                exp1_);                             //G
+        case 3 : return rate_ * r_ * (piT_ * -(piR_/piY_) * exp1_ + (piT_/piY_) * k2_ * exp2_); //T, U
+      }
+    }
+    //G
+    case 2 : {
+      switch(j) {
+        case 0 : return rate_ * r_ * (piA_ * -(piY_/piR_) * exp1_ + (piA_/piR_) * k2_ * exp2_); //A
+        case 1 : return rate_ * r_ * (piC_ *                exp1_);                             //C
+        case 2 : return rate_ * r_ * (piG_ * -(piY_/piR_) * exp1_ - (piA_/piR_) * k2_ * exp2_); //G
+        case 3 : return rate_ * r_ * (piT_ *                exp1_);                             //T, U
+      }
+    }
+    //T, U
+    case 3 : {
+      switch(j) {
+        case 0 : return rate_ * r_ * (piA_ *                exp1_);                             //A
+        case 1 : return rate_ * r_ * (piC_ * -(piR_/piY_) * exp1_ + (piC_/piY_) * k2_ * exp2_); //C
+        case 2 : return rate_ * r_ * (piG_ *                exp1_);                             //G
+        case 3 : return rate_ * r_ * (piT_ * -(piR_/piY_) * exp1_ - (piC_/piY_) * k2_ * exp2_); //T, U
+      }
+    }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+
+double F84::d2Pij_dt2(int i, int j, double d) const
+{
+  double r_2 = rate_ * rate_ * r_ * r_;
+  l_ = rate_ * r_ * d;
+  double k2_2 = k2_ * k2_;
+  exp1_ = exp(-k1_*l_);
+  exp2_ = exp(-k2_*l_);
+  
+  switch(i) {
+    //A
+    case 0 : {
+      switch(j) {
+        case 0 : return r_2 * (piA_ * (piY_/piR_) * exp1_ + (piG_/piR_) * k2_2 * exp2_); //A
+        case 1 : return r_2 * (piC_ *             - exp1_);                              //C
+        case 2 : return r_2 * (piG_ * (piY_/piR_) * exp1_ - (piG_/piR_) * k2_2 * exp2_); //G
+        case 3 : return r_2 * (piT_ *             - exp1_);                              //T, U
+      }
+    } 
+    //C
+    case 1 : {
+      switch(j) {
+        case 0 : return r_2 * (piA_ *             - exp1_);                              //A
+        case 1 : return r_2 * (piC_ * (piR_/piY_) * exp1_ + (piT_/piY_) * k2_2 * exp2_); //C
+        case 2 : return r_2 * (piG_ *             - exp1_);                              //G
+        case 3 : return r_2 * (piT_ * (piR_/piY_) * exp1_ - (piT_/piY_) * k2_2 * exp2_); //T, U
+      }
+    }
+    //G
+    case 2 : {
+      switch(j) {
+        case 0 : return r_2 * (piA_ * (piY_/piR_) * exp1_ - (piA_/piR_) * k2_2 * exp2_); //A
+        case 1 : return r_2 * (piC_ *             - exp1_);                              //C
+        case 2 : return r_2 * (piG_ * (piY_/piR_) * exp1_ + (piA_/piR_) * k2_2 * exp2_); //G
+        case 3 : return r_2 * (piT_ *             - exp1_);                              //T, U
+      }
+    }
+    //T, U
+    case 3 : {
+      switch(j) {
+        case 0 : return r_2 * (piA_ *             - exp1_);                              //A
+        case 1 : return r_2 * (piC_ * (piR_/piY_) * exp1_ - (piC_/piY_) * k2_2 * exp2_); //C
+        case 2 : return r_2 * (piG_ *             - exp1_);                              //G
+        case 3 : return r_2 * (piT_ * (piR_/piY_) * exp1_ + (piC_/piY_) * k2_2 * exp2_); //T, U
+      }
+    }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+
+const Matrix<double> & F84::getPij_t(double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = exp(-k1_*l_);
+  exp2_ = exp(-k2_*l_);
+
+  //A
+  p_(0, 0) = piA_ * (1. + (piY_/piR_) * exp1_) + (piG_/piR_) * exp2_; //A
+  p_(0, 1) = piC_ * (1. -               exp1_);                       //C
+  p_(0, 2) = piG_ * (1. + (piY_/piR_) * exp1_) - (piG_/piR_) * exp2_; //G
+  p_(0, 3) = piT_ * (1. -               exp1_);                       //T, U
+
+  //C
+  p_(1, 0) = piA_ * (1. -               exp1_);                       //A
+  p_(1, 1) = piC_ * (1. + (piR_/piY_) * exp1_) + (piT_/piY_) * exp2_; //C
+  p_(1, 2) = piG_ * (1. -               exp1_);                       //G
+  p_(1, 3) = piT_ * (1. + (piR_/piY_) * exp1_) - (piT_/piY_) * exp2_; //T, U
+
+  //G
+  p_(2, 0) = piA_ * (1. + (piY_/piR_) * exp1_) - (piA_/piR_) * exp2_; //A
+  p_(2, 1) = piC_ * (1. -               exp1_);                       //C
+  p_(2, 2) = piG_ * (1. + (piY_/piR_) * exp1_) + (piA_/piR_) * exp2_; //G
+  p_(2, 3) = piT_ * (1. -               exp1_);                       //T, U
+
+  //T, U
+  p_(3, 0) = piA_ * (1. -               exp1_);                       //A
+  p_(3, 1) = piC_ * (1. + (piR_/piY_) * exp1_) - (piC_/piY_) * exp2_; //C
+  p_(3, 2) = piG_ * (1. -               exp1_);                       //G
+  p_(3, 3) = piT_ * (1. + (piR_/piY_) * exp1_) + (piC_/piY_) * exp2_; //T, U
+
+  return p_;
+}
+
+const Matrix<double> & F84::getdPij_dt(double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = exp(-k1_*l_);
+  exp2_ = exp(-k2_*l_);
+
+  //A
+  p_(0, 0) = rate_ * r_ * (piA_ * -(piY_/piR_) * exp1_ - (piG_/piR_) * k2_ * exp2_); //A
+  p_(0, 1) = rate_ * r_ * (piC_ *                exp1_);                             //C
+  p_(0, 2) = rate_ * r_ * (piG_ * -(piY_/piR_) * exp1_ + (piG_/piR_) * k2_ * exp2_); //G
+  p_(0, 3) = rate_ * r_ * (piT_ *                exp1_);                             //T, U
+
+  //C
+  p_(1, 0) = rate_ * r_ * (piA_ *                exp1_);                             //A
+  p_(1, 1) = rate_ * r_ * (piC_ * -(piR_/piY_) * exp1_ - (piT_/piY_) * k2_ * exp2_); //C
+  p_(1, 2) = rate_ * r_ * (piG_ *                exp1_);                             //G
+  p_(1, 3) = rate_ * r_ * (piT_ * -(piR_/piY_) * exp1_ + (piT_/piY_) * k2_ * exp2_); //T, U
+
+  //G
+  p_(2, 0) = rate_ * r_ * (piA_ * -(piY_/piR_) * exp1_ + (piA_/piR_) * k2_ * exp2_); //A
+  p_(2, 1) = rate_ * r_ * (piC_ *                exp1_);                             //C
+  p_(2, 2) = rate_ * r_ * (piG_ * -(piY_/piR_) * exp1_ - (piA_/piR_) * k2_ * exp2_); //G
+  p_(2, 3) = rate_ * r_ * (piT_ *                exp1_);                             //T, U
+
+  //T, U
+  p_(3, 0) = rate_ * r_ * (piA_ *                exp1_);                             //A
+  p_(3, 1) = rate_ * r_ * (piC_ * -(piR_/piY_) * exp1_ + (piC_/piY_) * k2_ * exp2_); //C
+  p_(3, 2) = rate_ * r_ * (piG_ *                exp1_);                             //G
+  p_(3, 3) = rate_ * r_ * (piT_ * -(piR_/piY_) * exp1_ - (piC_/piY_) * k2_ * exp2_); //T, U
+
+  return p_;
+}
+
+const Matrix<double> & F84::getd2Pij_dt2(double d) const
+{
+  double r_2 = rate_ * rate_ * r_ * r_;
+  l_ = rate_ * r_ * d;
+  double k2_2 = k2_ * k2_;
+  exp1_ = exp(-k1_*l_);
+  exp2_ = exp(-k2_*l_);
+
+  //A
+  p_(0, 0) = r_2 * (piA_ * (piY_/piR_) * exp1_ + (piG_/piR_) * k2_2 * exp2_); //A
+  p_(0, 1) = r_2 * (piC_ *             - exp1_);                              //C
+  p_(0, 2) = r_2 * (piG_ * (piY_/piR_) * exp1_ - (piG_/piR_) * k2_2 * exp2_); //G
+  p_(0, 3) = r_2 * (piT_ *             - exp1_);                              //T, U
+
+  //C
+  p_(1, 0) = r_2 * (piA_ *             - exp1_);                              //A
+  p_(1, 1) = r_2 * (piC_ * (piR_/piY_) * exp1_ + (piT_/piY_) * k2_2 * exp2_); //C
+  p_(1, 2) = r_2 * (piG_ *             - exp1_);                              //G
+  p_(1, 3) = r_2 * (piT_ * (piR_/piY_) * exp1_ - (piT_/piY_) * k2_2 * exp2_); //T, U
+
+  //G
+  p_(2, 0) = r_2 * (piA_ * (piY_/piR_) * exp1_ - (piA_/piR_) * k2_2 * exp2_); //A
+  p_(2, 1) = r_2 * (piC_ *             - exp1_);                              //C
+  p_(2, 2) = r_2 * (piG_ * (piY_/piR_) * exp1_ + (piA_/piR_) * k2_2 * exp2_); //G
+  p_(2, 3) = r_2 * (piT_ *             - exp1_);                              //T, U
+ 
+  //T, U
+  p_(3, 0) = r_2 * (piA_ *             - exp1_);                              //A
+  p_(3, 1) = r_2 * (piC_ * (piR_/piY_) * exp1_ - (piC_/piY_) * k2_2 * exp2_); //C
+  p_(3, 2) = r_2 * (piG_ *             - exp1_);                              //G
+  p_(3, 3) = r_2 * (piT_ * (piR_/piY_) * exp1_ + (piC_/piY_) * k2_2 * exp2_); //T, U
+
+  return p_;
+}
+
+/******************************************************************************/
+
+void F84::setFreq(map<int, double>& freqs)
+{
+  piA_ = freqs[0];
+  piC_ = freqs[1];
+  piG_ = freqs[2];
+  piT_ = freqs[3];
+  vector<string> thetas(3);
+  thetas[0] = getNamespace()+ "theta";
+  thetas[1] = getNamespace() + "theta1";
+  thetas[2] = getNamespace() + "theta2";
+  ParameterList pl = getParameters().subList(thetas);
+  pl[0].setValue(piC_ + piG_);
+  pl[1].setValue(piA_ / (piA_ + piT_));
+  pl[2].setValue(piG_ / (piC_ + piG_));
+  setParametersValues(pl);
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/F84.h b/src/Bpp/Phyl/Model/Nucleotide/F84.h
new file mode 100644
index 0000000..99c1422
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/F84.h
@@ -0,0 +1,228 @@
+//
+// File: F84.h
+// Created by: Julien Dutheil
+// Created on: Tue May 23 11:13 2005
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _F84_H_
+#define _F84_H_
+
+#include "NucleotideSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+
+#include <Bpp/Numeric/Constraints.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The Felsenstein (1984) substitution model for nucleotides.
+ *
+ * This model is similar to the HKY85 model, with a different parametrization.
+ * \f[
+ * S = \begin{pmatrix}
+ * \cdots & r & \left(1 + \kappa/\pi_R\right) r & r \\ 
+ * r & \cdots & r & \left(1 + \kappa/\pi_Y\right) r \\ 
+ * \left(1 + \kappa/\pi_R\right) r & r & \cdots & r \\ 
+ * r & \left(1 + \kappa/\pi_Y\right) r & r & \cdots \\ 
+ * \end{pmatrix}
+ * \f]
+ * with \f$\pi_R = \pi_A + \pi_G\f$ and \f$\pi_Y = \pi_C + \pi_T\f$. 
+ * \f[
+ * \pi = \left(\pi_A, \pi_C, \pi_G, \pi_T\right)
+ * \f]
+ * This models includes five parameters, the transition / transversion
+ * relative rate \f$\kappa\f$ and four frequencies \f$\pi_A, \pi_C, \pi_G, \pi_T\f$.
+ * These four frequencies are not independent parameters, since they have the constraint to
+ * sum to 1.
+ * We use instead a different parametrization to remove this constraint:
+ * \f[
+ * \begin{cases}
+ * \theta = \pi_C + \pi_G\\
+ * \theta_1 = \frac{\pi_A}{1 - \theta} = \frac{\pi_A}{\pi_A + \pi_T}\\
+ * \theta_2 = \frac{\pi_G}{\theta} = \frac{\pi_G}{\pi_C + \pi_G}\\
+ * \end{cases}
+ * \Longleftrightarrow
+ * \begin{cases}
+ * \pi_A = \theta_1 (1 - \theta)\\
+ * \pi_C = (1 - \theta_2) \theta\\
+ * \pi_G = \theta_2 \theta\\
+ * \pi_T = (1 - \theta_1)(1 - \theta).
+ * \end{cases}
+ * \f]
+ * These parameters can also be measured from the data and not optimized.
+ *
+ * Normalization: \f$r\f$ is set so that \f$\sum_i Q_{i,i}\pi_i = -1\f$:
+ * \f[
+ * S = \frac{1}{P}\begin{pmatrix}
+ * \frac{-\pi_T-\left(1 + \kappa/\pi_R\right)\pi_G-\pi_C}{\pi_A} & 1 & \left(1 + \kappa/\pi_R\right) & 1 \\ 
+ * 1 & \frac{-\left(1 + \kappa/\pi_Y\right)\pi_T-\pi_G-\pi_A}{\pi_C} & 1 & \left(1 + \kappa/\pi_Y\right) \\ 
+ * \left(1 + \kappa/\pi_R\right) & 1 & \frac{-\pi_T-\pi_C-\left(1 + \kappa/\pi_R\right)\pi_A}{\pi_G} & 1 \\ 
+ * 1 & \left(1 + \kappa/\pi_Y\right) & 1 & \frac{-\pi_G-\left(1 + \kappa/\pi_Y\right)\pi_C-\pi_A}{\pi_T} \\ 
+ * \end{pmatrix}
+ * \f]
+ * with \f$P=2k\left({frac{piC.piT}{piT+piC}}+{\frac{piA.piG}{piG+piA}}\right)-piT^2-piG^2-piC^2-piA^2+1\f$.
+ *
+ * The normalized generator is obtained by taking the dot product of \f$S\f$ and \f$\pi\f$:
+ * \f[
+ * Q = S . \pi = \frac{1}{P}\begin{pmatrix}
+ * -\pi_T-\left(1 + \kappa/\pi_R\right)\pi_G-\pi_C & \pi_C & \left(1 + \kappa/\pi_R\right)\pi_G & \pi_T \\ 
+ * \pi_A & -\left(1 + \kappa/\pi_Y\right)\pi_T-\pi_G-\pi_A & \pi_G & \left(1 + \kappa/\pi_Y\right)\pi_T \\ 
+ * \left(1 + \kappa/\pi_R\right)\pi_A & \pi_C & -\pi_T-\pi_C-\left(1 + \kappa/\pi_R\right)\pi_A & \pi_T \\ 
+ * \pi_A & \left(1 + \kappa/\pi_Y\right)\pi_C & \pi_G & -\pi_G-\left(1 + \kappa/\pi_Y\right)\pi_C-\pi_A \\ 
+ * \end{pmatrix}
+ * \f]
+ *  
+ * The eigen values are \f$\left(0, -\frac{-1-k}{P}, -\frac{-1-k}{P}, \frac{-1}{P}\right)\f$,
+ * The left eigen vectors are, by row:
+ * \f[
+ * U = \begin{pmatrix}
+ *                    \pi_A &               \pi_C &                    \pi_G & \pi_T \\
+ *                        0 & \frac{\pi_T}{\pi_Y} &                        0 & -\frac{\pi_T}{\pi_Y} \\
+ *      \frac{\pi_G}{\pi_R} &                   0 &     -\frac{\pi_G}{\pi_R} & 0 \\
+ * \frac{\pi_A\pi_Y}{\pi_R} &              -\pi_C & \frac{\pi_G\pi_Y}{\pi_R} & -\pi_T \\
+ * \end{pmatrix}
+ * \f]
+ * and the right eigen vectors are, by column:
+ * \f[
+ * U^-1 = \begin{pmatrix}
+ * 1 &  0 &  1 &  1 \\
+ * 1 &  1 &  0 & -\frac{\pi_R}{\pi_Y} \\
+ * 1 &  0 & \frac{\pi_A}{\pi_G} &  1 \\
+ * 1 & -\frac{\pi_C}{\pi_T} &  0 & -\frac{\pi_R}{\pi_Y} \\
+ * \end{pmatrix}
+ * \f]
+ *
+ * In addition, a rate_ factor defines the mean rate of the model.
+ *
+ * The probabilities of changes are computed analytically using the formulas:
+ * \f{multline*}
+ * P_{i,j}(t) = \\
+ * \begin{pmatrix}
+ * \frac{\pi_G}{\pi_R}A + \frac{\pi_A\pi_Y}{\pi_R}B + \pi_A & \pi_C - \pi_CB & -\frac{\pi_G}{\pi_R}A + \frac{\pi_G\pi_Y}{\pi_R}B + \pi_G & \pi_T - \pi_TB \\
+ * \pi_A - \pi_AB & \frac{\pi_T}{\pi_Y}A + \frac{\pi_C\pi_R}{\pi_Y}B + \pi_C & \pi_G - \pi_GB & -\frac{\pi_T}{\pi_Y}A + \frac{\pi_T\pi_R}{\pi_Y}B + \pi_T \\
+ * -\frac{\pi_A}{\pi_R}A + \frac{\pi_A\pi_Y}{\pi_R}B + \pi_A & \pi_C - \pi_CB & \frac{\pi_A}{\pi_R}A + \frac{\pi_G\pi_Y}{\pi_R}B + \pi_G & \pi_T - \pi_TB \\
+ * \pi_A - \pi_AB & -\frac{\pi_C}{\pi_Y}A + \frac{\pi_C\pi_R}{\pi_Y}B + \pi_C & \pi_G - \pi_GB & \frac{\pi_C}{\pi_Y}A + \frac{\pi_R\pi_T}{\pi_Y}B + \pi_T \\
+ * \end{pmatrix}
+ * \f}
+ * with \f$A=e^{-\frac{rate\_*(-1-\kappa)t}{P}}\f$ and \f$B = e^{-\frac{rate\_*t}{P}}\f$. 
+ *
+ * First and second order derivatives are also computed analytically using the formulas:
+ * \f{multline*}
+ * \frac{\partial P_{i,j}(t)}{\partial t} = rate\_ * \\
+ * \frac{1}{P}
+ * \begin{pmatrix}
+ * -\frac{\pi_G((-1-\kappa))}{\pi_R}A - \frac{\pi_A\pi_Y}{\pi_R}B & \pi_CB & \frac{\pi_G((-1-\kappa))}{\pi_R}A - \frac{\pi_G\pi_Y}{\pi_R}B & \pi_TB \\
+ * \pi_AB & -\frac{\pi_T((-1-\kappa))}{\pi_Y}A - \frac{\pi_C\pi_R}{\pi_Y}B & \pi_GB & \frac{\pi_T((-1-\kappa))}{\pi_Y}A - \frac{\pi_T\pi_R}{\pi_Y}B \\
+ * \frac{\pi_A((-1-\kappa))}{\pi_R}A - \frac{\pi_A\pi_Y}{\pi_R}B & \pi_CB & -\frac{\pi_A((-1-\kappa))}{\pi_R}A - \frac{\pi_G\pi_Y}{\pi_R}B & \pi_TB \\
+ * \pi_AB & \frac{\pi_C((-1-\kappa))}{\pi_Y}A - \frac{\pi_C\pi_R}{\pi_Y}B & \pi_GB & -\frac{\pi_C((-1-\kappa))}{\pi_Y}A - \frac{\pi_R\pi_T}{\pi_Y}B \\
+ * \end{pmatrix}
+ * \f}
+ * \f{multline*}
+ * \frac{\partial^2 P_{i,j}(t)}{\partial t^2} = rate\_^2 * \\
+ * \frac{1}{P^2}
+ * \begin{pmatrix}
+ * \frac{\pi_G{((-1-\kappa))}^2}{\pi_R}A + \frac{\pi_A\pi_Y}{\pi_R}B & -\pi_CB & -\frac{\pi_G{((-1-\kappa))}^2}{\pi_R}A + \frac{\pi_G\pi_Y}{\pi_R}B & -\pi_TB \\
+ * -\pi_AB & \frac{\pi_T{((-1-\kappa))}^2}{\pi_Y}A + \frac{\pi_C\pi_R}{\pi_Y}B & -\pi_GB & -\frac{\pi_T{((-1-\kappa))}^2}{\pi_Y}A + \frac{\pi_T\pi_R}{\pi_Y}B \\
+ * -\frac{\pi_A{((-1-\kappa))}^2}{\pi_R}A + \frac{\pi_A\pi_Y}{\pi_R}B & -\pi_CB & \frac{\pi_A{((-1-\kappa))}^2}{\pi_R}A + \frac{\pi_G\pi_Y}{\pi_R}B & -\pi_TB \\
+ * -\pi_AB & -\frac{\pi_C{((-1-\kappa))}^2}{\pi_Y}A + \frac{\pi_C\pi_R}{\pi_Y}B & -\pi_GB & \frac{\pi_C{((-1-\kappa))}^2}{\pi_Y}A + \frac{\pi_R\pi_T}{\pi_Y}B \\
+ * \end{pmatrix}
+ * \f}
+ *
+ * The parameters are named \c "kappa", \c "theta", \c "theta1" and \c "theta2"
+ * and their values may be retrieve with the command 
+ * \code
+ * getParameterValue("kappa")
+ * \endcode
+ * for instance.
+ *
+ * Reference:
+ * - Felsenstein (1984), Phylip version 2.6. 
+ */
+class F84:
+  public virtual NucleotideSubstitutionModel,
+  public AbstractReversibleSubstitutionModel
+{
+  private:
+    double kappa_, piA_, piC_, piG_, piT_, piY_, piR_, r_, k1_, k2_, theta_, theta1_, theta2_;
+    mutable double l_, exp1_, exp2_;
+    mutable RowMatrix<double> p_;
+
+  public:
+    F84(
+      const NucleicAlphabet * alpha,
+      double kappa = 1.,
+      double piA = 0.25,
+      double piC = 0.25,
+      double piG = 0.25,
+      double piT = 0.25);
+  
+    virtual ~F84() {}
+
+#ifndef NO_VIRTUAL_COV
+    F84*
+#else
+    Clonable*
+#endif
+    clone() const { return new F84(*this); }
+
+  public:
+
+    double Pij_t    (int i, int j, double d) const;
+    double dPij_dt  (int i, int j, double d) const;
+    double d2Pij_dt2(int i, int j, double d) const;
+    const Matrix<double> & getPij_t    (double d) const;
+    const Matrix<double> & getdPij_dt  (double d) const;
+    const Matrix<double> & getd2Pij_dt2(double d) const;
+
+    std::string getName() const { return "F84"; }
+
+    /**
+     * @brief This method is redefined to actualize the corresponding parameters piA, piT, piG and piC too.
+     */
+  void setFreq(std::map<int, double>&);
+  
+  protected:
+    void updateMatrices();
+};
+
+} //end of namespace bpp.
+
+#endif  //_F84_H_
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/GTR.cpp b/src/Bpp/Phyl/Model/Nucleotide/GTR.cpp
new file mode 100755
index 0000000..736f38e
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/GTR.cpp
@@ -0,0 +1,151 @@
+//
+// File: GTR.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Oct 25 10:21 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "GTR.h"
+#include "../FrequenciesSet/NucleotideFrequenciesSet.h"
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+// From the STL:
+#include <cmath>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+GTR::GTR(
+    const NucleicAlphabet* alpha,
+    double a,
+    double b,
+    double c,
+    double d,
+    double e,
+    double piA,
+    double piC,
+    double piG,
+    double piT) :
+  AbstractParameterAliasable("GTR."),
+  AbstractSubstitutionModel(alpha, "GTR."),
+  AbstractReversibleSubstitutionModel(alpha, "GTR."),
+  a_(a), b_(b), c_(c), d_(d), e_(e), piA_(piA), piC_(piC), piG_(piG), piT_(piT), theta_(piG + piC), theta1_(piA / (1. - theta_)), theta2_(piG / theta_), p_()
+{
+  addParameter_(new Parameter("GTR.a", a, &Parameter::R_PLUS_STAR));
+  addParameter_(new Parameter("GTR.b", b, &Parameter::R_PLUS_STAR));
+  addParameter_(new Parameter("GTR.c", c, &Parameter::R_PLUS_STAR));
+  addParameter_(new Parameter("GTR.d", d, &Parameter::R_PLUS_STAR));
+  addParameter_(new Parameter("GTR.e", e, &Parameter::R_PLUS_STAR));
+  //jdutheil on 07/02/11: is this still needed? If yes, we should also change it in all models in order to facilitate parameter aliasing...
+  //Parameter thetaP("GTR.theta", theta_ , new IncludingInterval(0.001, 0.999), true); //Avoid numerical errors close to the bounds.
+  addParameter_(new Parameter("GTR.theta", theta_, &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+  //Parameter theta1P("GTR.theta1", theta1_, new IncludingInterval(0.001, 0.999), true);
+  addParameter_(new Parameter("GTR.theta1", theta1_, &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+  //Parameter theta2P("GTR.theta2", theta2_, new IncludingInterval(0.001, 0.999), true);
+  addParameter_(new Parameter("GTR.theta2", theta2_, &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+  updateMatrices();
+}
+
+/******************************************************************************/
+  
+void GTR::updateMatrices()
+{
+  a_ = getParameterValue("a");
+  b_ = getParameterValue("b");
+  c_ = getParameterValue("c");
+  d_ = getParameterValue("d");
+  e_ = getParameterValue("e");
+  theta_  = getParameterValue("theta");
+  theta1_ = getParameterValue("theta1");
+  theta2_ = getParameterValue("theta2");
+  piA_ = theta1_ * (1. - theta_);
+  piC_ = (1. - theta2_) * theta_;
+  piG_ = theta2_ * theta_;
+  piT_ = (1. - theta1_) * (1. - theta_);
+  p_ = 2*(a_*piC_*piT_+b_*piA_*piT_+c_*piG_*piT_+d_*piA_*piC_+e_*piC_*piG_+piA_*piG_);
+
+  freq_[0] = piA_;
+  freq_[1] = piC_;
+  freq_[2] = piG_;
+  freq_[3] = piT_;
+  
+  // Exchangeability matrix:
+  exchangeability_(0,0) = (-b_*piT_-piG_-d_*piC_)/(piA_ * p_);
+  exchangeability_(1,0) = d_/p_;
+  exchangeability_(0,1) = d_/p_;
+  exchangeability_(2,0) = 1/p_;
+  exchangeability_(0,2) = 1/p_;
+  exchangeability_(3,0) = b_/p_;
+  exchangeability_(0,3) = b_/p_;
+  exchangeability_(1,1) = (-a_*piT_-e_*piG_-d_*piA_)/(piC_ * p_);
+  exchangeability_(1,2) = e_/p_;
+  exchangeability_(2,1) = e_/p_;
+  exchangeability_(1,3) = a_/p_;
+  exchangeability_(3,1) = a_/p_;
+  exchangeability_(2,2) = (-c_*piT_-e_*piC_-piA_)/(piG_ * p_);
+  exchangeability_(2,3) = c_/p_;
+  exchangeability_(3,2) = c_/p_;
+  exchangeability_(3,3) = (-c_*piG_-a_*piC_-b_*piA_)/(piT_ * p_);
+
+  AbstractReversibleSubstitutionModel::updateMatrices();
+}
+
+/******************************************************************************/
+
+void GTR::setFreq(map<int, double>& freqs)
+{
+  piA_ = freqs[0];
+  piC_ = freqs[1];
+  piG_ = freqs[2];
+  piT_ = freqs[3];
+  vector<string> thetas(3);
+  thetas[0] = getNamespace() + "theta";
+  thetas[1] = getNamespace() + "theta1";
+  thetas[2] = getNamespace() + "theta2";
+  ParameterList pl = getParameters().subList(thetas);
+  pl[0].setValue(piC_ + piG_);
+  pl[1].setValue(piA_ / (piA_ + piT_));
+  pl[2].setValue(piG_ / (piC_ + piG_));
+  setParametersValues(pl);
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/GTR.h b/src/Bpp/Phyl/Model/Nucleotide/GTR.h
new file mode 100755
index 0000000..02b0a70
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/GTR.h
@@ -0,0 +1,183 @@
+//
+// File: GTR.h
+// Created by: Julien Dutheil
+// Created on: Tue Oct 25 10:17 2005
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _GTR_H_
+#define _GTR_H_
+
+#include "NucleotideSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+
+#include <Bpp/Numeric/Constraints.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The General Time-Reversible substitution model for nucleotides.
+ *
+ * This model is sometimes called the REV model, following Yang (1994), see references.
+ * It was used in Lanave et al (1984), described in Tavare et al. 1886 and Rodriguez et al. 1990.
+ * It is the most general reversible one, it has 6 substitution rates and 4 frequency
+ * parameters.
+ * We used the parametrization proposed by Yang (1994):
+ * \f[
+ * S = \begin{pmatrix}
+ * \cdots & d & f & b \\ 
+ * d & \cdots & e & a \\ 
+ * f & e & \cdots & c \\ 
+ * b & a & c & \cdots \\ 
+ * \end{pmatrix}
+ * \f]
+ * \f[
+ * \pi = \left(\pi_A, \pi_C, \pi_G, \pi_T\right)
+ * \f]
+ * This models hence includes nine parameters, five relative rates \f$a, b, c, d, e\f$
+ * and four frequencies \f$\pi_A, \pi_C, \pi_G, \pi_T\f$.
+ * These four frequencies are not independent parameters, since they have the constraint to
+ * sum to 1.
+ * We use instead a different parametrization to remove this constraint:
+ * \f[
+ * \begin{cases}
+ * \theta = \pi_C + \pi_G\\
+ * \theta_1 = \frac{\pi_A}{1 - \theta} = \frac{\pi_A}{\pi_A + \pi_T}\\
+ * \theta_2 = \frac{\pi_G}{\theta} = \frac{\pi_G}{\pi_C + \pi_G}\\
+ * \end{cases}
+ * \Longleftrightarrow
+ * \begin{cases}
+ * \pi_A = \theta_1 (1 - \theta)\\
+ * \pi_C = (1 - \theta_2) \theta\\
+ * \pi_G = \theta_2 \theta\\
+ * \pi_T = (1 - \theta_1)(1 - \theta).
+ * \end{cases}
+ * \f]
+ * These parameters can also be measured from the data and not optimized.
+ *
+ * Normalization: we set \f$f\f$ to 1, and scale the matrix so that \f$\sum_i Q_{i,i}\pi_i = -1\f$.
+ * Parameters \f$a,b,c,d,e\f$ are hence relative rates.
+ * \f[
+ * S = \frac{1}{P}\begin{pmatrix}
+ * \frac{-b\pi_T-\pi_G-d\pi_C}{\pi_A} & d & 1 & b \\ 
+ * d & \frac{-a\pi_T-e\pi_G-d\pi_A}{\pi_C} & e & a \\ 
+ * 1 & e & \frac{-c\pi_T-e\pi_C-\pi_A}{\pi_G} & c \\ 
+ * b & a & c & \frac{-c\pi_G-a\pi_C-b\pi_A}{\pi_T} \\ 
+ * \end{pmatrix}
+ * \f]
+ * with \f{eqnarray*}
+ * P &=& \pi_A(d\pi_C+ \pi_G+b\pi_T)\\
+ *   &+& \pi_C(d\pi_A+e\pi_G+a\pi_T)\\
+ *   &+& \pi_G( \pi_A+e\pi_C+c\pi_T)\\
+ *   &+& \pi_T(b\pi_A+a\pi_C+c\pi_G)\\
+ *   &=& 2*(a*\pi_C*\pi_T+b*\pi_A*\pi_T+c*\pi_G*\pi_T+d*\pi_A*\pi_C+e*\pi_C*\pi_G+\pi_A*\pi_G)
+ * \f}
+ *
+ * The normalized generator is obtained by taking the dot product of \f$S\f$ and \f$\pi\f$:
+ * \f[
+ * Q = S . \pi = \frac{1}{P}\begin{pmatrix}
+ * -b\pi_T-\pi_G-d\pi_C & d\pi_C & \pi_G & b\pi_T \\ 
+ * d\pi_A & -a\pi_T-e\pi_G-d\pi_A & e\pi_G & a\pi_T \\ 
+ * \pi_A & e\pi_C & -c\pi_T-e\pi_C-\pi_A & c\pi_T \\ 
+ * b\pi_A & a\pi_C & c\pi_G & -c\pi_G-a\pi_C-b\pi_A \\ 
+ * \end{pmatrix}
+ * \f]
+ *
+ * For now, the generator of this model is diagonalized numericaly.
+ * See AbstractSubstitutionModel for details of how the porbabilities are computed.
+ *
+ * The parameters are named \c "a", \c "b", \c "c", \c "d", \c "e", \c "theta", \c "theta1", and \c "theta2"
+ * and their values may be retrieve with the command 
+ * \code
+ * getParameterValue("a")
+ * \endcode
+ * for instance.
+ * 
+ * Reference:
+ * - Yang Z (1994), Journal_ Of Molecular Evolution_ 39(1) 105-11.
+ * - Lanave C, Preparata G, Saccone C and Serio G (1984), Journal_ Of Molecular Evolution_ 20 86-93.
+ * - Tavaré S (1986), Lect_. Math. Life Sci._ 17 57-86.
+ * - Rodriguez F (1990, Journal_ Of Theoretical Biology_ 142(4) 485-501.
+ */
+class GTR:
+  public virtual NucleotideSubstitutionModel,
+  public AbstractReversibleSubstitutionModel
+{
+  protected:
+    double a_, b_, c_, d_, e_, piA_, piC_, piG_, piT_, theta_, theta1_, theta2_, p_;
+
+  public:
+    GTR(
+      const NucleicAlphabet * alpha,
+      double a = 1.,
+      double b = 1.,
+      double c = 1.,
+      double d = 1.,
+      double e = 1.,
+      double piA = 0.25,
+      double piC = 0.25,
+      double piG = 0.25,
+      double piT = 0.25);
+  
+    virtual ~GTR() {}
+
+#ifndef NO_VIRTUAL_COV
+    GTR*
+#else
+    Clonable*
+#endif
+    clone() const { return new GTR(*this); }
+
+  public:
+    std::string getName() const { return "GTR"; }
+  
+  void updateMatrices();
+
+
+  /**
+   * @brief This method is redefined to actualize the corresponding parameters piA, piT, piG and piC too.
+   */
+
+  void setFreq(std::map<int,double>& freqs);
+};
+
+} //end of namespace bpp.
+
+#endif  //_GTR_H_
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/HKY85.cpp b/src/Bpp/Phyl/Model/Nucleotide/HKY85.cpp
new file mode 100755
index 0000000..574b66f
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/HKY85.cpp
@@ -0,0 +1,476 @@
+//
+// File: HKY85.cpp
+// Created by: Julien Dutheil
+// Created on: Thu Jan 22 16:17:39 2004
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "HKY85.h"
+#include "../FrequenciesSet/NucleotideFrequenciesSet.h"
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <cmath>
+
+using namespace std;
+
+/******************************************************************************/
+
+HKY85::HKY85(
+	const NucleicAlphabet* alpha,
+	double kappa,
+	double piA,
+	double piC,
+	double piG,
+	double piT):
+  AbstractParameterAliasable("HKY85."),
+  AbstractSubstitutionModel(alpha, "HKY85."),
+  AbstractReversibleSubstitutionModel(alpha, "HKY85."),
+  kappa_(kappa), k1_(), k2_(), r_(),
+  piA_(piA), piC_(piC), piG_(piG), piT_(piT), piY_(), piR_(),
+  theta_(piG + piC), theta1_(piA / (1. - theta_)), theta2_(piG / theta_),
+  exp1_(), exp21_(), exp22_(), l_(), p_(size_, size_)
+{
+	addParameter_(new Parameter("HKY85.kappa", kappa, &Parameter::R_PLUS_STAR));
+	addParameter_(new Parameter("HKY85.theta" , theta_, &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+	addParameter_(new Parameter("HKY85.theta1", theta1_, &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+	addParameter_(new Parameter("HKY85.theta2", theta2_, &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+	updateMatrices();
+}
+
+/******************************************************************************/
+
+void HKY85::updateMatrices()
+{
+	kappa_  = getParameterValue("kappa");
+	theta_  = getParameterValue("theta");
+	theta1_ = getParameterValue("theta1");
+	theta2_ = getParameterValue("theta2");
+  piA_ = theta1_ * (1. - theta_);
+  piC_ = (1. - theta2_) * theta_;
+  piG_ = theta2_ * theta_;
+  piT_ = (1. - theta1_) * (1. - theta_);
+	piR_   = piA_ + piG_;
+	piY_   = piT_ + piC_;
+	k1_    = kappa_ * piY_ + piR_;
+	k2_    = kappa_ * piR_ + piY_;
+
+  freq_[0] = piA_;
+  freq_[1] = piC_;
+  freq_[2] = piG_;
+  freq_[3] = piT_;
+	
+	generator_(0, 0) = -(                     piC_ + kappa_*piG_ +        piT_);
+	generator_(1, 1) = -(       piA_ +                      piG_ + kappa_*piT_); 
+	generator_(2, 2) = -(kappa_*piA_ +        piC_               +       piT_);
+	generator_(3, 3) = -(       piA_ + kappa_*piC_ +        piG_             );
+
+	generator_(1, 0) = piA_;
+	generator_(3, 0) = piA_;
+	generator_(0, 1) = piC_;
+	generator_(2, 1) = piC_;
+	generator_(1, 2) = piG_;
+	generator_(3, 2) = piG_;
+	generator_(0, 3) = piT_;
+	generator_(2, 3) = piT_;
+	
+	generator_(2, 0) = kappa_ * piA_;
+	generator_(3, 1) = kappa_ * piC_;
+	generator_(0, 2) = kappa_ * piG_;
+	generator_(1, 3) = kappa_ * piT_;
+	
+	// Normalization:
+	r_ = 1. / (2. * (piA_ * piC_ + piC_ * piG_ + piA_ * piT_ + piG_ * piT_ + kappa_ * (piC_ * piT_ + piA_ * piG_)));
+	MatrixTools::scale(generator_, r_);
+	
+	// Exchangeability:
+	exchangeability_(0,0) = generator_(0,0) / piA_;
+	exchangeability_(0,1) = generator_(0,1) / piC_; 
+	exchangeability_(0,2) = generator_(0,2) / piG_; 
+	exchangeability_(0,3) = generator_(0,3) / piT_;
+
+	exchangeability_(1,0) = generator_(1,0) / piA_; 
+	exchangeability_(1,1) = generator_(1,1) / piC_; 
+	exchangeability_(1,2) = generator_(1,2) / piG_; 
+	exchangeability_(1,3) = generator_(1,3) / piT_; 
+	
+	exchangeability_(2,0) = generator_(2,0) / piA_; 
+	exchangeability_(2,1) = generator_(2,1) / piC_; 
+	exchangeability_(2,2) = generator_(2,2) / piG_; 
+	exchangeability_(2,3) = generator_(2,3) / piT_; 
+	
+	exchangeability_(3,0) = generator_(3,0) / piA_;
+	exchangeability_(3,1) = generator_(3,1) / piC_; 
+	exchangeability_(3,2) = generator_(3,2) / piG_; 
+	exchangeability_(3,3) = generator_(3,3) / piT_;
+
+	// Eigen values:
+	eigenValues_[0] = 0;
+	eigenValues_[1] = -r_ * (kappa_ * piY_ + piR_);
+	eigenValues_[2] = -r_ * (kappa_ * piR_ + piY_); 
+	eigenValues_[3] = -r_;
+	
+	// Eigen vectors:
+	leftEigenVectors_(0,0) = piA_;
+	leftEigenVectors_(0,1) = piC_;
+	leftEigenVectors_(0,2) = piG_;
+	leftEigenVectors_(0,3) = piT_;
+
+	leftEigenVectors_(1,0) = 0.;
+	leftEigenVectors_(1,1) = piT_ / piY_;
+	leftEigenVectors_(1,2) = 0.;
+	leftEigenVectors_(1,3) = -piT_ / piY_;
+
+	leftEigenVectors_(2,0) = piG_ / piR_;
+	leftEigenVectors_(2,1) = 0.;
+	leftEigenVectors_(2,2) = -piG_ / piR_;
+	leftEigenVectors_(2,3) = 0.;
+
+	leftEigenVectors_(3,0) = piA_*piY_ / piR_;
+	leftEigenVectors_(3,1) = -piC_;
+	leftEigenVectors_(3,2) = piG_*piY_ / piR_;
+	leftEigenVectors_(3,3) = -piT_;
+
+	rightEigenVectors_(0,0) = 1.;
+	rightEigenVectors_(0,1) = 0.;
+	rightEigenVectors_(0,2) = 1.;
+	rightEigenVectors_(0,3) = 1.;
+	
+	rightEigenVectors_(1,0) = 1.;
+	rightEigenVectors_(1,1) = 1.;
+	rightEigenVectors_(1,2) = 0.;;
+	rightEigenVectors_(1,3) = -piR_ / piY_;
+
+	rightEigenVectors_(2,0) = 1.;
+	rightEigenVectors_(2,1) = 0.;
+	rightEigenVectors_(2,2) = -piA_ / piG_;
+	rightEigenVectors_(2,3) = 1.;
+
+	rightEigenVectors_(3,0) = 1.;
+	rightEigenVectors_(3,1) = -piC_ / piT_;
+	rightEigenVectors_(3,2) = 0.;
+	rightEigenVectors_(3,3) = -piR_ / piY_;
+}
+	
+/******************************************************************************/
+
+double HKY85::Pij_t(int i, int j, double d) const
+{
+	l_     = rate_ * r_ * d;
+	exp1_  = exp(-l_);
+	exp22_ = exp(-k2_ * l_);
+	exp21_ = exp(-k1_ * l_);
+	
+	switch(i)
+  {
+		//A
+		case 0 : {
+			switch(j) {
+				case 0 : return piA_ * (1. + (piY_/piR_) * exp1_) + (piG_/piR_) * exp22_; //A
+				case 1 : return piC_ * (1. -               exp1_);                        //C
+				case 2 : return piG_ * (1. + (piY_/piR_) * exp1_) - (piG_/piR_) * exp22_; //G
+				case 3 : return piT_ * (1. -               exp1_);                        //T, U
+			}
+		} 
+		//C
+		case 1 : {
+			switch(j) {
+				case 0 : return piA_ * (1. -               exp1_);                        //A
+				case 1 : return piC_ * (1. + (piR_/piY_) * exp1_) + (piT_/piY_) * exp21_; //C
+				case 2 : return piG_ * (1. -               exp1_);                        //G
+				case 3 : return piT_ * (1. + (piR_/piY_) * exp1_) - (piT_/piY_) * exp21_; //T, U
+			}
+		}
+		//G
+		case 2 : {
+			switch(j) {
+				case 0 : return piA_ * (1. + (piY_/piR_) * exp1_) - (piA_/piR_) * exp22_; //A
+				case 1 : return piC_ * (1. -               exp1_);                        //C
+				case 2 : return piG_ * (1. + (piY_/piR_) * exp1_) + (piA_/piR_) * exp22_; //G
+				case 3 : return piT_ * (1. -               exp1_);                        //T, U
+			}
+		}
+		//T, U
+		case 3 : {
+			switch(j) {
+				case 0 : return piA_ * (1. -               exp1_);                        //A
+				case 1 : return piC_ * (1. + (piR_/piY_) * exp1_) - (piC_/piY_) * exp21_; //C
+				case 2 : return piG_ * (1. -               exp1_);                        //G
+				case 3 : return piT_ * (1. + (piR_/piY_) * exp1_) + (piC_/piY_) * exp21_; //T, U
+			}
+		}
+	}
+	return 0;
+}
+
+/******************************************************************************/
+
+double HKY85::dPij_dt(int i, int j, double d) const
+{
+	l_     = rate_ * r_ * d;
+	exp1_  = exp(-l_);
+	exp22_ = exp(-k2_ * l_);
+	exp21_ = exp(-k1_ * l_);
+	
+	switch(i)
+  {
+		//A
+		case 0 : {
+			switch(j) {
+				case 0 : return rate_ * r_ * (piA_ * -(piY_/piR_) * exp1_ - (piG_/piR_) * k2_ * exp22_); //A
+				case 1 : return rate_ * r_ * (piC_ *                exp1_);                              //C
+				case 2 : return rate_ * r_ * (piG_ * -(piY_/piR_) * exp1_ + (piG_/piR_) * k2_ * exp22_); //G
+				case 3 : return rate_ * r_ * (piT_ *                exp1_);                              //T, U
+			}
+		} 
+		//C
+		case 1 : {
+			switch(j) {
+				case 0 : return rate_ * r_ * (piA_ *                exp1_);                              //A
+				case 1 : return rate_ * r_ * (piC_ * -(piR_/piY_) * exp1_ - (piT_/piY_) * k1_ * exp21_); //C
+				case 2 : return rate_ * r_ * (piG_ *                exp1_);                              //G
+				case 3 : return rate_ * r_ * (piT_ * -(piR_/piY_) * exp1_ + (piT_/piY_) * k1_ * exp21_); //T, U
+			}
+		}
+		//G
+		case 2 : {
+			switch(j) {
+				case 0 : return rate_ * r_ * (piA_ * -(piY_/piR_) * exp1_ + (piA_/piR_) * k2_ * exp22_); //A
+				case 1 : return rate_ * r_ * (piC_ *                exp1_);                              //C
+				case 2 : return rate_ * r_ * (piG_ * -(piY_/piR_) * exp1_ - (piA_/piR_) * k2_ * exp22_); //G
+				case 3 : return rate_ * r_ * (piT_ *                exp1_);                              //T, U
+			}
+		}
+		//T, U
+		case 3 : {
+			switch(j) {
+				case 0 : return rate_ * r_ * (piA_ *                exp1_);                              //A
+				case 1 : return rate_ * r_ * (piC_ * -(piR_/piY_) * exp1_ + (piC_/piY_) * k1_ * exp21_); //C
+				case 2 : return rate_ * r_ * (piG_ *                exp1_);                              //G
+				case 3 : return rate_ * r_ * (piT_ * -(piR_/piY_) * exp1_ - (piC_/piY_) * k1_ * exp21_); //T, U
+			}
+		}
+	}
+	return 0;
+}
+
+/******************************************************************************/
+
+double HKY85::d2Pij_dt2(int i, int j, double d) const
+{
+	double r_2 = rate_ * rate_ * r_ * r_;
+	l_ = rate_ * r_ * d;
+	double k1_2 = k1_ * k1_;
+	double k2_2 = k2_ * k2_;
+	exp1_ = exp(-l_);
+	exp22_ = exp(-k2_ * l_);
+	exp21_ = exp(-k1_ * l_);
+	
+	switch(i)
+  {
+		//A
+		case 0 : {
+			switch(j) {
+				case 0 : return r_2 * (piA_ * (piY_/piR_) * exp1_ + (piG_/piR_) * k2_2 * exp22_); //A
+				case 1 : return r_2 * (piC_ *             - exp1_);                               //C
+				case 2 : return r_2 * (piG_ * (piY_/piR_) * exp1_ - (piG_/piR_) * k2_2 * exp22_); //G
+				case 3 : return r_2 * (piT_ *             - exp1_);                               //T, U
+			}
+		} 
+		//C
+		case 1 : {
+			switch(j) {
+				case 0 : return r_2 * (piA_ *             - exp1_);                               //A
+				case 1 : return r_2 * (piC_ * (piR_/piY_) * exp1_ + (piT_/piY_) * k1_2 * exp21_); //C
+				case 2 : return r_2 * (piG_ *             - exp1_);                               //G
+				case 3 : return r_2 * (piT_ * (piR_/piY_) * exp1_ - (piT_/piY_) * k1_2 * exp21_); //T, U
+			}
+		}
+		//G
+		case 2 : {
+			switch(j) {
+				case 0 : return r_2 * (piA_ * (piY_/piR_) * exp1_ - (piA_/piR_) * k2_2 * exp22_); //A
+				case 1 : return r_2 * (piC_ *             - exp1_);                               //C
+				case 2 : return r_2 * (piG_ * (piY_/piR_) * exp1_ + (piA_/piR_) * k2_2 * exp22_); //G
+				case 3 : return r_2 * (piT_ *             - exp1_);                               //T, U
+			}
+		}
+		//T, U
+		case 3 : {
+			switch(j) {
+				case 0 : return r_2 * (piA_ *             - exp1_);                              //A
+				case 1 : return r_2 * (piC_ * (piR_/piY_) * exp1_ - (piC_/piY_) * k1_2 * exp21_); //C
+				case 2 : return r_2 * (piG_ *             - exp1_);                              //G
+				case 3 : return r_2 * (piT_ * (piR_/piY_) * exp1_ + (piC_/piY_) * k1_2 * exp21_); //T, U
+			}
+		}
+	}
+	return 0;
+}
+
+/******************************************************************************/
+
+const Matrix<double> & HKY85::getPij_t(double d) const
+{
+  l_ = rate_ * r_ * d;
+	exp1_ = exp(-l_);
+	exp22_ = exp(-k2_ * l_);
+	exp21_ = exp(-k1_ * l_);
+
+	//A
+	p_(0, 0) = piA_ * (1. + (piY_/piR_) * exp1_) + (piG_/piR_) * exp22_; //A
+	p_(0, 1) = piC_ * (1. -               exp1_);                        //C
+	p_(0, 2) = piG_ * (1. + (piY_/piR_) * exp1_) - (piG_/piR_) * exp22_; //G
+	p_(0, 3) = piT_ * (1. -               exp1_);                        //T, U
+
+	//C
+	p_(1, 0) = piA_ * (1. -               exp1_);                        //A
+	p_(1, 1) = piC_ * (1. + (piR_/piY_) * exp1_) + (piT_/piY_) * exp21_; //C
+	p_(1, 2) = piG_ * (1. -               exp1_);                        //G
+	p_(1, 3) = piT_ * (1. + (piR_/piY_) * exp1_) - (piT_/piY_) * exp21_; //T, U
+
+	//G
+	p_(2, 0) = piA_ * (1. + (piY_/piR_) * exp1_) - (piA_/piR_) * exp22_; //A
+	p_(2, 1) = piC_ * (1. -               exp1_);                        //C
+	p_(2, 2) = piG_ * (1. + (piY_/piR_) * exp1_) + (piA_/piR_) * exp22_; //G
+	p_(2, 3) = piT_ * (1. -               exp1_);                        //T, U
+
+	//T, U
+	p_(3, 0) = piA_ * (1. -               exp1_);                        //A
+	p_(3, 1) = piC_ * (1. + (piR_/piY_) * exp1_) - (piC_/piY_) * exp21_; //C
+	p_(3, 2) = piG_ * (1. -               exp1_);                        //G
+	p_(3, 3) = piT_ * (1. + (piR_/piY_) * exp1_) + (piC_/piY_) * exp21_; //T, U
+
+	return p_;
+}
+
+const Matrix<double> & HKY85::getdPij_dt(double d) const
+{
+	l_ = rate_ * r_ * d;
+	exp1_ = exp(-l_);
+	exp22_ = exp(-k2_ * l_);
+	exp21_ = exp(-k1_ * l_);
+
+	//A
+	p_(0, 0) = rate_ * r_ * (piA_ * -(piY_/piR_) * exp1_ - (piG_/piR_) * k2_ * exp22_); //A
+	p_(0, 1) = rate_ * r_ * (piC_ *                exp1_);                              //C
+	p_(0, 2) = rate_ * r_ * (piG_ * -(piY_/piR_) * exp1_ + (piG_/piR_) * k2_ * exp22_); //G
+	p_(0, 3) = rate_ * r_ * (piT_ *                exp1_);                              //T, U
+
+	//C
+	p_(1, 0) = rate_ * r_ * (piA_ *                exp1_);                              //A
+	p_(1, 1) = rate_ * r_ * (piC_ * -(piR_/piY_) * exp1_ - (piT_/piY_) * k1_ * exp21_); //C
+	p_(1, 2) = rate_ * r_ * (piG_ *                exp1_);                              //G
+	p_(1, 3) = rate_ * r_ * (piT_ * -(piR_/piY_) * exp1_ + (piT_/piY_) * k1_ * exp21_); //T, U
+
+	//G
+	p_(2, 0) = rate_ * r_ * (piA_ * -(piY_/piR_) * exp1_ + (piA_/piR_) * k2_ * exp22_); //A
+	p_(2, 1) = rate_ * r_ * (piC_ *                exp1_);                              //C
+	p_(2, 2) = rate_ * r_ * (piG_ * -(piY_/piR_) * exp1_ - (piA_/piR_) * k2_ * exp22_); //G
+	p_(2, 3) = rate_ * r_ * (piT_ *                exp1_);                              //T, U
+
+	//T, U
+	p_(3, 0) = rate_ * r_ * (piA_ *                exp1_);                              //A
+	p_(3, 1) = rate_ * r_ * (piC_ * -(piR_/piY_) * exp1_ + (piC_/piY_) * k1_ * exp21_); //C
+	p_(3, 2) = rate_ * r_ * (piG_ *                exp1_);                              //G
+	p_(3, 3) = rate_ * r_ * (piT_ * -(piR_/piY_) * exp1_ - (piC_/piY_) * k1_ * exp21_); //T, U
+
+	return p_;
+}
+
+const Matrix<double> & HKY85::getd2Pij_dt2(double d) const
+{
+	double r_2 = rate_ * rate_ * r_ * r_;
+	l_ = rate_ * r_ * d;
+	double k1_2 = k1_ * k1_;
+	double k2_2 = k2_ * k2_;
+	exp1_ = exp(-l_);
+	exp22_ = exp(-k2_ * l_);
+	exp21_ = exp(-k1_ * l_);
+
+	//A
+	p_(0, 0) = r_2 * (piA_ * (piY_/piR_) * exp1_ + (piG_/piR_) * k2_2 * exp22_); //A
+	p_(0, 1) = r_2 * (piC_ *             - exp1_);                               //C
+	p_(0, 2) = r_2 * (piG_ * (piY_/piR_) * exp1_ - (piG_/piR_) * k2_2 * exp22_); //G
+	p_(0, 3) = r_2 * (piT_ *             - exp1_);                               //T, U
+
+	//C
+	p_(1, 0) = r_2 * (piA_ *             - exp1_);                               //A
+	p_(1, 1) = r_2 * (piC_ * (piR_/piY_) * exp1_ + (piT_/piY_) * k1_2 * exp21_); //C
+	p_(1, 2) = r_2 * (piG_ *             - exp1_);                               //G
+	p_(1, 3) = r_2 * (piT_ * (piR_/piY_) * exp1_ - (piT_/piY_) * k1_2 * exp21_); //T, U
+
+	//G
+	p_(2, 0) = r_2 * (piA_ * (piY_/piR_) * exp1_ - (piA_/piR_) * k2_2 * exp22_); //A
+	p_(2, 1) = r_2 * (piC_ *             - exp1_);                               //C
+	p_(2, 2) = r_2 * (piG_ * (piY_/piR_) * exp1_ + (piA_/piR_) * k2_2 * exp22_); //G
+	p_(2, 3) = r_2 * (piT_ *             - exp1_);                               //T, U
+
+	//T, U
+	p_(3, 0) = r_2 * (piA_ *             - exp1_);                               //A
+	p_(3, 1) = r_2 * (piC_ * (piR_/piY_) * exp1_ - (piC_/piY_) * k1_2 * exp21_); //C
+	p_(3, 2) = r_2 * (piG_ *             - exp1_);                               //G
+	p_(3, 3) = r_2 * (piT_ * (piR_/piY_) * exp1_ + (piC_/piY_) * k1_2 * exp21_); //T, U
+
+	return p_;
+}
+
+/******************************************************************************/
+
+void HKY85::setFreq(std::map<int, double>& freqs)
+{
+  piA_ = freqs[0];
+  piC_ = freqs[1];
+  piG_ = freqs[2];
+  piT_ = freqs[3];
+  vector<string> thetas(3);
+  thetas[0] = getNamespace() + "theta";
+  thetas[1] = getNamespace() + "theta1";
+  thetas[2] = getNamespace() + "theta2";
+  ParameterList pl = getParameters().subList(thetas);
+  pl[0].setValue(piC_ + piG_);
+  pl[1].setValue(piA_ / (piA_ + piT_));
+  pl[2].setValue(piG_ / (piC_ + piG_));
+  setParametersValues(pl);
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/HKY85.h b/src/Bpp/Phyl/Model/Nucleotide/HKY85.h
new file mode 100755
index 0000000..19b56a8
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/HKY85.h
@@ -0,0 +1,227 @@
+//
+// File: HKY85.h
+// Created by: Julien Dutheil
+// Created on: Thu Jan 22 16:17:39 2004
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _HKY85_H_
+#define _HKY85_H_
+
+#include "NucleotideSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+
+#include <Bpp/Numeric/Constraints.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The Hasegawa M, Kishino H and Yano T (1985) substitution model for nucleotides.
+ *
+ * This model is similar to K80 model,
+ * but allows distinct equilibrium frequencies between A, C, G and T.
+ * \f[
+ * \begin{pmatrix}
+ * \cdots & r & \kappa r & r \\ 
+ * r & \cdots & r & \kappa r \\ 
+ * \kappa r & r & \cdots & r \\ 
+ * r & \kappa r & r & \cdots \\ 
+ * \end{pmatrix}
+ * \f]
+ * \f[
+ * \pi = \left(\pi_A, \pi_C, \pi_G, \pi_T\right)
+ * \f]
+ * This models hence includes five parameters, the transition / transversion
+ * relative rate \f$\kappa\f$ and four frequencies \f$\pi_A, \pi_C, \pi_G, \pi_T\f$.
+ * These four frequencies are not independent parameters, since they have the constraint to
+ * sum to 1.
+ * We use instead a different parametrization to remove this constraint:
+ * \f[
+ * \begin{cases}
+ * \theta = \pi_C + \pi_G\\
+ * \theta_1 = \frac{\pi_A}{1 - \theta} = \frac{\pi_A}{\pi_A + \pi_T}\\
+ * \theta_2 = \frac{\pi_G}{\theta} = \frac{\pi_G}{\pi_C + \pi_G}\\
+ * \end{cases}
+ * \Longleftrightarrow
+ * \begin{cases}
+ * \pi_A = \theta_1 (1 - \theta)\\
+ * \pi_C = (1 - \theta_2) \theta\\
+ * \pi_G = \theta_2 \theta\\
+ * \pi_T = (1 - \theta_1)(1 - \theta).
+ * \end{cases}
+ * \f]
+ * These parameters can also be measured from the data and not optimized.
+ *
+ * Normalization: \f$r\f$ is set so that \f$\sum_i Q_{i,i}\pi_i = -1\f$:
+ * \f[
+ * S = \frac{1}{P}\begin{pmatrix}
+ * \frac{-\pi_T-\kappa\pi_G-\pi_C}{\pi_A} & 1 & \kappa & 1 \\ 
+ * 1 & \frac{-\kappa\pi_T-\pi_G-\pi_A}{\pi_C} & 1 & \kappa \\ 
+ * \kappa & 1 & \frac{-\pi_T-\pi_C-\kappa\pi_A}{\pi_G} & 1 \\ 
+ * 1 & \kappa & 1 & \frac{-\pi_G-\kappa\pi_C-\pi_A}{\pi_T} \\ 
+ * \end{pmatrix}
+ * \f]
+ * with \f$P=2\left(\pi_A \pi_C + \pi_C \pi_G + \pi_A \pi_T + \pi_G \pi_T + \kappa \left(\pi_C \pi_T + \pi_A \pi_G\right)\right)\f$.
+ *
+ * The normalized generator is obtained by taking the dot product of \f$S\f$ and \f$\pi\f$:
+ * \f[
+ * Q = S . \pi = \frac{1}{P}\begin{pmatrix}
+ * -\pi_T-\kappa\pi_G-\pi_C & \pi_C & \kappa\pi_G & \pi_T \\ 
+ * \pi_A & -\kappa\pi_T-\pi_G-\pi_A & \pi_G & \kappa\pi_T \\ 
+ * \kappa\pi_A & \pi_C & -\pi_T-\pi_C-\kappa\pi_A & \pi_T \\ 
+ * \pi_A & \kappa\pi_C & \pi_G & -\pi_G-\kappa\pi_C-\pi_A \\ 
+ * \end{pmatrix}
+ * \f]
+ *  
+ * The eigen values are \f$\left(0, -\frac{\pi_R + \kappa\pi_Y}{P}, -\frac{\pi_Y + \kappa\pi_R}{P}, -\frac{1}{P}\right)\f$,
+ * with \f$\pi_R=\pi_A+\pi_G\f$ and \f$\pi_Y=\pi_C+\pi_T\f$.
+ * The left eigen vectors are, by row:
+ * \f[
+ * U = \begin{pmatrix}
+ *                    \pi_A &               \pi_C &                    \pi_G & \pi_T \\
+ *                        0 & \frac{\pi_T}{\pi_Y} &                        0 & -\frac{\pi_T}{\pi_Y} \\
+ *      \frac{\pi_G}{\pi_R} &                   0 &     -\frac{\pi_G}{\pi_R} & 0 \\
+ * \frac{\pi_A\pi_Y}{\pi_R} &              -\pi_C & \frac{\pi_G\pi_Y}{\pi_R} & -\pi_T \\
+ * \end{pmatrix}
+ * \f]
+ * and the right eigen vectors are, by column:
+ * \f[
+ * U^-1 = \begin{pmatrix}
+ * 1 &  0 &  1 &  1 \\
+ * 1 &  1 &  0 & -\frac{\pi_R}{\pi_Y} \\
+ * 1 &  0 & \frac{\pi_A}{\pi_G} &  1 \\
+ * 1 & -\frac{\pi_C}{\pi_T} &  0 & -\frac{\pi_R}{\pi_Y} \\
+ * \end{pmatrix}
+ * \f]
+ *
+ * In addition, a rate_ factor defines the mean rate of the model.
+ *
+ * The probabilities of changes are computed analytically using the formulas:
+ * \f{multline*}
+ * P_{i,j}(t) = \\
+ * \begin{pmatrix}
+ * \frac{\pi_G}{\pi_R}A + \frac{\pi_A\pi_Y}{\pi_R}B + \pi_A & \pi_C - \pi_CB & -\frac{\pi_G}{\pi_R}A + \frac{\pi_G\pi_Y}{\pi_R}B + \pi_G & \pi_T - \pi_TB \\
+ * \pi_A - \pi_AB & \frac{\pi_T}{\pi_Y}A + \frac{\pi_C\pi_R}{\pi_Y}B + \pi_C & \pi_G - \pi_GB & -\frac{\pi_T}{\pi_Y}A + \frac{\pi_T\pi_R}{\pi_Y}B + \pi_T \\
+ * -\frac{\pi_A}{\pi_R}A + \frac{\pi_A\pi_Y}{\pi_R}B + \pi_A & \pi_C - \pi_CB & \frac{\pi_A}{\pi_R}A + \frac{\pi_G\pi_Y}{\pi_R}B + \pi_G & \pi_T - \pi_TB \\
+ * \pi_A - \pi_AB & -\frac{\pi_C}{\pi_Y}A + \frac{\pi_C\pi_R}{\pi_Y}B + \pi_C & \pi_G - \pi_GB & \frac{\pi_C}{\pi_Y}A + \frac{\pi_R\pi_T}{\pi_Y}B + \pi_T \\
+ * \end{pmatrix}
+ * \f}
+ * with \f$A=e^{-\frac{rate\_*(\pi_Y+\kappa\pi_R)t}{P}}\f$ and \f$B = e^{-\frac{rate\_*t}{P}}\f$. 
+ *
+ * First and second order derivatives are also computed analytically using the formulas:
+ * \f{multline*}
+ * \frac{\partial P_{i,j}(t)}{\partial t} = rate\_ * \\
+ * \frac{1}{P}
+ * \begin{pmatrix}
+ * -\frac{\pi_G(\pi_Y+\kappa\pi_R)}{\pi_R}A - \frac{\pi_A\pi_Y}{\pi_R}B & \pi_CB & \frac{\pi_G(\pi_Y+\kappa\pi_R)}{\pi_R}A - \frac{\pi_G\pi_Y}{\pi_R}B & \pi_TB \\
+ * \pi_AB & -\frac{\pi_T(\pi_R+\kappa\pi_Y)}{\pi_Y}A - \frac{\pi_C\pi_R}{\pi_Y}B & \pi_GB & \frac{\pi_T(\pi_R+\kappa\pi_Y)}{\pi_Y}A - \frac{\pi_T\pi_R}{\pi_Y}B \\
+ * \frac{\pi_A(\pi_Y+\kappa\pi_R)}{\pi_R}A - \frac{\pi_A\pi_Y}{\pi_R}B & \pi_CB & -\frac{\pi_A(\pi_Y+\kappa\pi_R)}{\pi_R}A - \frac{\pi_G\pi_Y}{\pi_R}B & \pi_TB \\
+ * \pi_AB & \frac{\pi_C(\pi_R+\kappa\pi_Y)}{\pi_Y}A - \frac{\pi_C\pi_R}{\pi_Y}B & \pi_GB & -\frac{\pi_C(\pi_R+\kappa\pi_Y)}{\pi_Y}A - \frac{\pi_R\pi_T}{\pi_Y}B \\
+ * \end{pmatrix}
+ * \f}
+ * \f{multline*}
+ * \frac{\partial^2 P_{i,j}(t)}{\partial t^2} = rate\_^2 * \\
+ * \frac{1}{P^2}
+ * \begin{pmatrix}
+ * \frac{\pi_G{(\pi_Y+\kappa\pi_R)}^2}{\pi_R}A + \frac{\pi_A\pi_Y}{\pi_R}B & -\pi_CB & -\frac{\pi_G{(\pi_Y+\kappa\pi_R)}^2}{\pi_R}A + \frac{\pi_G\pi_Y}{\pi_R}B & -\pi_TB \\
+ * -\pi_AB & \frac{\pi_T{(\pi_R+\kappa\pi_Y)}^2}{\pi_Y}A + \frac{\pi_C\pi_R}{\pi_Y}B & -\pi_GB & -\frac{\pi_T{(\pi_R+\kappa\pi_Y)}^2}{\pi_Y}A + \frac{\pi_T\pi_R}{\pi_Y}B \\
+ * -\frac{\pi_A{(\pi_Y+\kappa\pi_R)}^2}{\pi_R}A + \frac{\pi_A\pi_Y}{\pi_R}B & -\pi_CB & \frac{\pi_A{(\pi_Y+\kappa\pi_R)}^2}{\pi_R}A + \frac{\pi_G\pi_Y}{\pi_R}B & -\pi_TB \\
+ * -\pi_AB & -\frac{\pi_C{(\pi_R+\kappa\pi_Y)}^2}{\pi_Y}A + \frac{\pi_C\pi_R}{\pi_Y}B & -\pi_GB & \frac{\pi_C{(\pi_R+\kappa\pi_Y)}^2}{\pi_Y}A + \frac{\pi_R\pi_T}{\pi_Y}B \\
+  * \end{pmatrix}
+ * \f}
+ *
+ * The parameters are named \c "kappa", \c "theta", \c "theta1", and \c "theta2"
+ * and their values may be retrieve with the command 
+ * \code
+ * getParameterValue("kappa")
+ * \endcode
+ * for instance.
+ *
+ * Reference:
+ * - Hasegawa M, Kishino H and Yano T (1985), Molecular_ Biology And Evolution_ 22(2) 160-74. 
+ */
+class HKY85:
+  public virtual NucleotideSubstitutionModel,
+  public AbstractReversibleSubstitutionModel
+{
+	private:
+		double kappa_, k1_, k2_, r_, piA_, piC_, piG_, piT_, piY_, piR_, theta_, theta1_, theta2_;
+    mutable double exp1_, exp21_, exp22_, l_;
+    mutable RowMatrix<double> p_;
+
+	public:
+		HKY85(
+			const NucleicAlphabet * alpha,
+			double kappa = 1.,
+			double piA = 0.25,
+			double piC = 0.25,
+			double piG = 0.25,
+			double piT = 0.25);
+	
+		virtual ~HKY85() {}
+
+#ifndef NO_VIRTUAL_COV
+    HKY85*
+#else
+    Clonable*
+#endif
+    clone() const { return new HKY85(*this); }
+
+  public:
+		double Pij_t    (int i, int j, double d) const;
+		double dPij_dt  (int i, int j, double d) const;
+		double d2Pij_dt2(int i, int j, double d) const;
+		const Matrix<double> & getPij_t    (double d) const;
+		const Matrix<double> & getdPij_dt  (double d) const;
+		const Matrix<double> & getd2Pij_dt2(double d) const;
+
+    std::string getName() const { return "HKY85"; }
+
+  /**
+   * @brief This method is redefined to actualize the corresponding parameters piA, piT, piG and piC too.
+   */
+  void setFreq(std::map<int, double>& freqs);
+	
+  void updateMatrices();
+};
+
+} //end of namespace bpp.
+
+#endif	//_HKY85_H_
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/JCnuc.cpp b/src/Bpp/Phyl/Model/Nucleotide/JCnuc.cpp
new file mode 100644
index 0000000..8546d3c
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/JCnuc.cpp
@@ -0,0 +1,189 @@
+//
+// File: JCnuc.cpp
+// Created by: Julien Dutheil
+// Created on: Tue May 27 16:04:36 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "JCnuc.h"
+
+using namespace bpp;
+
+#include <cmath>
+
+using namespace std;
+
+/******************************************************************************/
+
+JCnuc::JCnuc(const NucleicAlphabet* alpha) :
+  AbstractParameterAliasable("JC69."),
+  AbstractSubstitutionModel(alpha, "JC69."),
+  AbstractReversibleSubstitutionModel(alpha, "JC69."),
+  exp_(),
+  p_(size_, size_)
+{
+  updateMatrices();
+}
+
+/******************************************************************************/
+
+void JCnuc::updateMatrices()
+{
+  // Frequencies:
+  freq_[0] = freq_[1] = freq_[2] = freq_[3] = 1. / 4.;
+
+  // Generator and exchangeabilities:
+  for (int i = 0; i < 4; i++)
+  {
+    for (int j = 0; j < 4; j++)
+    {
+      generator_(i, j) = (i == j) ? -1. : 1. / 3.;
+      exchangeability_(i, j) = generator_(i, j) * 4.;
+    }
+  }
+
+  // Eigen values:
+  eigenValues_[0] = 0;
+  eigenValues_[1] = eigenValues_[2] = eigenValues_[3] = -4. / 3.;
+
+  // Eigen vectors:
+  for (size_t i = 0; i < 4; i++)
+  {
+    leftEigenVectors_(0, i) = 1. / 4.;
+  }
+  for (size_t i = 1; i < 4; i++)
+  {
+    for (size_t j = 0; j < 4; j++)
+    {
+      leftEigenVectors_(i, j) = -1. / 4.;
+    }
+  }
+  leftEigenVectors_(1, 2) = 3. / 4.;
+  leftEigenVectors_(2, 1) = 3. / 4.;
+  leftEigenVectors_(3, 0) = 3. / 4.;
+
+  for (size_t i = 0; i < 4; i++)
+  {
+    rightEigenVectors_(i, 0) = 1.;
+  }
+  for (size_t i = 1; i < 4; i++)
+  {
+    rightEigenVectors_(3, i) = -1.;
+  }
+  for (size_t i = 0; i < 3; i++)
+  {
+    for (size_t j = 1; j < 4; j++)
+    {
+      rightEigenVectors_(i, j) = 0.;
+    }
+  }
+  rightEigenVectors_(2, 1) = 1.;
+  rightEigenVectors_(1, 2) = 1.;
+  rightEigenVectors_(0, 3) = 1.;
+}
+
+/******************************************************************************/
+
+double JCnuc::Pij_t(size_t i, size_t j, double d) const
+{
+  if (i == j)
+    return 1. / 4. + 3. / 4. * exp(-rate_ * 4. / 3. * d);
+  else
+    return 1. / 4. - 1. / 4. * exp(-rate_ * 4. / 3. * d);
+}
+
+/******************************************************************************/
+
+double JCnuc::dPij_dt(size_t i, size_t j, double d) const
+{
+  if (i == j)
+    return -exp(-rate_ * 4. / 3. * d) * rate_;
+  else
+    return 1. / 3. * exp(-rate_ * 4. / 3. * d) * rate_;
+}
+
+/******************************************************************************/
+
+double JCnuc::d2Pij_dt2(size_t i, size_t j, double d) const
+{
+  if (i == j)
+    return 4. / 3. * exp(-rate_ * 4. / 3. * d) * rate_ * rate_;
+  else
+    return -4. / 9. * exp(-rate_ * 4. / 3. * d) * rate_ * rate_;
+}
+
+/******************************************************************************/
+
+const Matrix<double>& JCnuc::getPij_t(double d) const
+{
+  exp_ = exp(-4. / 3. * d * rate_);
+  for (size_t i = 0; i < size_; i++)
+  {
+    for (size_t j = 0; j < size_; j++)
+    {
+      p_(i, j) = (i == j) ? 1. / 4. + 3. / 4. * exp_ : 1. / 4. - 1. / 4. * exp_;
+    }
+  }
+  return p_;
+}
+
+const Matrix<double>& JCnuc::getdPij_dt(double d) const
+{
+  exp_ = exp(-4. / 3. * d * rate_);
+  for (size_t i = 0; i < size_; i++)
+  {
+    for (size_t j = 0; j < size_; j++)
+    {
+      p_(i, j) = rate_ * ((i == j) ? -exp_ : 1. / 3. * exp_);
+    }
+  }
+  return p_;
+}
+
+const Matrix<double>& JCnuc::getd2Pij_dt2(double d) const
+{
+  exp_ = exp(-4. / 3. * d * rate_);
+  for (size_t i = 0; i < size_; i++)
+  {
+    for (size_t j = 0; j < size_; j++)
+    {
+      p_(i, j) = rate_ * rate_ * ((i == j) ? 4. / 3. * exp_ : -4. / 9. * exp_);
+    }
+  }
+  return p_;
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/JCnuc.h b/src/Bpp/Phyl/Model/Nucleotide/JCnuc.h
new file mode 100644
index 0000000..ae5dfc6
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/JCnuc.h
@@ -0,0 +1,179 @@
+//
+// File: JCnuc.h
+// Created by: Julien Dutheil
+// Created on: Tue May 27 16:04:36 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _JCNUC_H_
+#define _JCNUC_H_
+
+#include "NucleotideSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+
+namespace bpp
+{
+/**
+ * @brief The Jukes-Cantor substitution model for nucleotides.
+ *
+ * All rates equal:
+ * \f[
+ * S = \begin{pmatrix}
+ * \cdots & r & r & r \\
+ * r & \cdots & r & r \\
+ * r & r & \cdots & r \\
+ * r & r & r & \cdots \\
+ * \end{pmatrix}
+ * \f]
+ * \f[
+ * \pi = diag\left(\frac{1}{4}, \frac{1}{4}, \frac{1}{4}, \frac{1}{4}\right)
+ * \f]
+ * Normalization: \f$r\f$ is set so that \f$\sum_i Q_{i,i}\pi_i = -1\f$:
+ * \f[
+ * S = \begin{pmatrix}
+ * -4 & \frac{4}{3} & \frac{4}{3} & \frac{4}{3} \\
+ * \frac{4}{3} & -4 & \frac{4}{3} & \frac{4}{3} \\
+ * \frac{4}{3} & \frac{4}{3} & -4 & \frac{4}{3} \\
+ * \frac{4}{3} & \frac{4}{3} & \frac{4}{3} & -4 \\
+ * \end{pmatrix}
+ * \f]
+ * The normalized generator is obtained by taking the dot product of \f$S\f$ and \f$pi\f$:
+ * \f[
+ * Q = S . \pi = \begin{pmatrix}
+ * -1 & \frac{1}{3} & \frac{1}{3} & \frac{1}{3} \\
+ * \frac{1}{3} & -1 & \frac{1}{3} & \frac{1}{3} \\
+ * \frac{1}{3} & \frac{1}{3} & -1 & \frac{1}{3} \\
+ * \frac{1}{3} & \frac{1}{3} & \frac{1}{3} & -1 \\
+ * \end{pmatrix}
+ * \f]
+ *
+ * The eigen values are \f$\left(0, -\frac{4}{3}, -\frac{4}{3}, -\frac{4}{3}\right)\f$,
+ * the left eigen vectors are, by row:
+ * \f[
+ * U = \begin{pmatrix}
+ *  \frac{1}{4} &  \frac{1}{4} &  \frac{1}{4} &  \frac{1}{4} \\
+ * -\frac{1}{4} & -\frac{1}{4} &  \frac{3}{4} & -\frac{1}{4} \\
+ * -\frac{1}{4} &  \frac{3}{4} & -\frac{1}{4} & -\frac{1}{4} \\
+ *  \frac{3}{4} & -\frac{1}{4} & -\frac{1}{4} & -\frac{1}{4} \\
+ * \end{pmatrix}
+ * \f]
+ * and the right eigen vectors are, by column:
+ * \f[
+ * U^-1 = \begin{pmatrix}
+ * 1 &  0 &  0 &  1 \\
+ * 1 &  0 &  1 &  0 \\
+ * 1 &  1 &  0 &  0 \\
+ * 1 & -1 & -1 & -1 \\
+ * \end{pmatrix}
+ * \f]
+ *
+ * In addition, a rate_ factor defines the mean rate of the model.
+ *
+ * The probabilities of changes are computed analytically using the formulas:
+ * \f[
+ * P_{i,j}(t) = \begin{cases}
+ * \frac{1}{4} + \frac{3}{4}e^{-rate\_*\frac{4}{3}t} & \text{if $i=j$}, \\
+ * \frac{1}{4} - \frac{1}{4}e^{-rate\_*\frac{4}{3}t} & \text{otherwise}.
+ * \end{cases}
+ * \f]
+ *
+ * First and second order derivatives are also computed analytically using the formulas:
+ * \f[
+ * \frac{\partial P_{i,j}(t)}{\partial t} = rate\_ * \begin{cases}
+ * -e^{-rate\_*\frac{4}{3}t}           & \text{if $i=j$}, \\
+ * \frac{1}{3}e^{-rate*\frac{4}{3}t} & \text{otherwise}.
+ * \end{cases}
+ * \f]
+ * \f[
+ * \frac{\partial^2 P_{i,j}(t)}{\partial t^2} = rate\_^2 *\begin{cases}
+ * \frac{4}{3}e^{-rate\_*\frac{4}{3}t}  & \text{if $i=j$}, \\
+ * -\frac{4}{9}e^{-rate\_*\frac{4}{3}t} & \text{otherwise}.
+ * \end{cases}
+ * \f]
+ *
+ * Reference:
+ * - Jukes TH and Cantor CR (1969), Evolution_ of proteins molecules_, 121-123, in Mammalian_ protein metabolism_.
+ */
+class JCnuc :
+  public virtual NucleotideSubstitutionModel,
+  public AbstractReversibleSubstitutionModel
+{
+private:
+  mutable double exp_;
+  mutable RowMatrix<double> p_;
+
+public:
+  JCnuc(const NucleicAlphabet* alpha);
+
+  virtual ~JCnuc() {}
+
+#ifndef NO_VIRTUAL_COV
+  JCnuc*
+#else
+  Clonable*
+#endif
+  clone() const { return new JCnuc(*this); }
+
+public:
+  double Pij_t    (size_t i, size_t j, double d) const;
+  double dPij_dt  (size_t i, size_t j, double d) const;
+  double d2Pij_dt2(size_t i, size_t j, double d) const;
+  const Matrix<double>& getPij_t    (double d) const;
+  const Matrix<double>& getdPij_dt  (double d) const;
+  const Matrix<double>& getd2Pij_dt2(double d) const;
+
+  std::string getName() const { return "JC69"; }
+
+  /**
+   * @brief This method is disabled in this model since frequencies are not free parameters.
+   *
+   * Consider using the HKY85 model for instance if you want to set frequencies as parameters.
+   *
+   * @param data Useless parameter.
+   */
+  void setFreqFromData(const SequenceContainer& data) {}
+
+protected:
+  /**
+   * In the case of the model of Jukes & Cantor, this method is not usefull since
+   * the generator is fully determined. No matrice can be changed... This method is only
+   * used in the constructor of the class.
+   */
+  void updateMatrices();
+};
+} // end of namespace bpp.
+
+#endif  // _JCNUC_H_
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/K80.cpp b/src/Bpp/Phyl/Model/Nucleotide/K80.cpp
new file mode 100755
index 0000000..c0b8e45
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/K80.cpp
@@ -0,0 +1,394 @@
+//
+// File: K80.cpp
+// Created by: Julien Dutheil
+// Created on: Tue May 27 15:24:30 2003
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "K80.h"
+
+// From the STL:
+#include <cmath>
+
+using namespace bpp;
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+using namespace std;
+
+/******************************************************************************/
+
+K80::K80(const NucleicAlphabet* alpha, double kappa) :
+  AbstractParameterAliasable("K80."),
+  AbstractSubstitutionModel(alpha, "K80."),
+  AbstractReversibleSubstitutionModel(alpha, "K80."),
+  kappa_(kappa), r_(), l_(), k_(), exp1_(), exp2_(), p_(size_, size_)
+{
+	addParameter_(new Parameter(getNamespace() + "kappa", kappa, &Parameter::R_PLUS_STAR));
+	updateMatrices();
+}
+
+/******************************************************************************/
+
+void K80::updateMatrices()
+{
+  kappa_ = getParameterValue("kappa");
+	k_ = (kappa_ + 1.) / 2.;
+	r_ = 4. / (kappa_ + 2.);
+	
+  // Frequences:
+	freq_[0] = freq_[1] = freq_[2] = freq_[3] = 1. / 4.;
+
+	// Generator:
+	generator_(0, 0) = -2. - kappa_;
+	generator_(1, 1) = -2. - kappa_;
+	generator_(2, 2) = -2. - kappa_;
+	generator_(3, 3) = -2. - kappa_;
+
+	generator_(0, 1) = 1.;
+	generator_(0, 3) = 1.;
+	generator_(1, 0) = 1.;
+	generator_(1, 2) = 1.;
+	generator_(2, 1) = 1.;
+	generator_(2, 3) = 1.;
+	generator_(3, 0) = 1.;
+	generator_(3, 2) = 1.;
+	
+	generator_(0, 2) = kappa_;
+	generator_(1, 3) = kappa_;
+	generator_(2, 0) = kappa_;
+	generator_(3, 1) = kappa_;
+
+	// Normalization:
+	MatrixTools::scale(generator_, r_/4);
+
+	// Exchangeability:
+	exchangeability_ = generator_;
+	MatrixTools::scale(exchangeability_, 4.);
+
+	// Eigen values:
+	eigenValues_[0] = 0;
+	eigenValues_[1] = -r_ * (1. + kappa_)/2;
+	eigenValues_[2] = -r_ * (1. + kappa_)/2;
+	eigenValues_[3] = -r_;
+	
+	// Eigen vectors:
+	leftEigenVectors_(0,0) = 1. / 4.;
+	leftEigenVectors_(0,1) = 1. / 4.;
+	leftEigenVectors_(0,2) = 1. / 4.;
+	leftEigenVectors_(0,3) = 1. / 4.;
+	leftEigenVectors_(1,0) = 0.;
+	leftEigenVectors_(1,1) = 1. / 2.;
+	leftEigenVectors_(1,2) = 0.;
+	leftEigenVectors_(1,3) = -1. / 2.;
+	leftEigenVectors_(2,0) = 1. / 2.;
+	leftEigenVectors_(2,1) = 0.;
+	leftEigenVectors_(2,2) = -1. / 2.;
+	leftEigenVectors_(2,3) = 0.;
+	leftEigenVectors_(3,0) = 1. / 4.;
+	leftEigenVectors_(3,1) = -1. / 4.;
+	leftEigenVectors_(3,2) = 1. / 4.;
+	leftEigenVectors_(3,3) = -1. / 4.;
+
+	rightEigenVectors_(0,0) = 1.;
+	rightEigenVectors_(0,1) = 0.;
+	rightEigenVectors_(0,2) = 1.;
+	rightEigenVectors_(0,3) = 1.;
+	rightEigenVectors_(1,0) = 1.;
+	rightEigenVectors_(1,1) = 1.;
+	rightEigenVectors_(1,2) = 0.;
+	rightEigenVectors_(1,3) = -1.;
+	rightEigenVectors_(2,0) = 1.;
+	rightEigenVectors_(2,1) = 0.;
+	rightEigenVectors_(2,2) = -1.;
+	rightEigenVectors_(2,3) = 1.;
+	rightEigenVectors_(3,0) = 1.;
+	rightEigenVectors_(3,1) = -1.;
+	rightEigenVectors_(3,2) = 0;
+	rightEigenVectors_(3,3) = -1.;
+}
+	
+/******************************************************************************/
+
+double K80::Pij_t(int i, int j, double d) const
+{
+	l_ = rate_ * r_ * d;
+	exp1_ = exp(-l_);
+	exp2_ = exp(-k_ * l_);
+	
+	switch(i) {
+		//A
+		case 0 : {
+			switch(j) {
+				case 0 : return 0.25 * (1. + exp1_) + 0.5 * exp2_; //A
+				case 1 : return 0.25 * (1. - exp1_);               //C
+				case 2 : return 0.25 * (1. + exp1_) - 0.5 * exp2_; //G
+				case 3 : return 0.25 * (1. - exp1_);               //T, U
+			}
+		} 
+		//C
+		case 1 : {
+			switch(j) {
+				case 0 : return 0.25 * (1. - exp1_);               //A
+				case 1 : return 0.25 * (1. + exp1_) + 0.5 * exp2_; //C
+				case 2 : return 0.25 * (1. - exp1_);               //G
+				case 3 : return 0.25 * (1. + exp1_) - 0.5 * exp2_; //T, U
+			}
+		}
+		//G
+		case 2 : {
+			switch(j) {
+				case 0 : return 0.25 * (1. + exp1_) - 0.5 * exp2_; //A
+				case 1 : return 0.25 * (1. - exp1_);               //C
+				case 2 : return 0.25 * (1. + exp1_) + 0.5 * exp2_; //G
+				case 3 : return 0.25 * (1. - exp1_);               //T, U
+			}
+		}
+		//T, U
+		case 3 : {
+			switch(j) {
+				case 0 : return 0.25 * (1. - exp1_);               //A
+				case 1 : return 0.25 * (1. + exp1_) - 0.5 * exp2_; //C
+				case 2 : return 0.25 * (1. - exp1_);               //G
+				case 3 : return 0.25 * (1. + exp1_) + 0.5 * exp2_; //T, U
+			}
+		}
+	}
+	return 0;
+}
+
+/******************************************************************************/
+
+double K80::dPij_dt(int i, int j, double d) const
+{
+  l_ = rate_ * r_ * d;
+	exp1_ = exp(-l_);
+	exp2_ = exp(-k_ * l_);
+
+	switch(i) {
+		//A
+		case 0 : {
+			switch(j) {
+                        case 0 : return rate_ * r_/4. * (- exp1_ - 2. * k_ * exp2_); //A
+                        case 1 : return rate_ * r_/4. * (  exp1_);                   //C
+                        case 2 : return rate_ * r_/4. * (- exp1_ + 2. * k_ * exp2_); //G
+                        case 3 : return rate_ * r_/4. * (  exp1_);                   //T, U
+			}
+		} 
+		//C
+		case 1 : {
+			switch(j) {
+                        case 0 : return rate_ * r_/4. * (  exp1_);                   //A
+                        case 1 : return rate_ * r_/4. * (- exp1_ - 2. * k_ * exp2_); //C
+                        case 2 : return rate_ * r_/4. * (  exp1_);                   //G
+                        case 3 : return rate_ * r_/4. * (- exp1_ + 2. * k_ * exp2_); //T, U
+			}
+		}
+		//G
+		case 2 : {
+			switch(j) {
+                        case 0 : return rate_ * r_/4. * (- exp1_ + 2. * k_ * exp2_); //A
+                        case 1 : return rate_ * r_/4. * (  exp1_);                   //C
+                        case 2 : return rate_ * r_/4. * (- exp1_ - 2. * k_ * exp2_); //G
+                        case 3 : return rate_ * r_/4. * (  exp1_);                   //T, U
+			}
+		}
+		//T, U
+		case 3 : {
+			switch(j) {
+                        case 0 : return rate_ * r_/4. * (  exp1_);                   //A
+                        case 1 : return rate_ * r_/4. * (- exp1_ + 2. * k_ * exp2_); //C
+                        case 2 : return rate_ * r_/4. * (  exp1_);                   //G
+                        case 3 : return rate_ * r_/4. * (- exp1_ - 2. * k_ * exp2_); //T, U
+			}
+		}
+	}
+	return 0;
+}
+
+/******************************************************************************/
+
+double K80::d2Pij_dt2(int i, int j, double d) const
+{
+	double k_2 = k_ * k_;
+	double r_2 = rate_ * rate_ * r_ * r_;
+	l_ = rate_ * r_ * d;
+	exp1_ = exp(-l_);
+	exp2_ = exp(-k_ * l_);
+
+	switch(i) {
+		//A
+		case 0 : {
+			switch(j) {
+				case 0 : return r_2/4. * (  exp1_ + 2. * k_2 * exp2_); //A
+				case 1 : return r_2/4. * (- exp1_);                    //C
+				case 2 : return r_2/4. * (  exp1_ - 2. * k_2 * exp2_); //G
+				case 3 : return r_2/4. * (- exp1_);                    //T, U
+			}
+		} 
+		//C
+		case 1 : {
+			switch(j) {
+				case 0 : return r_2/4. * (- exp1_);                    //A
+				case 1 : return r_2/4. * (  exp1_ + 2. * k_2 * exp2_); //C
+				case 2 : return r_2/4. * (- exp1_);                    //G
+				case 3 : return r_2/4. * (  exp1_ - 2. * k_2 * exp2_); //T, U
+			}
+		}
+		//G
+		case 2 : {
+			switch(j) {
+				case 0 : return r_2/4. * (  exp1_ - 2. * k_2 * exp2_); //A
+				case 1 : return r_2/4. * (- exp1_);                    //C
+				case 2 : return r_2/4. * (  exp1_ + 2. * k_2 * exp2_); //G
+				case 3 : return r_2/4. * (- exp1_);                    //T, U
+			}
+		}
+		//T, U
+		case 3 : {
+			switch(j) {
+				case 0 : return r_2/4. * (- exp1_);                    //A
+				case 1 : return r_2/4. * (  exp1_ - 2. * k_2 * exp2_); //C
+				case 2 : return r_2/4. * (- exp1_);                    //G
+				case 3 : return r_2/4. * (  exp1_ + 2. * k_2 * exp2_); //T, U
+			}
+		}
+	}
+	return 0;
+}
+
+/******************************************************************************/
+
+const Matrix<double> & K80::getPij_t(double d) const
+{
+  l_ = rate_ * r_ * d;
+	exp1_ = exp(-l_);
+	exp2_ = exp(-k_ * l_);
+
+	//A
+	p_(0, 0) = 0.25 * (1. + exp1_) + 0.5 * exp2_; //A
+	p_(0, 1) = 0.25 * (1. - exp1_);               //C
+	p_(0, 2) = 0.25 * (1. + exp1_) - 0.5 * exp2_; //G
+	p_(0, 3) = 0.25 * (1. - exp1_);               //T, U
+
+	//C
+	p_(1, 0) = 0.25 * (1. - exp1_);               //A
+	p_(1, 1) = 0.25 * (1. + exp1_) + 0.5 * exp2_; //C
+	p_(1, 2) = 0.25 * (1. - exp1_);               //G
+	p_(1, 3) = 0.25 * (1. + exp1_) - 0.5 * exp2_; //T, U
+
+	//G
+	p_(2, 0) = 0.25 * (1. + exp1_) - 0.5 * exp2_; //A
+	p_(2, 1) = 0.25 * (1. - exp1_);               //C
+	p_(2, 2) = 0.25 * (1. + exp1_) + 0.5 * exp2_; //G
+	p_(2, 3) = 0.25 * (1. - exp1_);               //T, U
+
+	//T, U
+	p_(3, 0) = 0.25 * (1. - exp1_);               //A
+	p_(3, 1) = 0.25 * (1. + exp1_) - 0.5 * exp2_; //C
+	p_(3, 2) = 0.25 * (1. - exp1_);               //G
+	p_(3, 3) = 0.25 * (1. + exp1_) + 0.5 * exp2_; //T, U
+
+	return p_;
+}
+
+const Matrix<double> & K80::getdPij_dt(double d) const
+{
+  l_ = rate_ * r_ * d;
+	exp1_ = exp(-l_);
+	exp2_ = exp(-k_ * l_);
+
+	p_(0, 0) = rate_ * r_/4. * (- exp1_ - 2. * k_ * exp2_); //A
+	p_(0, 1) = rate_ * r_/4. * (  exp1_);                   //C
+	p_(0, 2) = rate_ * r_/4. * (- exp1_ + 2. * k_ * exp2_); //G
+	p_(0, 3) = rate_ * r_/4. * (  exp1_);                   //T, U
+
+	//C
+	p_(1, 0) = rate_ * r_/4. * (  exp1_);                   //A
+	p_(1, 1) = rate_ * r_/4. * (- exp1_ - 2. * k_ * exp2_); //C
+	p_(1, 2) = rate_ * r_/4. * (  exp1_);                   //G
+	p_(1, 3) = rate_ * r_/4. * (- exp1_ + 2. * k_ * exp2_); //T, U
+
+	//G
+	p_(2, 0) = rate_ * r_/4. * (- exp1_ + 2. * k_ * exp2_); //A
+	p_(2, 1) = rate_ * r_/4. * (  exp1_);                   //C
+	p_(2, 2) = rate_ * r_/4. * (- exp1_ - 2. * k_ * exp2_); //G
+	p_(2, 3) = rate_ * r_/4. * (  exp1_);                   //T, U
+
+	//T, U
+	p_(3, 0) = rate_ * r_/4. * (  exp1_);                   //A
+	p_(3, 1) = rate_ * r_/4. * (- exp1_ + 2. * k_ * exp2_); //C
+	p_(3, 2) = rate_ * r_/4. * (  exp1_);                   //G
+	p_(3, 3) = rate_ * r_/4. * (- exp1_ - 2. * k_ * exp2_); //T, U
+
+	return p_;
+}
+
+const Matrix<double> & K80::getd2Pij_dt2(double d) const
+{
+	double k_2 = k_ * k_;
+	double r_2 = rate_ * rate_ * r_ * r_;
+	l_ = rate_ * r_ * d;
+	exp1_ = exp(-l_);
+	exp2_ = exp(-k_ * l_);
+
+	p_(0, 0) = r_2/4. * (  exp1_ + 2. * k_2 * exp2_); //A
+	p_(0, 1) = r_2/4. * (- exp1_);                    //C
+	p_(0, 2) = r_2/4. * (  exp1_ - 2. * k_2 * exp2_); //G
+	p_(0, 3) = r_2/4. * (- exp1_);                    //T, U
+
+	//C
+	p_(1, 0) = r_2/4. * (- exp1_);                    //A
+	p_(1, 1) = r_2/4. * (  exp1_ + 2. * k_2 * exp2_); //C
+	p_(1, 2) = r_2/4. * (- exp1_);                    //G
+	p_(1, 3) = r_2/4. * (  exp1_ - 2. * k_2 * exp2_); //T, U
+
+	//G
+	p_(2, 0) = r_2/4. * (  exp1_ - 2. * k_2 * exp2_); //A
+	p_(2, 1) = r_2/4. * (- exp1_);                    //C
+	p_(2, 2) = r_2/4. * (  exp1_ + 2. * k_2 * exp2_); //G
+	p_(2, 3) = r_2/4. * (- exp1_);                    //T, U
+
+	//T, U
+	p_(3, 0) = r_2/4. * (- exp1_);                    //A
+	p_(3, 1) = r_2/4. * (  exp1_ - 2. * k_2 * exp2_); //C
+	p_(3, 2) = r_2/4. * (- exp1_);                    //G
+	p_(3, 3) = r_2/4. * (  exp1_ + 2. * k_2 * exp2_); //T, U
+
+	return p_;
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/K80.h b/src/Bpp/Phyl/Model/Nucleotide/K80.h
new file mode 100755
index 0000000..6e6a96a
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/K80.h
@@ -0,0 +1,198 @@
+//
+// File: K80.h
+// Created by: Julien Dutheil
+// Created on: Tue May 27 15:24:30 2003
+//
+
+/*
+  Copyright or © or Copr. CNRS, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _K80_H_
+#define _K80_H_
+
+
+#include "NucleotideSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+
+namespace bpp
+{
+
+  /**
+   * @brief The Kimura 2-rates substitution model for nucleotides.
+   *
+   * All two rates: one for transitions and one for transversions.
+   * This models include one parameter, the transition / transversion
+   * relative rate \f$\kappa\f$.
+   * \f[
+   * S = \begin{pmatrix}
+   * \cdots & r & \kappa r & r \\ 
+   * r & \cdots & r & \kappa r \\ 
+   * \kappa r & r & \cdots & r \\ 
+   * r & \kappa r & r & \cdots \\ 
+   * \end{pmatrix}
+   * \f]
+   * \f[
+   * \pi = \left(\frac{1}{4}, \frac{1}{4}, \frac{1}{4}, \frac{1}{4}\right)
+   * \f]
+   * Normalization: \f$r\f$ is set so that \f$\sum_i Q_{i,i}\pi_i = -1\f$:
+   * \f[
+   * S = \begin{pmatrix}
+   * -4 & \frac{4}{\kappa+2} & \frac{4\kappa}{\kappa+2} & \frac{4}{\kappa+2} \\ 
+   * \frac{4}{\kappa+2} & -4 & \frac{4}{\kappa+2} & \frac{4\kappa}{\kappa+2} \\ 
+   * \frac{4\kappa}{\kappa+2} & \frac{4}{\kappa+2} & -4 & \frac{4}{\kappa+2} \\ 
+   * \frac{4}{\kappa+2} & \frac{4\kappa}{\kappa+2} & \frac{4}{\kappa+2} & -4 \\ 
+   * \end{pmatrix}
+   * \f]
+   * The normalized generator is obtained by taking the dot product of \f$S\f$ and \f$\pi\f$:
+   * \f[
+   * Q = S . \pi = \begin{pmatrix}
+   * -1 & \frac{1}{\kappa+2} & \frac{\kappa}{\kappa+2} & \frac{1}{\kappa+2} \\ 
+   * \frac{1}{\kappa+2} & -1 & \frac{1}{\kappa+2} & \frac{\kappa}{\kappa+2} \\ 
+   * \frac{\kappa}{\kappa+2} & \frac{1}{\kappa+2} & -1 & \frac{1}{\kappa+2} \\ 
+   * \frac{1}{\kappa+2} & \frac{\kappa}{\kappa+2} & \frac{1}{\kappa+2} & -1 \\ 
+   * \end{pmatrix}
+   * \f]
+   *  
+   * The eigen values are \f$\left(0, -\frac{2\kappa+2}{\kappa+2}, -\frac{2\kappa+2}{\kappa+2}, -\frac{4}{\kappa+2}\right)\f$, 
+   * the left eigen vectors are, by row:
+   * \f[
+   * U = \begin{pmatrix}
+   * \frac{1}{4} &  \frac{1}{4} &  \frac{1}{4} &  \frac{1}{4} \\
+   *           0 &  \frac{1}{2} &            0 & -\frac{1}{2} \\
+   * \frac{1}{2} &            0 & -\frac{1}{2} &            0 \\
+   * \frac{1}{4} & -\frac{1}{4} &  \frac{1}{4} & -\frac{1}{4} \\
+   * \end{pmatrix}
+   * \f]
+   * and the right eigen vectors are, by column:
+   * \f[
+   * U^-1 = \begin{pmatrix}
+   * 1 &  0 &  1 &  1 \\
+   * 1 &  1 &  0 & -1 \\
+   * 1 &  0 & -1 &  1 \\
+   * 1 & -1 &  0 & -1 \\
+   * \end{pmatrix}
+   * \f]
+   *
+   * In addition, a rate_ factor defines the mean rate of the model.
+   *
+   * The probabilities of changes are computed analytically using the formulas:
+   * \f[
+   * P_{i,j}(t) = \begin{pmatrix}
+   * \frac{1}{2}A + \frac{1}{4}B + \frac{1}{4} & \frac{1}{4} - \frac{1}{4}B & -\frac{1}{2}A + \frac{1}{4}B + \frac{1}{4} & \frac{1}{4} - \frac{1}{4}B \\
+   * \frac{1}{4} - \frac{1}{4}B & \frac{1}{2}A + \frac{1}{4}B + \frac{1}{4} & \frac{1}{4} - \frac{1}{4}B & -\frac{1}{2}A + \frac{1}{4}B + \frac{1}{4} \\
+   * -\frac{1}{2}A + \frac{1}{4}B + \frac{1}{4} & \frac{1}{4} - \frac{1}{4}B & \frac{1}{2}A + \frac{1}{4}B + \frac{1}{4} & \frac{1}{4} - \frac{1}{4}B \\
+   * \frac{1}{4} - \frac{1}{4}B & -\frac{1}{2}A + \frac{1}{4}B + \frac{1}{4} & \frac{1}{4} - \frac{1}{4}B & \frac{1}{2}A + \frac{1}{4}B + \frac{1}{4} \\
+   * \end{pmatrix}
+   * \f]
+   * with \f$A=e^{-\frac{rate\_ * (2\kappa+2)t}{\kappa+2}}\f$ and \f$B = e^{-\frac{rate\_ * 4t}{\kappa+2}}\f$. 
+   *
+   * First and second order derivatives are also computed analytically using the formulas:
+   * \f[
+   * \frac{\partial P_{i,j}(t)}{\partial t} = rate\_ * \begin{pmatrix}
+   * -\frac{2\kappa+2}{2(\kappa+2)}A - \frac{1}{\kappa+2}B & \frac{1}{\kappa+2}B & \frac{2\kappa+2}{2(\kappa+2)}A - \frac{1}{\kappa+2}B & \frac{1}{\kappa+2}B \\
+   * \frac{1}{\kappa+2}B & -\frac{2\kappa+2}{2(\kappa+2)}A - \frac{1}{\kappa+2}B & \frac{1}{\kappa+2}B & \frac{2\kappa+2}{2(\kappa+2)}A - \frac{1}{\kappa+2}B \\
+   * \frac{2\kappa+2}{2(\kappa+2)}A - \frac{1}{\kappa+2}B & \frac{1}{\kappa+2}B & -\frac{2\kappa+2}{2(\kappa+2)}A - \frac{1}{\kappa+2}B & \frac{1}{\kappa+2}B \\
+   * \frac{1}{\kappa+2}B & \frac{2\kappa+2}{2(\kappa+2)}A - \frac{1}{\kappa+2}B & \frac{1}{\kappa+2}B & -\frac{2\kappa+2}{2(\kappa+2)}A - \frac{1}{\kappa+2}B \\
+   * \end{pmatrix}
+   * \f]
+   * \f{multline*}
+   * \frac{\partial^2 P_{i,j}(t)}{\partial t^2} = rate\_^2 * \\
+   * \begin{pmatrix}
+   * \frac{{(2\kappa+2)}^2}{2{(\kappa+2)}^2}A - \frac{4}{{(\kappa+2)}^2}B & -\frac{4}{{(\kappa+2)}^2}B & -\frac{{(2\kappa+2)}^2}{2{(\kappa+2)}^2}A + \frac{4}{{(\kappa+2)}^2}B & -\frac{4}{{(\kappa+2)}^2}B \\
+   * -\frac{4}{{(\kappa+2)}^2}B & \frac{{(2\kappa+2)}^2}{2{(\kappa+2)}^2}A + \frac{4}{{(\kappa+2)}^2}B & -\frac{4}{{(\kappa+2)}^2}B & -\frac{{(2\kappa+2)}^2}{2{(\kappa+2)}^2}A + \frac{4}{{(\kappa+2)}^2}B \\
+   * -\frac{{(2\kappa+2)}^2}{2{(\kappa+2)}^2}A + \frac{4}{{(\kappa+2)}^2}B & -\frac{4}{{(\kappa+2)}^2}B & \frac{{(2\kappa+2)}^2}{2{(\kappa+2)}^2}A + \frac{4}{{(\kappa+2)}^2}B & -\frac{4}{{(\kappa+2)}^2}B \\
+   * -\frac{4}{{(\kappa+2)}^2}B & -\frac{2{(\kappa+2)}^2}{2{(\kappa+2)}^2}A + \frac{4}{{(\kappa+2)}^2}B & -\frac{4}{{(\kappa+2)}^2}B & \frac{2{(\kappa+2)}^2}{{(2\kappa+2)}^2}A + \frac{4}{{(\kappa+2)}^2}B \\
+   * \end{pmatrix}
+   * \f}
+   *
+   * The parameter is named \c "kappa"
+   * and its value may be retrieve with the command 
+   * \code
+   * getParameterValue("kappa")
+   * \endcode
+   * 
+   * Reference:
+   * - Kimura M (1980), Journal_ Of Molecular Evolution_ 16(2) 111-20. 
+   */
+  class K80:
+    public virtual NucleotideSubstitutionModel,
+    public AbstractReversibleSubstitutionModel
+  {
+  private:
+    double kappa_, r_;
+    mutable double l_, k_, exp1_, exp2_;
+    mutable RowMatrix<double> p_;
+
+  public:
+    K80(const NucleicAlphabet* alpha, double kappa = 1.);
+
+    virtual ~K80() {}
+
+#ifndef NO_VIRTUAL_COV
+    K80*
+#else
+    Clonable*
+#endif
+    clone() const { return new K80(*this); }
+
+  public:
+    double Pij_t    (int i, int j, double d) const;
+    double dPij_dt  (int i, int j, double d) const;
+    double d2Pij_dt2(int i, int j, double d) const;
+    const Matrix<double> & getPij_t    (double d) const;
+    const Matrix<double> & getdPij_dt  (double d) const;
+    const Matrix<double> & getd2Pij_dt2(double d) const;
+
+    std::string getName() const { return "K80"; }
+	   
+    /**
+     * @brief This method is disabled in this model since frequencies are not free parameters.
+     *
+     * Consider using the HKY85 model for instance if you want to set frequencies as parameters.
+     *
+     * @param data Useless parameter.
+     */
+    void setFreqFromData(const SequenceContainer & data) {}
+	
+  protected:
+    void updateMatrices();
+
+  };
+
+} //end of namespace bpp.
+
+#endif	//_K80_H_
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/L95.cpp b/src/Bpp/Phyl/Model/Nucleotide/L95.cpp
new file mode 100755
index 0000000..b1f71f7
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/L95.cpp
@@ -0,0 +1,118 @@
+//
+// File: L95.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Nov 4 11:46 2008
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Tools, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "L95.h"
+#include "../FrequenciesSet/NucleotideFrequenciesSet.h"
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+// From the STL:
+#include <cmath>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+ 
+L95::L95(
+	const NucleicAlphabet* alphabet,
+	double alpha, double beta, double gamma, double kappa, double theta):
+    AbstractParameterAliasable("L95."),
+    AbstractSubstitutionModel(alphabet, "L95."), alpha_(alpha), beta_(beta), gamma_(gamma), kappa_(kappa), theta_(theta)
+{
+
+  addParameter_(new Parameter("L95.alpha", alpha, &Parameter::PROP_CONSTRAINT_IN));
+  addParameter_(new Parameter("L95.beta", beta, &Parameter::PROP_CONSTRAINT_IN));
+  addParameter_(new Parameter("L95.gamma", gamma, &Parameter::PROP_CONSTRAINT_IN));
+  addParameter_(new Parameter("L95.kappa", kappa, new IntervalConstraint(0, 1000, false, false, NumConstants::MILLI()), true));
+  addParameter_(new Parameter("L95.theta", theta, new IntervalConstraint(0, 1, false, false, NumConstants::MILLI()), true));
+
+  updateMatrices();
+}
+
+/******************************************************************************/
+	
+void L95::updateMatrices()
+{
+  alpha_  = getParameterValue("alpha");
+  beta_  = getParameterValue("beta");
+  gamma_  = getParameterValue("gamma");
+  kappa_  = getParameterValue("kappa");
+  theta_  = getParameterValue("theta");
+  
+  freq_[0] = (1-theta_)/2;
+  freq_[1] = theta_/2;
+  freq_[2] = theta_/2;
+  freq_[3] = (1-theta_)/2;
+	
+  // Generator matrix:
+  generator_(0,0) = -kappa_ * theta_ - gamma_;
+  generator_(0,1) = kappa_* beta_ * theta_;
+  generator_(0,2) = kappa_ * (1-beta_) * theta_;
+  generator_(0,3) = gamma_;
+  generator_(1,0) = kappa_ * alpha_ * ( 1- theta_);
+  generator_(1,1) = -kappa_ * (1 - theta_) + gamma_ - 1;
+  generator_(1,2) = 1 - gamma_;
+  generator_(1,3) = kappa_ * (1 - theta_) * (1 - alpha_);
+  generator_(2,0) = kappa_ * (1 - theta_) * (1 - alpha_);
+  generator_(2,1) = 1 - gamma_;
+  generator_(2,2) = -kappa_ * (1 - theta_) + gamma_ - 1;
+  generator_(2,3) = kappa_ * alpha_ * (1 - theta_);
+  generator_(3,0) = gamma_;
+  generator_(3,1) = kappa_ * (1-beta_) * theta_;
+  generator_(3,2) = kappa_* beta_ * theta_;
+  generator_(3,3) = -kappa_ * theta_ - gamma_;
+
+  MatrixTools::scale(generator_, 1. / (2*kappa_*theta_*(1-theta_)+gamma_+theta_-2*theta_*gamma_));
+  AbstractSubstitutionModel::updateMatrices();
+}
+
+/******************************************************************************/
+
+void L95::setFreq(map<int, double>& freqs)
+{
+  setParameterValue("theta",freqs[1]+freqs[2]);
+  updateMatrices();
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/L95.h b/src/Bpp/Phyl/Model/Nucleotide/L95.h
new file mode 100755
index 0000000..510313d
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/L95.h
@@ -0,0 +1,132 @@
+//
+// File: L95.h
+// Created by: Laurent Guéguen
+// Created on: lundi 18 octobre 2010, à 22h 21
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _L95_H_
+#define _L95_H_
+
+#include "NucleotideSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+
+#include <Bpp/Numeric/Constraints.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The no-strand bias substitution model for nucleotides, from
+ * Lobry 1995. The point of this model is that the substitution rate
+ * from a nucleotide N towards another M is the same as the rate from
+ * the complement of N towards the complement of M. Note that this
+ * model is not reversible.
+ *
+ * After normalization, this model contains 5 parameters:
+ * \f[
+ * Q = \frac 1{2*\kappa*\theta*(1-\theta)+\gamma+\theta-2*\theta*\gamma} \begin{pmatrix}
+ * \cdots & \kappa.\beta.\theta & \kappa.(1-\beta).\theta & \gamma \\ 
+ * \kappa.\alpha.(1-\theta) & \cdots & 1-\gamma & \kappa.(1-\alpha).(1-\theta) \\ 
+ * \kappa.(1-\alpha).(1-\theta) & 1-\gamma & \cdots & \kappa.\alpha.(1-\theta) \\ 
+ * \gamma & \kappa.(1-\beta).\theta & \kappa.\beta.\theta & \cdots \\ 
+ * \end{pmatrix}
+ * \f]
+ * The equilibrium frequencies are
+ * \f[
+ * \pi = \left(\frac{1-\theta}{2}, \frac{\theta}{2}, \frac{\theta}{2}, \frac{1-\theta}{2}\right)
+ * \f]
+ *
+ * and then \f$\sum_i Q_{i,i}\pi_i = -1\f$.
+ *
+ * The generator of this model is diagonalized numerically.
+ * See AbstractSubstitutionModel for details of how the probabilities are computed.
+ *
+ * The parameters are named \c "alpha", \c "beta", \c "gamma", \c
+ * "kappa" and \c "theta". The values of \c "alpha", \c "beta", \c
+ * "gamma" are between 0 and 1, The values of \c "gamma" are between 0
+ * and 1 excluded, the values of "kappa" which are positive. Their
+ * values may be retrieved with the command:
+ *
+ * \code
+ * getParameterValue("alpha")
+ * \endcode for instance.
+ * 
+ * Reference:
+ * - Lobry J R (1995), Journal_ Of Molecular Evolution_ 40 326-330.
+ */
+class L95:
+  public virtual NucleotideSubstitutionModel,
+  public AbstractSubstitutionModel
+{
+private:
+  double alpha_, beta_, gamma_, kappa_, theta_;
+  
+public:
+  L95(
+      const NucleicAlphabet* alphabet,
+      double alpha = 0.5,
+      double beta = 0.5,
+      double gamma = 0.5,
+      double kappa = 1.,
+      double theta = 0.5);
+  
+  virtual ~L95() {}
+  
+#ifndef NO_VIRTUAL_COV
+  L95*
+#else
+  Clonable*
+#endif
+  clone() const { return new L95(*this); }
+  
+public:
+  std::string getName() const { return "L95"; }
+  
+  void updateMatrices();
+  
+  /**
+   * @brief This method is redefined to actualize the corresponding parameters theta too.
+   */
+  void setFreq(std::map<int, double>&);
+};
+
+} //end of namespace bpp.
+
+#endif	//_L95_H_
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/NucleotideSubstitutionModel.h b/src/Bpp/Phyl/Model/Nucleotide/NucleotideSubstitutionModel.h
new file mode 100755
index 0000000..0862fa8
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/NucleotideSubstitutionModel.h
@@ -0,0 +1,75 @@
+//
+// File: NucleicSubstitutionModel.h
+// Created by: Julien Dutheil
+// Created on: Tue May 27 11:03:53 2003
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _NUCLEICSUBSTITUTIONMODEL_H_
+#define _NUCLEICSUBSTITUTIONMODEL_H_
+
+#include "../SubstitutionModel.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+
+namespace bpp
+{
+
+/**
+ * @brief Specialisation interface for nucleotide substitution model.
+ */
+class NucleotideSubstitutionModel :
+  public virtual SubstitutionModel
+{
+	public:
+		virtual ~NucleotideSubstitutionModel() {}
+
+#ifndef NO_VIRTUAL_COV
+    NucleotideSubstitutionModel*
+#else
+    Clonable*
+#endif
+    clone() const = 0;
+
+  public:
+    virtual size_t getNumberOfStates() const { return 4; }
+
+};
+
+} //end of namespace bpp.
+
+#endif	//_NUCLEICSUBSTITUTIONMODEL_H_
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/RN95.cpp b/src/Bpp/Phyl/Model/Nucleotide/RN95.cpp
new file mode 100644
index 0000000..a9cf5d6
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/RN95.cpp
@@ -0,0 +1,529 @@
+//
+// File: RN95.cpp
+// Created by: Laurent Guéguen
+// Created on: jeudi 24 février 2011, à 20h 42
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "RN95.h"
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+// From the STL:
+#include <cmath>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+RN95::RN95(
+  const NucleicAlphabet* alphabet,
+  double alpha,
+  double beta,
+  double gamma,
+  double delta,
+  double epsilon,
+  double kappa,
+  double lambda,
+  double sigma) :
+  AbstractParameterAliasable("RN95."),
+  AbstractSubstitutionModel(alphabet, "RN95."),
+  alpha_(),
+  beta_(),
+  gamma_(),
+  delta_(),
+  epsilon_(),
+  kappa_(),
+  lambda_(),
+  sigma_(),
+  r_(),
+  c1_(),
+  c2_(),
+  c3_(),
+  c4_(),
+  c5_(),
+  c6_(),
+  c7_(),
+  c8_(),
+  c9_(),
+  p_(size_, size_),
+  exp1_(),
+  exp3_(),
+  exp6_(),
+  l_()
+{
+  double f = gamma + lambda + delta + kappa;
+
+  alpha_  = alpha / f;
+  beta_   = beta / f;
+  gamma_  = gamma / f;
+  delta_  = delta / f;
+  epsilon_ = epsilon / f;
+  kappa_  = kappa / f;
+  lambda_ = lambda / f;
+  sigma_  = sigma / f;
+
+  double thetaR = delta_ + kappa_;
+  double thetaC = (gamma_ * thetaR + sigma_ * (1 - thetaR)) / (beta_ + sigma_ + thetaR) / (1 - thetaR);
+  double thetaG = (alpha_ * thetaR + kappa_ * (1 - thetaR)) / (alpha_ + epsilon_ + 1 - thetaR) / thetaR;
+  double kappaP = kappa_ / thetaR;
+  double gammaP = gamma_ / (1 - thetaR);
+  double alphaP = (alpha_ * (1 - thetaG) + (thetaG < kappaP ? thetaG : kappaP) * (1 - thetaR)) / (thetaG * (1 - thetaR));
+  double sigmaP = (sigma_ * (1 - thetaC) + (thetaC < gammaP ? thetaC : gammaP) * thetaR) / (thetaC * thetaR);
+  addParameter_(new Parameter("RN95.thetaR", thetaR, &Parameter::PROP_CONSTRAINT_EX));
+  addParameter_(new Parameter("RN95.thetaC", thetaC, &Parameter::PROP_CONSTRAINT_EX));
+  addParameter_(new Parameter("RN95.thetaG", thetaG, &Parameter::PROP_CONSTRAINT_EX));
+  addParameter_(new Parameter("RN95.gammaP", gammaP, &Parameter::PROP_CONSTRAINT_EX));
+  addParameter_(new Parameter("RN95.kappaP", kappaP, &Parameter::PROP_CONSTRAINT_EX));
+  addParameter_(new Parameter("RN95.alphaP", alphaP, new IntervalConstraint(1, 1, false), true));
+  addParameter_(new Parameter("RN95.sigmaP", sigmaP, new IntervalConstraint(1, 1, false), true));
+
+  updateMatrices();
+}
+
+/******************************************************************************/
+void RN95::updateMatrices()
+{
+  double alphaP  = getParameterValue("alphaP");
+  double sigmaP  = getParameterValue("sigmaP");
+  double thetaR  = getParameterValue("thetaR");
+  double thetaC  = getParameterValue("thetaC");
+  double thetaG  = getParameterValue("thetaG");
+  double gammaP  = getParameterValue("gammaP");
+  double kappaP  = getParameterValue("kappaP");
+
+  kappa_ = kappaP * thetaR;
+  gamma_ = gammaP * (1 - thetaR);
+  delta_ = thetaR - kappa_;
+  lambda_ = 1 - thetaR - gamma_;
+  alpha_ = (alphaP * (1 - thetaR) * thetaG - (thetaG < kappaP ? thetaG : kappaP) * (1 - thetaR)) / (1 - thetaG);
+  sigma_ = (sigmaP * thetaR * thetaC - (thetaC < gammaP ? thetaC : gammaP) * thetaR) / (1 - thetaC);
+  epsilon_ = (alpha_ * thetaR + kappa_ * (1 - thetaR)) / (thetaG * thetaR) - alpha_ - (1 - thetaR);
+  beta_ = (gamma_ * thetaR + sigma_ * (1 - thetaR)) / (thetaC * (1 - thetaR)) - sigma_ - thetaR;
+
+  // stationnary frequencies
+
+  freq_[0] = (1 - thetaG) * thetaR;
+  freq_[1] = thetaC * (1 - thetaR);
+  freq_[2] = thetaG * thetaR;
+  freq_[3] = (1 - thetaC) * (1 - thetaR);
+
+  // Generator matrix:
+
+  generator_(0, 1) = gamma_;
+  generator_(0, 2) = alpha_;
+  generator_(0, 3) = lambda_;
+
+  generator_(0, 0) = -(gamma_ + alpha_ + lambda_);
+
+  generator_(1, 0) = delta_;
+  generator_(1, 2) = kappa_;
+  generator_(1, 3) = beta_;
+
+  generator_(1, 1) = -(delta_ + beta_ + kappa_);
+
+  generator_(2, 0) = epsilon_;
+  generator_(2, 1) = gamma_;
+  generator_(2, 3) = lambda_;
+
+  generator_(2, 2) = -(gamma_ + epsilon_ + lambda_);
+
+  generator_(3, 0) = delta_;
+  generator_(3, 1) = sigma_;
+  generator_(3, 2) = kappa_;
+
+  generator_(3, 3) = -(delta_ + sigma_ + kappa_);
+
+  // Normalization
+
+  double x = 0;
+  for (size_t i = 0; i < 4; i++)
+  {
+    x += generator_(i, i) * freq_[i];
+  }
+
+  r_ = -1 / x;
+
+  MatrixTools::scale(generator_, r_);
+  // variables for calculation purposes
+
+  c1_ = 1;
+  c2_ = gamma_ + lambda_;
+  c3_ = alpha_ + gamma_ + epsilon_ + lambda_;
+  c4_ = kappa_ - alpha_;
+  c5_ = delta_ + kappa_;
+  c6_ = delta_ + kappa_ + sigma_ + beta_;
+  c7_ = gamma_ - sigma_;
+  c8_ = delta_ - epsilon_;
+  c9_ = lambda_ - beta_;
+
+  // eigen vectors and values
+
+  eigenValues_[0] = 0;
+  eigenValues_[1] = -c1_ * r_;
+  eigenValues_[2] = -c3_ * r_;
+  eigenValues_[3] = -c6_ * r_;
+
+  rightEigenVectors_(0, 0) = 1.;
+  rightEigenVectors_(1, 0) = 1.;
+  rightEigenVectors_(2, 0) = 1.;
+  rightEigenVectors_(3, 0) = 1.;
+
+  rightEigenVectors_(0, 1) = 1.;
+  rightEigenVectors_(1, 1) = -c5_ / c2_;
+  rightEigenVectors_(2, 1) = 1.;
+  rightEigenVectors_(3, 1) = -c5_ / c2_;
+
+  rightEigenVectors_(0, 2) = (alpha_ * (c5_ - c3_) + kappa_ * c2_) / (delta_ * (c3_ - c2_) - epsilon_ * c5_);
+  rightEigenVectors_(1, 2) = 1.;
+  rightEigenVectors_(2, 2) = (-epsilon_ * (c5_ - c3_) - delta_ * c2_) / (delta_ * (c3_ - c2_) - epsilon_ * c5_);
+  rightEigenVectors_(3, 2) = 1.;
+
+  rightEigenVectors_(0, 3) = 1.;
+  rightEigenVectors_(1, 3) = (beta_ * (c2_ - c6_) + lambda_ * c5_) / (gamma_ * (c6_ - c5_) - sigma_ * c2_);
+  rightEigenVectors_(2, 3) = 1;
+  rightEigenVectors_(3, 3) = (-sigma_ * (c2_ - c6_) - gamma_ * c5_) / (gamma_ * (c6_ - c5_) - sigma_ * c2_);
+
+  // Need formula
+
+  try
+  {
+    MatrixTools::inv(rightEigenVectors_, leftEigenVectors_);
+    isNonSingular_ = true;
+    isDiagonalizable_ = true;
+    for (size_t i = 0; i < size_ && isDiagonalizable_; i++)
+    {
+      if (abs(iEigenValues_[i]) > NumConstants::TINY())
+        isDiagonalizable_ = false;
+    }
+  }
+  catch (ZeroDivisionException& e)
+  {
+    ApplicationTools::displayMessage("Singularity during  diagonalization. Taylor series used instead.");
+
+    isNonSingular_ = false;
+    isDiagonalizable_ = false;
+    MatrixTools::Taylor(generator_, 30, vPowGen_);
+  }
+
+  // and the exchangeability_
+  for (unsigned int i = 0; i < size_; i++)
+    for (unsigned int j = 0; j < size_; j++)
+      exchangeability_(i,j) = generator_(i,j) / freq_[j];
+
+}
+
+/******************************************************************************/
+double RN95::Pij_t(int i, int j, double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = exp(-c1_ * l_);
+  exp3_ = exp(-c3_ * l_);
+  exp6_ = exp(-c6_ * l_);
+
+  switch (i)
+  {
+    {
+    // A
+    case 0: {
+      switch (j)
+      {
+      case 0: return freq_[0] - c2_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (alpha_ * (c3_ - c1_) - c2_ * c4_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+      case 1: return freq_[1] + c2_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+      case 2: return freq_[2] - c2_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (alpha_ * (c3_ - c1_) - c2_ * c4_) / (c3_ * (c3_ - c1_)) * exp3_;  // G
+      case 3: return freq_[3] + c2_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;           // T, U
+      }
+    }
+    // C
+    case 1: {
+      switch (j)
+      {
+      case 0: return freq_[0] + c5_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+      case 1: return freq_[1] - c5_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (beta_ * (c6_ - c1_) - c5_ * c9_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+      case 2: return freq_[2] + c5_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // G
+      case 3: return freq_[3] - c5_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (beta_ * (c6_ - c1_) - c5_ * c9_) / (c6_ * (c6_ - c1_)) * exp6_;                  // T
+      }
+    }
+    // G
+    case 2: {
+      switch (j)
+      {
+      case 0: return freq_[0] - c2_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (c2_ * c8_ - epsilon_ * (c3_ - c1_)) / (c3_ * (c3_ - c1_)) * exp3_; // A
+      case 1: return freq_[1] + c2_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+      case 2: return freq_[2] - c2_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (c2_ * c8_ - epsilon_ * (c3_ - c1_)) / (c3_ * (c3_ - c1_)) * exp3_;   // G
+      case 3: return freq_[3] + c2_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;           // T, U
+      }
+    }
+    }
+  // T, U
+  case 3: {
+    switch (j)
+    {
+    case 0: return freq_[0] + c5_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+    case 1: return freq_[1] - c5_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (c5_ * c7_ - sigma_ * (c6_ - c1_)) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+    case 2: return freq_[2] + c5_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // G
+    case 3: return freq_[3] - c5_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (c5_ * c7_ - sigma_ * (c6_ - c1_)) / (c6_ * (c6_ - c1_)) * exp6_;                  // T
+    }
+  }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+double RN95::dPij_dt(int i, int j, double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = -c1_* rate_* r_* exp(-c1_ * l_);
+  exp3_ = -c3_* rate_* r_* exp(-c3_ * l_);
+  exp6_ = -c6_* rate_* r_* exp(-c6_ * l_);
+
+  switch (i)
+  {
+    {
+    // A
+    case 0: {
+      switch (j)
+      {
+      case 0: return -c2_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (alpha_ * (c3_ - c1_) - c2_ * c4_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+      case 1: return c2_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+      case 2: return -c2_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (alpha_ * (c3_ - c1_) - c2_ * c4_) / (c3_ * (c3_ - c1_)) * exp3_;  // G
+      case 3: return c2_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;           // T, U
+      }
+    }
+    // C
+    case 1: {
+      switch (j)
+      {
+      case 0: return c5_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+      case 1: return -c5_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (beta_ * (c6_ - c1_) - c5_ * c9_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+      case 2: return c5_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // G
+      case 3: return -c5_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (beta_ * (c6_ - c1_) - c5_ * c9_) / (c6_ * (c6_ - c1_)) * exp6_;                  // T
+      }
+    }
+    // G
+    case 2: {
+      switch (j)
+      {
+      case 0: return -c2_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (c2_ * c8_ - epsilon_ * (c3_ - c1_)) / (c3_ * (c3_ - c1_)) * exp3_; // A
+      case 1: return c2_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+      case 2: return -c2_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (c2_ * c8_ - epsilon_ * (c3_ - c1_)) / (c3_ * (c3_ - c1_)) * exp3_;   // G
+      case 3: return c2_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;           // T, U
+      }
+    }
+    }
+  // T, U
+  case 3: {
+    switch (j)
+    {
+    case 0: return c5_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+    case 1: return -c5_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (c5_ * c7_ - sigma_ * (c6_ - c1_)) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+    case 2: return c5_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // G
+    case 3: return -c5_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (c5_ * c7_ - sigma_ * (c6_ - c1_)) / (c6_ * (c6_ - c1_)) * exp6_;                  // T
+    }
+  }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+double RN95::d2Pij_dt2(int i, int j, double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = c1_ * rate_ * r_ * c1_ * rate_ * r_ * exp(-c1_ * l_);
+  exp3_ = c3_ * rate_ * r_ * c3_ * rate_ * r_ * exp(-c3_ * l_);
+  exp6_ = c6_ * rate_ * r_ * c6_ * rate_ * r_ * exp(-c6_ * l_);
+
+  switch (i)
+  {
+    {
+    // A
+    case 0: {
+      switch (j)
+      {
+      case 0: return -c2_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (alpha_ * (c3_ - c1_) - c2_ * c4_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+      case 1: return c2_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+      case 2: return -c2_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (alpha_ * (c3_ - c1_) - c2_ * c4_) / (c3_ * (c3_ - c1_)) * exp3_;  // G
+      case 3: return c2_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;           // T, U
+      }
+    }
+    // C
+    case 1: {
+      switch (j)
+      {
+      case 0: return c5_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+      case 1: return -c5_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (beta_ * (c6_ - c1_) - c5_ * c9_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+      case 2: return c5_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // G
+      case 3: return -c5_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (beta_ * (c6_ - c1_) - c5_ * c9_) / (c6_ * (c6_ - c1_)) * exp6_;                  // T
+      }
+    }
+    // G
+    case 2: {
+      switch (j)
+      {
+      case 0: return -c2_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (c2_ * c8_ - epsilon_ * (c3_ - c1_)) / (c3_ * (c3_ - c1_)) * exp3_; // A
+      case 1: return c2_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+      case 2: return -c2_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (c2_ * c8_ - epsilon_ * (c3_ - c1_)) / (c3_ * (c3_ - c1_)) * exp3_;   // G
+      case 3: return c2_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;           // T, U
+      }
+    }
+    }
+  // T, U
+  case 3: {
+    switch (j)
+    {
+    case 0: return c5_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+    case 1: return -c5_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (c5_ * c7_ - sigma_ * (c6_ - c1_)) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+    case 2: return c5_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // G
+    case 3: return -c5_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (c5_ * c7_ - sigma_ * (c6_ - c1_)) / (c6_ * (c6_ - c1_)) * exp6_;                  // T
+    }
+  }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+
+const Matrix<double>& RN95::getPij_t(double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = exp(-c1_ * l_);
+  exp3_ = exp(-c3_ * l_);
+  exp6_ = exp(-c6_ * l_);
+
+  // A
+  p_(0, 0) = freq_[0] - c2_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (alpha_ * (c3_ - c1_) - c2_ * c4_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+  p_(0, 1) = freq_[1] + c2_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+  p_(0, 2) = freq_[2] - c2_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (alpha_ * (c3_ - c1_) - c2_ * c4_) / (c3_ * (c3_ - c1_)) * exp3_;  // G
+  p_(0, 3) = freq_[3] + c2_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;           // T, U
+  // C
+  p_(1, 0) = freq_[0] + c5_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+  p_(1, 1) = freq_[1] - c5_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (beta_ * (c6_ - c1_) - c5_ * c9_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+  p_(1, 2) = freq_[2] + c5_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // G
+  p_(1, 3) = freq_[3] - c5_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (beta_ * (c6_ - c1_) - c5_ * c9_) / (c6_ * (c6_ - c1_)) * exp6_;                  // T
+  // G
+  p_(2, 0) = freq_[0] - c2_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (c2_ * c8_ - epsilon_ * (c3_ - c1_)) / (c3_ * (c3_ - c1_)) * exp3_; // A
+  p_(2, 1) = freq_[1] + c2_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+  p_(2, 2) = freq_[2] - c2_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (c2_ * c8_ - epsilon_ * (c3_ - c1_)) / (c3_ * (c3_ - c1_)) * exp3_;   // G
+  p_(2, 3) = freq_[3] + c2_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;           // T, U
+  // T, U
+  p_(3, 0) = freq_[0] + c5_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+  p_(3, 1) = freq_[1] - c5_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (c5_ * c7_ - sigma_ * (c6_ - c1_)) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+  p_(3, 2) = freq_[2] + c5_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // G
+  p_(3, 3) = freq_[3] - c5_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (c5_ * c7_ - sigma_ * (c6_ - c1_)) / (c6_ * (c6_ - c1_)) * exp6_;                  // T
+
+  return p_;
+}
+
+/******************************************************************************/
+
+const Matrix<double>&  RN95::getdPij_dt(double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = -c1_* rate_* r_* exp(-c1_ * l_);
+  exp3_ = -c3_* rate_* r_* exp(-c3_ * l_);
+  exp6_ = -c6_* rate_* r_* exp(-c6_ * l_);
+
+  // A
+  p_(0, 0) = -c2_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (alpha_ * (c3_ - c1_) - c2_ * c4_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+  p_(0, 1) =  c2_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+  p_(0, 2) =  -c2_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (alpha_ * (c3_ - c1_) - c2_ * c4_) / (c3_ * (c3_ - c1_)) * exp3_;  // G
+  p_(0, 3) = c2_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;           // T, U
+  // C
+  p_(1, 0) = c5_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+  p_(1, 1) = -c5_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (beta_ * (c6_ - c1_) - c5_ * c9_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+  p_(1, 2) = c5_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // G
+  p_(1, 3) = -c5_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (beta_ * (c6_ - c1_) - c5_ * c9_) / (c6_ * (c6_ - c1_)) * exp6_;                  // T
+  // G
+  p_(2, 0) = -c2_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (c2_ * c8_ - epsilon_ * (c3_ - c1_)) / (c3_ * (c3_ - c1_)) * exp3_; // A
+  p_(2, 1) = c2_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+  p_(2, 2) = -c2_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (c2_ * c8_ - epsilon_ * (c3_ - c1_)) / (c3_ * (c3_ - c1_)) * exp3_;   // G
+  p_(2, 3) = c2_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;           // T, U
+  // T, U
+  p_(3, 0) = c5_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+  p_(3, 1) = -c5_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (c5_ * c7_ - sigma_ * (c6_ - c1_)) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+  p_(3, 2) = c5_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // G
+  p_(3, 3) = -c5_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (c5_ * c7_ - sigma_ * (c6_ - c1_)) / (c6_ * (c6_ - c1_)) * exp6_;                  // T
+  return p_;
+}
+
+/******************************************************************************/
+
+const Matrix<double>&  RN95::getd2Pij_dt2(double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = c1_ * rate_ * r_ * c1_ * rate_ * r_ * exp(-c1_ * l_);
+  exp3_ = c3_ * rate_ * r_ * c3_ * rate_ * r_ * exp(-c3_ * l_);
+  exp6_ = c6_ * rate_ * r_ * c6_ * rate_ * r_ * exp(-c6_ * l_);
+
+  // A
+  p_(0, 0) = -c2_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (alpha_ * (c3_ - c1_) - c2_ * c4_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+  p_(0, 1) =  c2_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+  p_(0, 2) =  -c2_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (alpha_ * (c3_ - c1_) - c2_ * c4_) / (c3_ * (c3_ - c1_)) * exp3_;  // G
+  p_(0, 3) = c2_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;           // T, U
+  // C
+  p_(1, 0) = c5_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+  p_(1, 1) = -c5_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (beta_ * (c6_ - c1_) - c5_ * c9_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+  p_(1, 2) = c5_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // G
+  p_(1, 3) = -c5_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (beta_ * (c6_ - c1_) - c5_ * c9_) / (c6_ * (c6_ - c1_)) * exp6_;                  // T
+  // G
+  p_(2, 0) = -c2_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (c2_ * c8_ - epsilon_ * (c3_ - c1_)) / (c3_ * (c3_ - c1_)) * exp3_; // A
+  p_(2, 1) = c2_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+  p_(2, 2) = -c2_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (c2_ * c8_ - epsilon_ * (c3_ - c1_)) / (c3_ * (c3_ - c1_)) * exp3_;   // G
+  p_(2, 3) = c2_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (lambda_ * sigma_ - gamma_ * beta_) / (c6_ * (c6_ - c1_)) * exp6_;           // T, U
+  // T, U
+  p_(3, 0) = c5_ * c8_ / (c1_ * (c3_ - c1_)) * exp1_ + (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // A
+  p_(3, 1) = -c5_ * c7_ / (c1_ * (c6_ - c1_)) * exp1_ + (c5_ * c7_ - sigma_ * (c6_ - c1_)) / (c6_ * (c6_ - c1_)) * exp6_;                  // C
+  p_(3, 2) = c5_ * c4_ / (c1_ * (c3_ - c1_)) * exp1_ - (epsilon_ * kappa_ - delta_ * alpha_) / (c3_ * (c3_ - c1_)) * exp3_; // G
+  p_(3, 3) = -c5_ * c9_ / (c1_ * (c6_ - c1_)) * exp1_ - (c5_ * c7_ - sigma_ * (c6_ - c1_)) / (c6_ * (c6_ - c1_)) * exp6_;
+
+  return p_;
+}
+
+/******************************************************************************/
+void RN95::setFreq(map<int, double>& freqs)
+{
+  setParameterValue("thetaR", (freqs[0] + freqs[2]) / (freqs[0] + freqs[1] + freqs[2] + freqs[3]));
+  setParameterValue("thetaC", freqs[1] / (freqs[1] + freqs[3]));
+  setParameterValue("thetaG", freqs[2] / (freqs[0] + freqs[2]));
+
+  updateMatrices();
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/RN95.h b/src/Bpp/Phyl/Model/Nucleotide/RN95.h
new file mode 100644
index 0000000..62c95fc
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/RN95.h
@@ -0,0 +1,181 @@
+//
+// File: RN95.h
+// Created by: Laurent Guéguen
+// Created on: jeudi 24 février 2011, à 20h 43
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _RN95_H_
+#define _RN95_H_
+
+#include "NucleotideSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+
+#include <Bpp/Numeric/Constraints.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+
+namespace bpp
+{
+/**
+ * @brief The model described by Rhetsky \& Nei, where the only
+ * hypothesis is that the transversion rates are only dependent of
+ * the target nucleotide. This model is not reversible.
+ *
+ * This model has been thoroughly studied by Schadt & al, and we
+ * follow their notations and formula. The parameters are defined to
+ * allow allow the direct definition of the stationnary frequencies.
+ *
+ * After normalization this model has 7 parameters:
+ * \f[
+ * Q= \frac 1P
+ * \begin{pmatrix}
+ * . & \gamma & \alpha & \lambda \\
+ * \delta & . &  \kappa & \beta \\
+ * \epsilon & \gamma & . & \lambda \\
+ * \delta & \sigma & \kappa & .\\
+ * \end{pmatrix}\f]
+ *
+ * so in the parametrization process we set: \f[\gamma+\lambda+\delta+\kappa=1\f]
+ *
+ * The stationnary distribution
+ * \f[
+ * \pi = \left(\pi_A, \pi_C, \pi_G, \pi_T\right)
+ * \f]
+ * can be computed analytically, so we define parameters for it (values between 0 and 1):
+ *\f[
+ * \begin{cases}
+ * \theta_R = \pi_A + \pi_G\\
+ * \theta_C = \frac{\pi_C}{1 - \theta_R} = \frac{\pi_C}{\pi_C + \pi_G}\\
+ * \theta_G = \frac{\pi_G}{\theta_R} = \frac{\pi_G}{\pi_A + \pi_G}\\
+ * \end{cases}
+ * \f]
+ *
+ * with parameters with values in [0;1[:
+ *
+ *\f[
+ * \begin{cases}
+ * \kappa'=\frac{\kappa}{\theta_R}\\
+ * \gamma'=\frac{\gamma}{1-\theta_R}\\
+ * \end{cases}
+ * \f]
+ *
+ * and parameters with values > 1:
+ *
+ *\f[
+ * \begin{cases}
+ * \alpha'=\frac{\alpha(1-\theta_G)+min(\theta_G,\kappa')(1-\theta_R)}{\theta_G(1-\theta_R)}\\
+ * \sigma'=\frac{\sigma(1-\theta_C)+min(\theta_C,\gamma')\theta_R}{\theta_C\theta_R}\\
+ * \end{cases}
+ * \f]
+ *
+ * The generator is then computed as:
+ *
+ *\f[
+ * \begin{cases}
+ * \kappa=\kappa' \theta_R\\
+ * \gamma=\gamma' (1-\theta_R)\\
+ * \delta=\theta_R - \kappa\\
+ * \lambda=1-\theta_R-\gamma\\
+ * \alpha=\frac{\alpha'(1-\theta_R)\theta_G-min(\theta_G,\kappa')(1-\theta_R)}{1-\theta_G}\\
+ * \sigma=\frac{\sigma'\theta_R\theta_C-min(\theta_C,\gamma')\theta_R}{1-\theta_C}\\
+ * \beta=\frac{\gamma'*\theta_R+\sigma}{\theta_C}-\sigma-\theta_R\\
+ * \epsilon=\frac{\kappa'*(1-\theta_R)+\alpha}{\theta_G}-\alpha-(1-\theta_R)\\
+ * \end{cases}
+ * \f]
+ *
+ * and \f[P\f] is set for normalization.
+ *
+ * The parameters are named \c "thetaR", \c "thetaC", \c "thetaG",
+ * \c "kappaP", \c "gammaP", \c "sigmaP", \c "alphaP".
+ *
+ * References:
+ * - Rhetsky A. \& Nei M. (1995) MBE 12(1) 131-151.
+ * - Schadt, Sinsheimer \& Lange (1998) Genome Research 8 222-233.
+ */
+
+class RN95 :
+  public virtual NucleotideSubstitutionModel,
+  public AbstractSubstitutionModel
+{
+private:
+  double alpha_, beta_, gamma_, delta_, epsilon_, kappa_, lambda_, sigma_;
+  double r_;
+  /**
+   * For calculation purposes as in Schadt & al. (with c1_=1)
+   */
+  double c1_, c2_, c3_, c4_, c5_, c6_, c7_, c8_, c9_;
+  mutable RowMatrix<double> p_;
+  mutable double exp1_, exp3_, exp6_, l_;
+
+public:
+  RN95(
+    const NucleicAlphabet* alphabet,
+    double alpha = 1,
+    double beta = 1,
+    double gamma = 1,
+    double delta = 1,
+    double epsilon = 1,
+    double kappa = 1,
+    double lambda = 1,
+    double sigma = 1);
+
+  virtual ~RN95() {}
+
+#ifndef NO_VIRTUAL_COV
+  RN95*
+#else
+  Clonable*
+#endif
+  clone() const { return new RN95(*this); }
+
+public:
+  double Pij_t    (int i, int j, double d) const;
+  double dPij_dt  (int i, int j, double d) const;
+  double d2Pij_dt2(int i, int j, double d) const;
+  const Matrix<double>& getPij_t    (double d) const;
+  const Matrix<double>& getdPij_dt  (double d) const;
+  const Matrix<double>& getd2Pij_dt2(double d) const;
+  std::string getName() const { return "RN95"; }
+
+  void updateMatrices();
+
+  void setFreq(std::map<int, double>&);
+};
+} // end of namespace bpp.
+
+#endif  // _RN95_H_
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/RN95s.cpp b/src/Bpp/Phyl/Model/Nucleotide/RN95s.cpp
new file mode 100644
index 0000000..16a2298
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/RN95s.cpp
@@ -0,0 +1,477 @@
+//
+// File: RN95s.cpp
+// Created by: Laurent Guéguen
+// Created on: jeudi 24 février 2011, à 20h 42
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "RN95s.h"
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+// From the STL:
+#include <cmath>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+RN95s::RN95s(const NucleicAlphabet* alphabet,
+             double alpha,
+             double beta,
+             double gamma,
+             double delta) :
+  AbstractParameterAliasable("RN95s."),
+  AbstractSubstitutionModel(alphabet, "RN95s."),
+  alpha_(),
+  beta_(),
+  gamma_(),
+  delta_(),
+  r_(),
+  c3_(),
+  c4_(),
+  c8_(),
+  p_(size_, size_),
+  exp1_(),
+  exp3_(),
+  l_()
+{
+  double f = 2 * (gamma + delta);
+
+  alpha_ = alpha / f;
+  beta_ = beta / f;
+  gamma_ = gamma / f;
+  delta_ = delta / f;
+
+  double piA = 0.5 * (beta_ + delta_) / (alpha_ + beta_ + 0.5);
+  double alphaP = (2 * alpha_ * piA + ((0.5 - piA < gamma_) ? 0.5 - piA : gamma_)) / (0.5 - piA);
+  addParameter_(new Parameter("RN95s.thetaA", piA, new IntervalConstraint(0, 0.5, false, false), true));
+  addParameter_(new Parameter("RN95s.gamma", gamma_, new IntervalConstraint(0, 0.5, false, false), true));
+  addParameter_(new Parameter("RN95s.alphaP", alphaP, new IntervalConstraint(1, 1, false), true));
+
+  updateMatrices();
+}
+
+/******************************************************************************/
+void RN95s::updateMatrices()
+{
+  freq_[0]  = getParameterValue("thetaA");
+  double alphaP  = getParameterValue("alphaP");
+  gamma_  = getParameterValue("gamma");
+  alpha_  = (alphaP * (0.5 - freq_[0]) - ((0.5 - freq_[0] < gamma_) ? 0.5 - freq_[0] : gamma_)) / (2 * freq_[0]);
+  delta_  = 0.5 - gamma_;
+  beta_   = (2 * freq_[0] * (alpha_ + 0.5) - delta_) / (1 - 2 * freq_[0]);
+
+  // stationnary frequencies
+
+  freq_[1] = 0.5 - freq_[0];
+  freq_[2] = freq_[1];
+  freq_[3] = freq_[0];
+
+  // Generator matrix:
+
+  generator_(0, 1) = gamma_;
+  generator_(0, 2) = alpha_;
+  generator_(0, 3) = delta_;
+
+  generator_(0, 0) = -(gamma_ + alpha_ + delta_);
+
+  generator_(1, 0) = delta_;
+  generator_(1, 2) = gamma_;
+  generator_(1, 3) = beta_;
+
+  generator_(1, 1) = -(delta_ + beta_ + gamma_);
+
+  generator_(2, 0) = beta_;
+  generator_(2, 1) = gamma_;
+  generator_(2, 3) = delta_;
+
+  generator_(2, 2) = -(gamma_ + beta_ + delta_);
+
+  generator_(3, 0) = delta_;
+  generator_(3, 1) = alpha_;
+  generator_(3, 2) = gamma_;
+
+  generator_(3, 3) = -(delta_ + alpha_ + gamma_);
+
+  // Normalization
+
+  double x = 0;
+  for (unsigned int i = 0; i < 4; i++)
+  {
+    x += generator_(i, i) * freq_[i];
+  }
+
+  r_ = -1 / x;
+
+  MatrixTools::scale(generator_, r_);
+
+  // variables for calculation purposes
+
+  c3_ = alpha_ + gamma_ + beta_ + delta_;
+  c4_ = gamma_ - alpha_;
+  c8_ = delta_ - beta_;
+
+
+  // eigen vectors and values
+
+  eigenValues_[0] = 0;
+  eigenValues_[1] = -r_;
+  eigenValues_[2] = -c3_ * r_;
+  eigenValues_[3] = -c3_ * r_;
+
+  rightEigenVectors_(0, 0) = 1.;
+  rightEigenVectors_(1, 0) = 1.;
+  rightEigenVectors_(2, 0) = 1.;
+  rightEigenVectors_(3, 0) = 1.;
+
+  rightEigenVectors_(0, 1) = 1.;
+  rightEigenVectors_(1, 1) = -1;
+  rightEigenVectors_(2, 1) = 1.;
+  rightEigenVectors_(3, 1) = -1;
+
+  rightEigenVectors_(0, 2) = (alpha_ * (0.5 - c3_) + gamma_ * 0.5) / (delta_ * (c3_ - 0.5) - beta_ * 0.5);
+  rightEigenVectors_(1, 2) = 1.;
+  rightEigenVectors_(2, 2) = (-beta_ * (0.5 - c3_) - delta_ * 0.5) / (delta_ * (c3_ - 0.5) - beta_ * 0.5);
+  rightEigenVectors_(3, 2) = 1.;
+
+  rightEigenVectors_(0, 3) = 1.;
+  rightEigenVectors_(1, 3) = (beta_ * (0.5 - c3_) + delta_ * 0.5) / (gamma_ * (c3_ - 0.5) - alpha_ * 0.5);
+  rightEigenVectors_(2, 3) = 1;
+  rightEigenVectors_(3, 3) = (-alpha_ * (0.5 - c3_) - gamma_ * 0.5) / (gamma_ * (c3_ - 0.5) - alpha_ * 0.5);
+
+// Need formula
+
+  try
+  {
+    MatrixTools::inv(rightEigenVectors_, leftEigenVectors_);
+    isNonSingular_ = true;
+    isDiagonalizable_ = true;
+    for (unsigned int i = 0; i < size_ && isDiagonalizable_; i++)
+    {
+      if (abs(iEigenValues_[i]) > NumConstants::TINY())
+        isDiagonalizable_ = false;
+    }
+  }
+  catch (ZeroDivisionException& e)
+  {
+    ApplicationTools::displayMessage("Singularity during  diagonalization. Taylor series used instead.");
+
+    isNonSingular_ = false;
+    isDiagonalizable_ = false;
+    MatrixTools::Taylor(generator_, 30, vPowGen_);
+  }
+
+  // and the exchangeability_
+  for (size_t i = 0; i < size_; i++)
+    for (size_t j = 0; j < size_; j++)
+      exchangeability_(i,j) = generator_(i,j) / freq_[j];
+
+}
+
+/******************************************************************************/
+double RN95s::Pij_t(int i, int j, double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = exp(-l_);
+  exp3_ = exp(-c3_ * l_);
+
+  switch (i)
+  {
+    {
+    // A
+    case 0: {
+      switch (j)
+      {
+      case 0: return freq_[0] - 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (alpha_ * (c3_ - 1.) - 0.5 * c4_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+      case 1: return freq_[1] + 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+      case 2: return freq_[2] - 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (alpha_ * (c3_ - 1.) - 0.5 * c4_) / (c3_ * (c3_ - 1.)) * exp3_;  // G
+      case 3: return freq_[3] + 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;           // T, U
+      }
+    }
+    // C
+    case 1: {
+      switch (j)
+      {
+      case 0: return freq_[0] + 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+      case 1: return freq_[1] - 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * (c3_ - 1.) - 0.5 * c8_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+      case 2: return freq_[2] + 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // G
+      case 3: return freq_[3] - 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * (c3_ - 1.) - 0.5 * c8_) / (c3_ * (c3_ - 1.)) * exp3_;                  // T
+      }
+    }
+    // G
+    case 2: {
+      switch (j)
+      {
+      case 0: return freq_[0] - 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (0.5 * c8_ - beta_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_; // A
+      case 1: return freq_[1] + 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+      case 2: return freq_[2] - 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (0.5 * c8_ - beta_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;   // G
+      case 3: return freq_[3] + 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;           // T, U
+      }
+    }
+    }
+  // T, U
+  case 3: {
+    switch (j)
+    {
+    case 0: return freq_[0] + 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+    case 1: return freq_[1] - 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (0.5 * c4_ - alpha_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+    case 2: return freq_[2] + 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // G
+    case 3: return freq_[3] - 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (0.5 * c4_ - alpha_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;                  // T
+    }
+  }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+double RN95s::dPij_dt(int i, int j, double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = -1.* rate_* r_* exp(-1. * l_);
+  exp3_ = -c3_* rate_* r_* exp(-c3_ * l_);
+
+  switch (i)
+  {
+    {
+    // A
+    case 0: {
+      switch (j)
+      {
+      case 0: return -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (alpha_ * (c3_ - 1.) - 0.5 * c4_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+      case 1: return 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+      case 2: return -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (alpha_ * (c3_ - 1.) - 0.5 * c4_) / (c3_ * (c3_ - 1.)) * exp3_;  // G
+      case 3: return 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;           // T, U
+      }
+    }
+    // C
+    case 1: {
+      switch (j)
+      {
+      case 0: return 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+      case 1: return -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * (c3_ - 1.) - 0.5 * c8_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+      case 2: return 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // G
+      case 3: return -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * (c3_ - 1.) - 0.5 * c8_) / (c3_ * (c3_ - 1.)) * exp3_;                  // T
+      }
+    }
+    // G
+    case 2: {
+      switch (j)
+      {
+      case 0: return -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (0.5 * c8_ - beta_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_; // A
+      case 1: return 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+      case 2: return -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (0.5 * c8_ - beta_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;   // G
+      case 3: return 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;           // T, U
+      }
+    }
+    }
+  // T, U
+  case 3: {
+    switch (j)
+    {
+    case 0: return 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+    case 1: return -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (0.5 * c4_ - alpha_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+    case 2: return 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // G
+    case 3: return -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (0.5 * c4_ - alpha_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;                  // T
+    }
+  }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+double RN95s::d2Pij_dt2(int i, int j, double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = 1. * rate_ * r_ * 1.* rate_* r_* exp(-1. * l_);
+  exp3_ = c3_ * rate_ * r_ * c3_ * rate_ * r_ * exp(-c3_ * l_);
+
+  switch (i)
+  {
+    {
+    // A
+    case 0: {
+      switch (j)
+      {
+      case 0: return -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (alpha_ * (c3_ - 1.) - 0.5 * c4_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+      case 1: return 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+      case 2: return -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (alpha_ * (c3_ - 1.) - 0.5 * c4_) / (c3_ * (c3_ - 1.)) * exp3_;  // G
+      case 3: return 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;           // T, U
+      }
+    }
+    // C
+    case 1: {
+      switch (j)
+      {
+      case 0: return 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+      case 1: return -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * (c3_ - 1.) - 0.5 * c8_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+      case 2: return 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // G
+      case 3: return -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * (c3_ - 1.) - 0.5 * c8_) / (c3_ * (c3_ - 1.)) * exp3_;                  // T
+      }
+    }
+    // G
+    case 2: {
+      switch (j)
+      {
+      case 0: return -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (0.5 * c8_ - beta_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_; // A
+      case 1: return 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+      case 2: return -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (0.5 * c8_ - beta_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;   // G
+      case 3: return 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;           // T, U
+      }
+    }
+    }
+  // T, U
+  case 3: {
+    switch (j)
+    {
+    case 0: return 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+    case 1: return -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (0.5 * c4_ - alpha_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+    case 2: return 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // G
+    case 3: return -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (0.5 * c4_ - alpha_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;                  // T
+    }
+  }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+
+const Matrix<double>& RN95s::getPij_t(double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = exp(-1. * l_);
+  exp3_ = exp(-c3_ * l_);
+
+  // A
+  p_(0, 0) = freq_[0] - 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (alpha_ * (c3_ - 1.) - 0.5 * c4_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+  p_(0, 1) = freq_[1] + 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+  p_(0, 2) = freq_[2] - 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (alpha_ * (c3_ - 1.) - 0.5 * c4_) / (c3_ * (c3_ - 1.)) * exp3_;  // G
+  p_(0, 3) = freq_[3] + 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;           // T, U
+  // C
+  p_(1, 0) = freq_[0] + 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+  p_(1, 1) = freq_[1] - 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * (c3_ - 1.) - 0.5 * c8_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+  p_(1, 2) = freq_[2] + 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // G
+  p_(1, 3) = freq_[3] - 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * (c3_ - 1.) - 0.5 * c8_) / (c3_ * (c3_ - 1.)) * exp3_;                  // T
+  // G
+  p_(2, 0) = freq_[0] - 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (0.5 * c8_ - beta_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_; // A
+  p_(2, 1) = freq_[1] + 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+  p_(2, 2) = freq_[2] - 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (0.5 * c8_ - beta_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;   // G
+  p_(2, 3) = freq_[3] + 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;           // T, U
+  // T, U
+  p_(3, 0) = freq_[0] + 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+  p_(3, 1) = freq_[1] - 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (0.5 * c4_ - alpha_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+  p_(3, 2) = freq_[2] + 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // G
+  p_(3, 3) = freq_[3] - 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (0.5 * c4_ - alpha_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;                  // T
+
+  return p_;
+}
+
+/******************************************************************************/
+
+const Matrix<double>&  RN95s::getdPij_dt(double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = -1.* rate_* r_* exp(-1. * l_);
+  exp3_ = -c3_* rate_* r_* exp(-c3_ * l_);
+
+  // A
+  p_(0, 0) = -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (alpha_ * (c3_ - 1.) - 0.5 * c4_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+  p_(0, 1) =  0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+  p_(0, 2) =  -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (alpha_ * (c3_ - 1.) - 0.5 * c4_) / (c3_ * (c3_ - 1.)) * exp3_;  // G
+  p_(0, 3) = 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;           // T, U
+  // C
+  p_(1, 0) = 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+  p_(1, 1) = -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * (c3_ - 1.) - 0.5 * c8_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+  p_(1, 2) = 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // G
+  p_(1, 3) = -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * (c3_ - 1.) - 0.5 * c8_) / (c3_ * (c3_ - 1.)) * exp3_;                  // T
+  // G
+  p_(2, 0) = -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (0.5 * c8_ - beta_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_; // A
+  p_(2, 1) = 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+  p_(2, 2) = -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (0.5 * c8_ - beta_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;   // G
+  p_(2, 3) = 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;           // T, U
+  // T, U
+  p_(3, 0) = 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+  p_(3, 1) = -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (0.5 * c4_ - alpha_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+  p_(3, 2) = 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // G
+  p_(3, 3) = -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (0.5 * c4_ - alpha_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;                  // T
+  return p_;
+}
+
+/******************************************************************************/
+
+const Matrix<double>&  RN95s::getd2Pij_dt2(double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = 1. * rate_ * r_ * 1.* rate_* r_* exp(-1. * l_);
+  exp3_ = c3_ * rate_ * r_ * c3_ * rate_ * r_ * exp(-c3_ * l_);
+
+  // A
+  p_(0, 0) = -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (alpha_ * (c3_ - 1.) - 0.5 * c4_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+  p_(0, 1) =  0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+  p_(0, 2) =  -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (alpha_ * (c3_ - 1.) - 0.5 * c4_) / (c3_ * (c3_ - 1.)) * exp3_;  // G
+  p_(0, 3) = 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;           // T, U
+  // C
+  p_(1, 0) = 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+  p_(1, 1) = -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * (c3_ - 1.) - 0.5 * c8_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+  p_(1, 2) = 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // G
+  p_(1, 3) = -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * (c3_ - 1.) - 0.5 * c8_) / (c3_ * (c3_ - 1.)) * exp3_;                  // T
+  // G
+  p_(2, 0) = -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (0.5 * c8_ - beta_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_; // A
+  p_(2, 1) = 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+  p_(2, 2) = -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (0.5 * c8_ - beta_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;   // G
+  p_(2, 3) = 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (delta_ * alpha_ - gamma_ * beta_) / (c3_ * (c3_ - 1.)) * exp3_;           // T, U
+  // T, U
+  p_(3, 0) = 0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ + (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // A
+  p_(3, 1) = -0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ + (0.5 * c4_ - alpha_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;                  // C
+  p_(3, 2) = 0.5 * c4_ / (1. * (c3_ - 1.)) * exp1_ - (beta_ * gamma_ - delta_ * alpha_) / (c3_ * (c3_ - 1.)) * exp3_; // G
+  p_(3, 3) = -0.5 * c8_ / (1. * (c3_ - 1.)) * exp1_ - (0.5 * c4_ - alpha_ * (c3_ - 1.)) / (c3_ * (c3_ - 1.)) * exp3_;
+
+  return p_;
+}
+
+/******************************************************************************/
+void RN95s::setFreq(map<int, double>& freqs)
+{
+  setParameterValue("thetaA", (freqs[0] + freqs[3]) / 2);
+
+  updateMatrices();
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/RN95s.h b/src/Bpp/Phyl/Model/Nucleotide/RN95s.h
new file mode 100644
index 0000000..68d44f7
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/RN95s.h
@@ -0,0 +1,161 @@
+//
+// File: RN95s.h
+// Created by: Laurent Guéguen
+// Created on: samedi 12 mars 2011, à 06h 49
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _RN95s_H_
+#define _RN95s_H_
+
+#include "NucleotideSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+
+#include <Bpp/Numeric/Constraints.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+
+namespace bpp
+{
+/**
+ * @brief Intersection of models RN95 and L95.
+ *
+ * The two hypotheses are that the transversion rates are only
+ * dependent of the target nucleotide, and strand symmetry.
+ *
+ * After normalization this model has 3 parameters:
+ * \f[
+ * Q= \frac 1P
+ * \begin{pmatrix}
+ * . & \gamma & \alpha & \delta \\
+ * \delta & . &  \gamma & \beta \\
+ * \beta & \gamma & . & \delta \\
+ * \delta & \alpha & \gamma & .\\
+ * \end{pmatrix}\f]
+ *
+ * so in the parametrization process we set: \f[\gamma+\delta=\frac 12\f]
+ *
+ * The stationnary distribution
+ * \f[
+ * \pi = \left(\pi_A, \pi_C, \pi_G, \pi_T\right)
+ * \f]
+ * is such as \f[\pi_A=\pi_T\f] and \f[\pi_C=\pi_G\f]
+ * It can be computed analytically.
+ *
+ * We use as  parameters:
+ *
+ *\f[
+ * \begin{cases}
+ * \theta_A (=\pi_A) \in ]0;1/2[\\
+ * \gamma \in ]0;1/2[\\
+ * \alpha' > 1
+ * \end{cases}
+ * \f]
+ *
+ * where \f[\alpha'=\frac{2\alpha\pi_A+min(0.5-\pi_A,\gamma)}{0.5-\pi_A}\f].
+ *
+ * The generator is then computed as:
+ *
+ *\f[
+ * \begin{cases}
+ * \delta=\frac 12-\gamma\\
+ * \alpha=\frac{\alpha'(0.5-\pi_A)-min(0.5-\pi_A,\gamma)}{2\pi_A}\\
+ * \beta=\frac{2*\pi_A*(\alpha+\frac 12)-\delta}{1-2*\pi_A}\\
+ * \end{cases}
+ * \f]
+ *
+ * and @f$P at f$ is set for normalization.
+ *
+ * The parameters are named \c "thetaA", \c "gamma", \c "alphaP".
+ *
+ * References:
+ * - Rhetsky A. \& Ney M. (1995) MBE 12(1) 131-151.
+ * - Lobry J R (1995), Journal_ Of Molecular Evolution_ 40 326-330.
+ * - Schadt, Sinsheimer \& Lange (1998) Genome Research 8 222-233.
+ */
+
+class RN95s :
+  public virtual NucleotideSubstitutionModel,
+  public AbstractSubstitutionModel
+{
+private:
+  double alpha_, beta_, gamma_, delta_;
+  double r_;
+  /**
+   * For calculation purposes as in Schadt & al. (with c1_=1)
+   */
+  double c3_, c4_, c8_;
+  mutable RowMatrix<double> p_;
+  mutable double exp1_, exp3_, l_;
+
+public:
+  RN95s(const NucleicAlphabet* alphabet,
+        double alpha = 1,
+        double beta = 1,
+        double gamma = 1,
+        double delta = 1);
+
+  virtual ~RN95s() {}
+
+#ifndef NO_VIRTUAL_COV
+  RN95s*
+#else
+  Clonable*
+#endif
+  clone() const { return new RN95s(*this); }
+
+public:
+  double Pij_t    (int i, int j, double d) const;
+  double dPij_dt  (int i, int j, double d) const;
+  double d2Pij_dt2(int i, int j, double d) const;
+  const Matrix<double>& getPij_t    (double d) const;
+  const Matrix<double>& getdPij_dt  (double d) const;
+  const Matrix<double>& getd2Pij_dt2(double d) const;
+
+  std::string getName() const { return "RN95s"; }
+
+  void updateMatrices();
+
+  /**
+   * @brief This method takes the average value between observed @f$\pi_A at f$ and @f$\pi_T at f$.
+   */
+
+  void setFreq(std::map<int, double>&);
+};
+} // end of namespace bpp.
+
+#endif  // _RN95s_H_
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/SSR.cpp b/src/Bpp/Phyl/Model/Nucleotide/SSR.cpp
new file mode 100755
index 0000000..555355d
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/SSR.cpp
@@ -0,0 +1,120 @@
+//
+// File: SSR.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Nov 4 11:46 2008
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "SSR.h"
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+// From the STL:
+#include <cmath>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+ 
+SSR::SSR(
+	const NucleicAlphabet* alpha,
+	double beta,
+	double gamma,
+	double delta,
+	double theta):
+  AbstractParameterAliasable("SSR."),
+  AbstractSubstitutionModel(alpha, "SSR."),
+  AbstractReversibleSubstitutionModel(alpha, "SSR."),
+  beta_(beta), gamma_(gamma), delta_(delta_), theta_(theta),
+  piA_((1. - theta) / 2.), piC_(theta / 2.), piG_(theta / 2.), piT_((1. - theta) / 2.)
+{
+	addParameter_(new Parameter("SSR.beta" , beta , &Parameter::R_PLUS_STAR));
+	addParameter_(new Parameter("SSR.gamma", gamma, &Parameter::R_PLUS_STAR));
+	addParameter_(new Parameter("SSR.delta", delta, &Parameter::R_PLUS_STAR));
+	addParameter_(new Parameter("SSR.theta" , theta , &Parameter::PROP_CONSTRAINT_EX));
+	updateMatrices();
+}
+
+/******************************************************************************/
+	
+void SSR::updateMatrices()
+{
+  beta_  = getParameterValue("beta");
+  gamma_ = getParameterValue("gamma");
+  delta_ = getParameterValue("delta");
+  theta_ = getParameterValue("theta");
+  
+  freq_[0] = piA_ = (1. - theta_)/2.;
+  freq_[1] = piC_ = theta_/2.;
+  freq_[2] = piG_ = theta_/2;
+  freq_[3] = piT_ = (1. - theta_)/2.;
+	
+  // Exchangeability matrix:
+  exchangeability_(0,0) = -gamma_*piT_-piG_-beta_*piC_;
+  exchangeability_(1,0) = beta_;
+  exchangeability_(0,1) = beta_;
+  exchangeability_(2,0) = 1.;
+  exchangeability_(0,2) = 1.;
+  exchangeability_(3,0) = gamma_;
+  exchangeability_(0,3) = gamma_;
+  exchangeability_(1,1) = -piT_-delta_*piG_-beta_*piA_;
+  exchangeability_(1,2) = delta_;
+  exchangeability_(2,1) = delta_;
+  exchangeability_(1,3) = 1.;
+  exchangeability_(3,1) = 1.;
+  exchangeability_(2,2) = -beta_*piT_-delta_*piC_-piA_;
+  exchangeability_(2,3) = beta_;
+  exchangeability_(3,2) = beta_;
+  exchangeability_(3,3) = -beta_*piG_-piC_-gamma_*piA_;
+  
+  AbstractReversibleSubstitutionModel::updateMatrices();
+}
+
+/******************************************************************************/
+
+void SSR::setFreq(map<int, double>& freqs)
+{
+  piC_ = freqs[1];
+  piG_ = freqs[2];
+  setParameterValue("theta",piC_ + piG_);
+  updateMatrices();
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/SSR.h b/src/Bpp/Phyl/Model/Nucleotide/SSR.h
new file mode 100755
index 0000000..b565a3e
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/SSR.h
@@ -0,0 +1,135 @@
+//
+// File: SSR.h
+// Created by: Julien Dutheil
+// Created on: Tue Nov 4 11:46 2008
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _SSR_H_
+#define _SSR_H_
+
+#include "NucleotideSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+
+#include <Bpp/Numeric/Constraints.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The Strand Symmetric Reversible substitution model for
+ * nucleotides.
+ *
+ * We use a parametrization derived from Hobolth et al 2007
+ * \f[
+ * S = \begin{pmatrix}
+ * \cdots & \beta & 1 & \gamma \\ 
+ * \beta & \cdots & \delta & 1 \\ 
+ * 1 & \delta & \cdots & \beta \\ 
+ * \gamma & 1 & \beta & \cdots \\ 
+ * \end{pmatrix}
+ * \f]
+ * The equilibrium frequencies 
+ * \f[
+ * \pi = \left(1-\frac{\theta}{2}, \frac{\theta}{2}, \frac{\theta}{2}, 1-\frac{\theta}{2}\right)
+ * \f]
+ * This models hence includes four parameters, three relative rates \f$\beta, \gamma, \delta\f$ and the GC content \f$\theta\f$.
+ *
+ * Normalization: we set \f$f\f$ to 1, and scale the matrix so that \f$\sum_i Q_{i,i}\pi_i = -1\f$.
+ * The normalized generator is obtained by taking the dot product of \f$S\f$ and \f$\pi\f$:
+ * \f[
+ * Q = S . \pi = \frac{1}{P}\begin{pmatrix}
+ * -\gamma\pi_T-\pi_G-\beta\pi_C & \beta\pi_C & \pi_G & \gamma\pi_T \\ 
+ * \beta\pi_A & -\pi_T-\delta\pi_G-\beta\pi_A & \delta\pi_G & \pi_T \\ 
+ * \pi_A & \delta\pi_C & -\beta\pi_T-\delta\pi_C-\pi_A & \beta\pi_T \\ 
+ * \gamma\pi_A & \pi_C & \beta\pi_G & -\beta\pi_G-\pi_C-\gamma\pi_A \\ 
+ * \end{pmatrix}
+ * \f]
+ * where P is the normalization constant.
+ * For now, the generator of this model is diagonalized numericaly.
+ * See AbstractSubstitutionModel for details of how the probabilities are computed.
+ *
+ * The parameters are named \c "beta", \c "gamma", \c "delta", and \c "theta"
+ * and their values may be retrieved with the command 
+ * \code
+ * getParameterValue("beta")
+ * \endcode
+ * for instance.
+ * 
+ * Reference:
+ * - Hobolth A, Christensen O Fm Mailund T, Schierup M H (2007), PLoS_ Genetics_ 3(2) e7.
+ * - Yap VB, Speed TP (1995), Journal_ Of Molecular Evolution_ 58(1) 12-18
+ */
+class SSR:
+  public virtual NucleotideSubstitutionModel,
+  public AbstractReversibleSubstitutionModel
+{
+private:
+  double beta_, gamma_, delta_, theta_, piA_, piC_, piG_, piT_;
+  
+public:
+  SSR( const NucleicAlphabet* alpha,
+      double beta = 1.,
+      double gamma = 1.,
+      double delta = 1.,
+      double theta = 0.5);
+  
+  virtual ~SSR() {}
+  
+#ifndef NO_VIRTUAL_COV
+  SSR*
+#else
+  Clonable*
+#endif
+  clone() const { return new SSR(*this); }
+  
+public:
+  std::string getName() const { return "Strand Symmetric Reversible"; }
+  
+  void updateMatrices();
+  
+  /**
+   * @brief This method is redefined to actualize the corresponding parameters theta too.
+   */
+  void setFreq(std::map<int, double>&);
+};
+
+} //end of namespace bpp.
+
+#endif	//_SSR_H_
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/T92.cpp b/src/Bpp/Phyl/Model/Nucleotide/T92.cpp
new file mode 100644
index 0000000..0a7eceb
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/T92.cpp
@@ -0,0 +1,466 @@
+//
+// File: T92.cpp
+// Created by:  Julien Dutheil
+// Created on: Mon May 26 14:41:24 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "T92.h"
+#include "../FrequenciesSet/NucleotideFrequenciesSet.h"
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <cmath>
+
+using namespace std;
+
+/******************************************************************************/
+
+T92::T92(const NucleicAlphabet* alpha, double kappa, double theta) :
+  AbstractParameterAliasable("T92."),
+  AbstractSubstitutionModel(alpha, "T92."),
+  AbstractReversibleSubstitutionModel(alpha, "T92."),
+  kappa_(kappa),
+  theta_(theta),
+  k_(),
+  r_(),
+  piA_((1. - theta_) / 2.),
+  piC_(theta_ / 2.),
+  piG_(theta_ / 2.),
+  piT_((1. - theta_) / 2.),
+  exp1_(),
+  exp2_(),
+  l_(),
+  p_(size_, size_)
+{
+  addParameter_(new Parameter("T92.kappa", kappa, &Parameter::R_PLUS_STAR));
+  addParameter_(new Parameter("T92.theta", theta, &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+  p_.resize(size_, size_);
+  updateMatrices();
+}
+
+/******************************************************************************/
+
+void T92::updateMatrices()
+{
+  kappa_ = getParameterValue("kappa");
+  theta_ = getParameterValue("theta");
+  piA_ = (1 - theta_) / 2;
+  piC_ = theta_ / 2;
+  piG_ = theta_ / 2;
+  piT_ = (1 - theta_) / 2;
+  k_ = (kappa_ + 1.) / 2.;
+  r_ = 2. / (1. + 2. * theta_ * kappa_ - 2. * theta_ * theta_ * kappa_);
+
+  freq_[0] = piA_;
+  freq_[1] = piC_;
+  freq_[2] = piG_;
+  freq_[3] = piT_;
+
+  generator_(0, 0) = -(1. +        theta_ * kappa_) / 2;
+  generator_(1, 1) = -(1. + (1. - theta_) * kappa_) / 2;
+  generator_(2, 2) = -(1. + (1. - theta_) * kappa_) / 2;
+  generator_(3, 3) = -(1. +        theta_ * kappa_) / 2;
+
+  generator_(1, 0) = (1. - theta_) / 2;
+  generator_(3, 0) = (1. - theta_) / 2;
+  generator_(0, 1) = theta_ / 2;
+  generator_(2, 1) = theta_ / 2;
+  generator_(1, 2) = theta_ / 2;
+  generator_(3, 2) = theta_ / 2;
+  generator_(0, 3) = (1. - theta_) / 2;
+  generator_(2, 3) = (1. - theta_) / 2;
+
+  generator_(2, 0) = kappa_ * (1. - theta_) / 2;
+  generator_(3, 1) = kappa_ * theta_ / 2;
+  generator_(0, 2) = kappa_ * theta_ / 2;
+  generator_(1, 3) = kappa_ * (1. - theta_) / 2;
+
+  // Normalization:
+  MatrixTools::scale(generator_, r_);
+
+  // Exchangeability:
+  exchangeability_(0, 0) = generator_(0, 0) * 2. / (1. - theta_);
+  exchangeability_(0, 1) = generator_(0, 1) * 2. / theta_;
+  exchangeability_(0, 2) = generator_(0, 2) * 2. / theta_;
+  exchangeability_(0, 3) = generator_(0, 3) * 2. / (1. - theta_);
+
+  exchangeability_(1, 0) = generator_(1, 0) * 2. / (1. - theta_);
+  exchangeability_(1, 1) = generator_(1, 1) * 2 / theta_;
+  exchangeability_(1, 2) = generator_(1, 2) * 2 / theta_;
+  exchangeability_(1, 3) = generator_(1, 3) * 2 / (1. - theta_);
+
+  exchangeability_(2, 0) = generator_(2, 0) * 2. / (1. - theta_);
+  exchangeability_(2, 1) = generator_(2, 1) * 2 / theta_;
+  exchangeability_(2, 2) = generator_(2, 2) * 2 / theta_;
+  exchangeability_(2, 3) = generator_(2, 3) * 2 / (1. - theta_);
+
+  exchangeability_(3, 0) = generator_(3, 0) * 2. / (1. - theta_);
+  exchangeability_(3, 1) = generator_(3, 1) * 2. / theta_;
+  exchangeability_(3, 2) = generator_(3, 2) * 2. / theta_;
+  exchangeability_(3, 3) = generator_(3, 3) * 2. / (1. - theta_);
+
+  // Eigen values:
+  eigenValues_[0] = 0;
+  eigenValues_[1] = eigenValues_[2] = -r_ * (1. + kappa_) / 2;
+  eigenValues_[3] = -r_;
+
+  // Eigen vectors:
+  leftEigenVectors_(0, 0) = -(theta_ - 1.) / 2.;
+  leftEigenVectors_(0, 1) = theta_ / 2.;
+  leftEigenVectors_(0, 2) = theta_ / 2.;
+  leftEigenVectors_(0, 3) = -(theta_ - 1.) / 2.;
+
+  leftEigenVectors_(1, 0) = 0.;
+  leftEigenVectors_(1, 1) = -(theta_ - 1.);
+  leftEigenVectors_(1, 2) = 0.;
+  leftEigenVectors_(1, 3) = theta_ - 1.;
+
+  leftEigenVectors_(2, 0) = theta_;
+  leftEigenVectors_(2, 1) = 0.;
+  leftEigenVectors_(2, 2) = -theta_;
+  leftEigenVectors_(2, 3) = 0.;
+
+  leftEigenVectors_(3, 0) = -(theta_ - 1.) / 2.;
+  leftEigenVectors_(3, 1) = -theta_ / 2.;
+  leftEigenVectors_(3, 2) = theta_ / 2.;
+  leftEigenVectors_(3, 3) = (theta_ - 1.) / 2.;
+
+
+  rightEigenVectors_(0, 0) = 1.;
+  rightEigenVectors_(0, 1) = 0.;
+  rightEigenVectors_(0, 2) = 1.;
+  rightEigenVectors_(0, 3) = 1.;
+
+  rightEigenVectors_(1, 0) = 1.;
+  rightEigenVectors_(1, 1) = 1.;
+  rightEigenVectors_(1, 2) = 0.;
+  rightEigenVectors_(1, 3) = -1.;
+
+  rightEigenVectors_(2, 0) = 1.;
+  rightEigenVectors_(2, 1) = 0.;
+  rightEigenVectors_(2, 2) = (theta_ - 1.) / theta_;
+  rightEigenVectors_(2, 3) = 1.;
+
+  rightEigenVectors_(3, 0) = 1.;
+  rightEigenVectors_(3, 1) = theta_ / (theta_ - 1.);
+  rightEigenVectors_(3, 2) = 0;
+  rightEigenVectors_(3, 3) = -1.;
+}
+
+/******************************************************************************/
+
+double T92::Pij_t(int i, int j, double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = exp(-l_);
+  exp2_ = exp(-k_ * l_);
+
+  switch (i)
+  {
+  // A
+  case 0: {
+    switch (j)
+    {
+    case 0: return piA_ * (1. + exp1_) + theta_ * exp2_; // A
+    case 1: return piC_ * (1. - exp1_);                 // C
+    case 2: return piG_ * (1. + exp1_) - theta_ * exp2_; // G
+    case 3: return piT_ * (1. - exp1_);                 // T, U
+    }
+  }
+  // C
+  case 1: {
+    switch (j)
+    {
+    case 0: return piA_ * (1. - exp1_);                        // A
+    case 1: return piC_ * (1. + exp1_) + (1. - theta_) * exp2_; // C
+    case 2: return piG_ * (1. - exp1_);                        // G
+    case 3: return piT_ * (1. + exp1_) - (1. - theta_) * exp2_; // T, U
+    }
+  }
+  // G
+  case 2: {
+    switch (j)
+    {
+    case 0: return piA_ * (1. + exp1_) - (1. - theta_) * exp2_; // A
+    case 1: return piC_ * (1. - exp1_);                        // C
+    case 2: return piG_ * (1. + exp1_) + (1. - theta_) * exp2_; // G
+    case 3: return piT_ * (1. - exp1_);                        // T, U
+    }
+  }
+  // T, U
+  case 3: {
+    switch (j)
+    {
+    case 0: return piA_ * (1. - exp1_);                 // A
+    case 1: return piC_ * (1. + exp1_) - theta_ * exp2_; // C
+    case 2: return piG_ * (1. - exp1_);                 // G
+    case 3: return piT_ * (1. + exp1_) + theta_ * exp2_; // T, U
+    }
+  }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+
+double T92::dPij_dt(int i, int j, double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = exp(-l_);
+  exp2_ = exp(-k_ * l_);
+
+  switch (i)
+  {
+  // A
+  case 0: {
+    switch (j)
+    {
+    case 0: return rate_ * r_ * (piA_ * -exp1_ + theta_ * -k_ * exp2_); // A
+    case 1: return rate_ * r_ * (piC_ *   exp1_);                       // C
+    case 2: return rate_ * r_ * (piG_ * -exp1_ - theta_ * -k_ * exp2_); // G
+    case 3: return rate_ * r_ * (piT_ *   exp1_);                       // T, U
+    }
+  }
+  // C
+  case 1: {
+    switch (j)
+    {
+    case 0: return rate_ * r_ * (piA_ *   exp1_);                              // A
+    case 1: return rate_ * r_ * (piC_ * -exp1_ + (1. - theta_) * -k_ * exp2_); // C
+    case 2: return rate_ * r_ * (piG_ *   exp1_);                              // G
+    case 3: return rate_ * r_ * (piT_ * -exp1_ - (1. - theta_) * -k_ * exp2_); // T, U
+    }
+  }
+  // G
+  case 2: {
+    switch (j)
+    {
+    case 0: return rate_ * r_ * (piA_ * -exp1_ - (1. - theta_) * -k_ * exp2_); // A
+    case 1: return rate_ * r_ * (piC_ *   exp1_);                              // C
+    case 2: return rate_ * r_ * (piG_ * -exp1_ + (1. - theta_) * -k_ * exp2_); // G
+    case 3: return rate_ * r_ * (piT_ *   exp1_);                              // T, U
+    }
+  }
+  // T, U
+  case 3: {
+    switch (j)
+    {
+    case 0: return rate_ * r_ * (piA_ *   exp1_);                       // A
+    case 1: return rate_ * r_ * (piC_ * -exp1_ - theta_ * -k_ * exp2_); // C
+    case 2: return rate_ * r_ * (piG_ *   exp1_);                       // G
+    case 3: return rate_ * r_ * (piT_ * -exp1_ + theta_ * -k_ * exp2_); // T, U
+    }
+  }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+
+double T92::d2Pij_dt2(int i, int j, double d) const
+{
+  double k2_ = k_ * k_;
+  l_ = rate_ * r_ * d;
+  double r2 = rate_ * rate_ * r_ * r_;
+  exp1_ = exp(-l_);
+  exp2_ = exp(-k_ * l_);
+
+  switch (i)
+  {
+  // A
+  case 0: {
+    switch (j)
+    {
+    case 0: return r2 * (piA_ *   exp1_ + theta_ * k2_ * exp2_); // A
+    case 1: return r2 * (piC_ * -exp1_);                       // C
+    case 2: return r2 * (piG_ *   exp1_ - theta_ * k2_ * exp2_); // G
+    case 3: return r2 * (piT_ * -exp1_);                       // T, U
+    }
+  }
+  // C
+  case 1: {
+    switch (j)
+    {
+    case 0: return r2 * (piA_ * -exp1_);                              // A
+    case 1: return r2 * (piC_ *   exp1_ + (1. - theta_) * k2_ * exp2_); // C
+    case 2: return r2 * (piG_ * -exp1_);                              // G
+    case 3: return r2 * (piT_ *   exp1_ - (1. - theta_) * k2_ * exp2_); // T, U
+    }
+  }
+  // G
+  case 2: {
+    switch (j)
+    {
+    case 0: return r2 * (piA_ *   exp1_ - (1. - theta_) * k2_ * exp2_); // A
+    case 1: return r2 * (piC_ * -exp1_);                              // C
+    case 2: return r2 * (piG_ *   exp1_ + (1. - theta_) * k2_ * exp2_); // G
+    case 3: return r2 * (piT_ * -exp1_);                              // T, U
+    }
+  }
+  // T, U
+  case 3: {
+    switch (j)
+    {
+    case 0: return r2 * (piA_ * -exp1_);                       // A
+    case 1: return r2 * (piC_ *   exp1_ - theta_ * k2_ * exp2_); // C
+    case 2: return r2 * (piG_ * -exp1_);                       // G
+    case 3: return r2 * (piT_ *   exp1_ + theta_ * k2_ * exp2_); // T, U
+    }
+  }
+  }
+  return 0;
+}
+
+/******************************************************************************/
+
+const Matrix<double>& T92::getPij_t(double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = exp(-l_);
+  exp2_ = exp(-k_ * l_);
+
+  // A
+  p_(0, 0) = piA_ * (1. + exp1_) + theta_ * exp2_; // A
+  p_(0, 1) = piC_ * (1. - exp1_);                  // C
+  p_(0, 2) = piG_ * (1. + exp1_) - theta_ * exp2_; // G
+  p_(0, 3) = piT_ * (1. - exp1_);                  // T, U
+
+  // C
+  p_(1, 0) = piA_ * (1. - exp1_);                         // A
+  p_(1, 1) = piC_ * (1. + exp1_) + (1. - theta_) * exp2_; // C
+  p_(1, 2) = piG_ * (1. - exp1_);                         // G
+  p_(1, 3) = piT_ * (1. + exp1_) - (1. - theta_) * exp2_; // T, U
+
+  // G
+  p_(2, 0) = piA_ * (1. + exp1_) - (1. - theta_) * exp2_; // A
+  p_(2, 1) = piC_ * (1. - exp1_);                         // C
+  p_(2, 2) = piG_ * (1. + exp1_) + (1. - theta_) * exp2_; // G
+  p_(2, 3) = piT_ * (1. - exp1_);                         // T, U
+
+  // T, U
+  p_(3, 0) = piA_ * (1. - exp1_);                  // A
+  p_(3, 1) = piC_ * (1. + exp1_) - theta_ * exp2_; // C
+  p_(3, 2) = piG_ * (1. - exp1_);                  // G
+  p_(3, 3) = piT_ * (1. + exp1_) + theta_ * exp2_; // T, U
+
+  return p_;
+}
+
+const Matrix<double>& T92::getdPij_dt(double d) const
+{
+  l_ = rate_ * r_ * d;
+  exp1_ = exp(-l_);
+  exp2_ = exp(-k_ * l_);
+
+  // A
+  p_(0, 0) = rate_ * r_ * (piA_ * -exp1_ + theta_ * -k_ * exp2_); // A
+  p_(0, 1) = rate_ * r_ * (piC_ *   exp1_);                        // C
+  p_(0, 2) = rate_ * r_ * (piG_ * -exp1_ - theta_ * -k_ * exp2_); // G
+  p_(0, 3) = rate_ * r_ * (piT_ *   exp1_);                        // T, U
+
+  // C
+  p_(1, 0) = rate_ * r_ * (piA_ *   exp1_);                               // A
+  p_(1, 1) = rate_ * r_ * (piC_ * -exp1_ + (1. - theta_) * -k_ * exp2_); // C
+  p_(1, 2) = rate_ * r_ * (piG_ *   exp1_);                               // G
+  p_(1, 3) = rate_ * r_ * (piT_ * -exp1_ - (1. - theta_) * -k_ * exp2_); // T, U
+
+  // G
+  p_(2, 0) = rate_ * r_ * (piA_ * -exp1_ - (1. - theta_) * -k_ * exp2_); // A
+  p_(2, 1) = rate_ * r_ * (piC_ *   exp1_);                               // C
+  p_(2, 2) = rate_ * r_ * (piG_ * -exp1_ + (1. - theta_) * -k_ * exp2_); // G
+  p_(2, 3) = rate_ * r_ * (piT_ *   exp1_);                               // T, U
+
+  // T, U
+  p_(3, 0) = rate_ * r_ * (piA_ *   exp1_);                        // A
+  p_(3, 1) = rate_ * r_ * (piC_ * -exp1_ - theta_ * -k_ * exp2_); // C
+  p_(3, 2) = rate_ * r_ * (piG_ *   exp1_);                        // G
+  p_(3, 3) = rate_ * r_ * (piT_ * -exp1_ + theta_ * -k_ * exp2_); // T, U
+
+  return p_;
+}
+
+const Matrix<double>& T92::getd2Pij_dt2(double d) const
+{
+  double k2 = k_ * k_;
+  l_ = rate_ * r_ * d;
+  double r2 = rate_ * rate_ * r_ * r_;
+  exp1_ = exp(-l_);
+  exp2_ = exp(-k_ * l_);
+
+  // A
+  p_(0, 0) = r2 * (piA_ *   exp1_ + theta_ * k2 * exp2_); // A
+  p_(0, 1) = r2 * (piC_ * -exp1_);                      // C
+  p_(0, 2) = r2 * (piG_ *   exp1_ - theta_ * k2 * exp2_); // G
+  p_(0, 3) = r2 * (piT_ * -exp1_);                      // T, U
+
+  // C
+  p_(1, 0) = r2 * (piA_ * -exp1_);                             // A
+  p_(1, 1) = r2 * (piC_ *   exp1_ + (1. - theta_) * k2 * exp2_); // C
+  p_(1, 2) = r2 * (piG_ * -exp1_);                             // G
+  p_(1, 3) = r2 * (piT_ *   exp1_ - (1. - theta_) * k2 * exp2_); // T, U
+
+  // G
+  p_(2, 0) = r2 * (piA_ *   exp1_ - (1. - theta_) * k2 * exp2_); // A
+  p_(2, 1) = r2 * (piC_ * -exp1_);                             // C
+  p_(2, 2) = r2 * (piG_ *   exp1_ + (1. - theta_) * k2 * exp2_); // G
+  p_(2, 3) = r2 * (piT_ * -exp1_);                             // T, U
+
+  // T, U
+  p_(3, 0) = r2 * (piA_ * -exp1_);                      // A
+  p_(3, 1) = r2 * (piC_ *   exp1_ - theta_ * k2 * exp2_); // C
+  p_(3, 2) = r2 * (piG_ * -exp1_);                      // G
+  p_(3, 3) = r2 * (piT_ *   exp1_ + theta_ * k2 * exp2_); // T, U
+
+  return p_;
+}
+
+/******************************************************************************/
+
+void T92::setFreq(std::map<int, double>& freqs)
+{
+  double f = (freqs[1] + freqs[2]) / (freqs[0] + freqs[1] + freqs[2] + freqs[3]);
+  setParameterValue("theta", f);
+  updateMatrices();
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/T92.h b/src/Bpp/Phyl/Model/Nucleotide/T92.h
new file mode 100644
index 0000000..39068b2
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/T92.h
@@ -0,0 +1,202 @@
+//
+// File: T92.h
+// Created by: Julien Dutheil
+// Created on: Mon May 26 14:41:24 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _T92_H_
+#define _T92_H_
+
+#include "NucleotideSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+
+#include <Bpp/Numeric/Constraints.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+#include <Bpp/Seq/Container/SequenceContainer.h>
+
+namespace bpp
+{
+/**
+ * @brief The Tamura (1992) substitution model for nucleotides.
+ *
+ * This model is similar to the K80 model,
+ * but allows distinct equilibrium frequencies between GC and AT.
+ * This models hence includes two parameters, the transition / transversion
+ * relative rate \f$\kappa\f$ and the frequency of GC, \f$\theta\f$.
+ * \f[
+ * S = \begin{pmatrix}
+ * \cdots & r & \kappa r & r \\
+ * r & \cdots & r & \kappa r \\
+ * \kappa r & r & \cdots & r \\
+ * r & \kappa r & r & \cdots \\
+ * \end{pmatrix}
+ * \f]
+ * \f[
+ * \pi = \left(\frac{1-\theta}{2}, \frac{\theta}{2}, \frac{\theta}{2}, \frac{1 - \theta}{2}\right)
+ * \f]
+ * Normalization: \f$r\f$ is set so that \f$\sum_i Q_{i,i}\pi_i = -1\f$:
+ * \f[
+ * S = \frac{1}{P}\begin{pmatrix}
+ * \frac{2\theta\kappa + 2}{\theta - 1} & 2 & 2\kappa & 2 \\
+ * 2 & \frac{2(\theta-1)\kappa - 2}{\theta} & 2 & 2\kappa \\
+ * 2\kappa & 2 & \frac{2(\theta-1)\kappa - 2}{\theta} & 2 \\
+ * 2 & 2\kappa & 2 & \frac{2\theta\kappa + 2}{\theta - 1} \\
+ * \end{pmatrix}
+ * \f]
+ * with \f$P=1+2\theta\kappa-2\theta^2\kappa\f$.
+ *
+ * The normalized generator is obtained by taking the dot product of \f$S\f$ and \f$\pi\f$:
+ * \f[
+ * Q = S . \pi = \frac{1}{P}\begin{pmatrix}
+ * -(\theta\kappa+1) & \theta & \theta\kappa & 1-\theta \\
+ * 1-\theta & -((1-\theta)\kappa+1) & \theta & (1-\theta)\kappa \\
+ * (1-\theta)\kappa & \theta & -((1-\theta)\kappa+1) & 1-\theta \\
+ * 1-\theta & \theta\kappa & \theta & -(\theta\kappa+1) \\
+ * \end{pmatrix}
+ * \f]
+ *
+ * The eigen values are \f$\left(0, -\frac{\kappa+1}{P}, -\frac{\kappa+1}{P}, -\frac{2}{P}\right)\f$,
+ * the left eigen vectors are, by row:
+ * \f[
+ * U = \begin{pmatrix}
+ * \frac{1-\theta}{2} &  \frac{\theta}{2} &  \frac{\theta}{2} & \frac{1-\theta}{2} \\
+ *                  0 &          1-\theta &                 0 & \theta-1 \\
+ *             \theta &                   0 &         -\theta & 0 \\
+ * \frac{1-\theta}{2} & -\frac{\theta}{2} &  \frac{\theta}{2} & -\frac{1-\theta}{2} \\
+ * \end{pmatrix}
+ * \f]
+ * and the right eigen vectors are, by column:
+ * \f[
+ * U^-1 = \begin{pmatrix}
+ * 1 &  0 &  1 &  1 \\
+ * 1 &  1 &  0 & -1 \\
+ * 1 &  0 & -\frac{1-\theta}{\theta} &  1 \\
+ * 1 & -\frac{\theta}{1-\theta} &  0 & -1 \\
+ * \end{pmatrix}
+ * \f]
+ *
+ * In addition, a rate_ factor defines the mean rate of the model.
+ *
+ * The probabilities of changes are computed analytically using the formulas:
+ * \f{multline*}
+ * P_{i,j}(t) = \\
+ * \begin{pmatrix}
+ * \theta A + \frac{1-\theta}{2}B + \frac{1-\theta}{2} & \frac{\theta}{2} - \frac{\theta}{2}B & -\theta A + \frac{\theta}{2}B + \frac{\theta}{2} & \frac{1-\theta}{2} - \frac{1-\theta}{2}B \\
+ * \frac{1-\theta}{2} - \frac{1-\theta}{2}B & (1-\theta)A + \frac{\theta}{2}B + \frac{\theta}{2} & \frac{\theta}{2} - \frac{\theta}{2}B & -(1-\theta)A + \frac{1-\theta}{2}B + \frac{1-\theta}{2} \\
+ * -(1-\theta)A + \frac{1-\theta}{2}B + \frac{1-\theta}{2} & \frac{\theta}{2} - \frac{\theta}{2}B & (1-\theta)A + \frac{\theta}{2}B + \frac{\theta}{2} & \frac{1-\theta}{2} - \frac{1-\theta}{2}B \\
+ * \frac{1-\theta}{2} - \frac{1-\theta}{2}B & -\theta A + \frac{\theta}{2}B + \frac{\theta}{2} & \frac{\theta}{2} - \frac{\theta}{2}B & \theta A + \frac{1-\theta}{2}B + \frac{1-\theta}{2} \\
+ * \end{pmatrix}
+ * \f}
+ * with \f$A=e^{-\frac{rate\_ * (\kappa+1)t}{P}}\f$ and \f$B = e^{-\frac{rate\_ * 2t}{P}}\f$.
+ *
+ * First and second order derivatives are also computed analytically using the formulas:
+ * \f{multline*}
+ * \frac{\partial P_{i,j}(t)}{\partial t} = rate\_ * \\
+ * \frac{1}{P}
+ * \begin{pmatrix}
+ * -\theta(\kappa+1)A - (1-\theta)B & \theta B & \theta(\kappa+1)A - \theta B & (1-\theta)B \\
+ * (1-\theta)B & -(1-\theta)(\kappa+1)A - \theta B & \theta B & (1-\theta)(\kappa+1)A - (1-\theta)B \\
+ * (1-\theta)(\kappa+1)A - (1-\theta)B & \theta B & -(1-\theta)(\kappa+1)A - \theta B & (1-\theta)B \\
+ * (1-\theta)B & \theta(\kappa+1)A - \theta B & \theta B & -\theta(\kappa+1)A - (1-\theta)B \\
+ * \end{pmatrix}
+ * \f}
+ * \f{multline*}
+ * \frac{\partial^2 P_{i,j}(t)}{\partial t^2} = rate\_^2 * \\
+ * \frac{1}{P^2}
+ * \begin{pmatrix}
+ * \theta{(\kappa+1)}^2A + 2(1-\theta)B & -2\theta B & -\theta{(\kappa+1)}^2A + 2\theta B & -2(1-\theta)B \\
+ * -2(1-\theta)B & (1-\theta){(\kappa+1)}^2A + 2\theta B & -2\theta B & -(1-\theta){(\kappa+1)}^2A + 2(1-\theta)B \\
+ * -(1-\theta){(\kappa+1)}^2A + 2(1-\theta)B & -2\theta B & (1-\theta){(\kappa+1)}^2A + 2\theta B & -2(1-\theta)B \\
+ * -2(1-\theta)B & -\theta{(\kappa+1)}^2A + 2\theta B & -2\theta B & \theta{(\kappa+1)}^2A + 2(1-\theta)B \\
+ * \end{pmatrix}
+ * \f}
+ *
+ * The parameters are named \c "kappa" and \c "theta"
+ * and their values may be retrieve with the commands
+ * \code
+ * getParameterValue("kappa")
+ * getParameterValue("theta")
+ * \endcode
+ *
+ * Reference:
+ * - Tamura K (1992), Molecular_ Biology And Evolution_ 9(5) 814-25.
+ */
+class T92 :
+  public virtual NucleotideSubstitutionModel,
+  public AbstractReversibleSubstitutionModel
+{
+private:
+  double kappa_, theta_, k_, r_, piA_, piC_, piG_, piT_;
+  mutable double exp1_, exp2_, l_;
+  mutable RowMatrix<double> p_;
+
+public:
+  T92(const NucleicAlphabet* alpha, double kappa = 1., double theta = 0.5);
+
+  virtual ~T92() {}
+
+#ifndef NOVIRTUAL_COV_
+  T92*
+#else
+  Clonable*
+#endif
+  clone() const { return new T92(*this); }
+
+public:
+  double Pij_t    (int i, int j, double d) const;
+  double dPij_dt  (int i, int j, double d) const;
+  double d2Pij_dt2(int i, int j, double d) const;
+  const Matrix<double>& getPij_t(double d) const;
+  const Matrix<double>& getdPij_dt(double d) const;
+  const Matrix<double>& getd2Pij_dt2(double d) const;
+
+  std::string getName() const { return "T92"; }
+
+
+  /**
+   * @brief This method is over-defined to actualize the 'theta' parameter too.
+   */
+  void setFreq(std::map<int, double>& freqs);
+
+protected:
+  void updateMatrices();
+};
+} // end of namespace bpp.
+
+#endif  // _T92_H_
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/TN93.cpp b/src/Bpp/Phyl/Model/Nucleotide/TN93.cpp
new file mode 100755
index 0000000..83f5179
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/TN93.cpp
@@ -0,0 +1,448 @@
+//
+// File: TN93.cpp
+// Created by: Julien Dutheil
+// Created on: Thu Jan 22 10:26:51 2004
+//
+
+/*
+Copyright or © or Copr. Bio++ Developement Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "TN93.h"
+#include "../FrequenciesSet/NucleotideFrequenciesSet.h"
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Numeric/Matrix/EigenValue.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+// From the STL:
+#include <cmath>
+
+using namespace std;
+
+using namespace bpp;
+
+/******************************************************************************/
+
+TN93::TN93(
+	const NucleicAlphabet* alpha,
+	double kappa1,
+	double kappa2,
+	double piA,
+	double piC,
+	double piG,
+	double piT):
+  AbstractParameterAliasable("TN93."),
+  AbstractSubstitutionModel(alpha, "TN93."),
+  AbstractReversibleSubstitutionModel(alpha, "TN93."),
+  kappa1_(kappa1), kappa2_(kappa2), 
+  piA_(piA), piC_(piC), piG_(piG), piT_(piT), piY_(), piR_(),
+  r_(), k1_(), k2_(),
+  theta_(piG + piC), theta1_(piA / (1. - theta_)), theta2_(piG / theta_),
+  exp1_(), exp21_(), exp22_(), l_(), p_(size_, size_)
+{
+	addParameter_(new Parameter("TN93.kappa1", kappa1, &Parameter::R_PLUS_STAR));
+	addParameter_(new Parameter("TN93.kappa2", kappa2, &Parameter::R_PLUS_STAR));
+	addParameter_(new Parameter("TN93.theta" , theta_ , &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+	addParameter_(new Parameter("TN93.theta1", theta1_, &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+	addParameter_(new Parameter("TN93.theta2", theta2_, &FrequenciesSet::FREQUENCE_CONSTRAINT_SMALL));
+  p_.resize(size_, size_);
+	updateMatrices();
+}
+
+/******************************************************************************/
+
+void TN93::updateMatrices()
+{
+	kappa1_ = getParameterValue("kappa1");
+	kappa2_ = getParameterValue("kappa2");
+  theta_  = getParameterValue("theta" );
+	theta1_ = getParameterValue("theta1");
+	theta2_ = getParameterValue("theta2");
+  piA_ = theta1_ * (1. - theta_);
+  piC_ = (1. - theta2_) * theta_;
+  piG_ = theta2_ * theta_;
+  piT_ = (1. - theta1_) * (1. - theta_);
+	piR_ = piA_ + piG_;
+	piY_ = piT_ + piC_;
+	r_ = 1. / (2. * (piA_ * piC_ + piC_ * piG_ + piA_ * piT_ + piG_ * piT_ + kappa2_ * piC_ * piT_ + kappa1_ * piA_ * piG_));
+	k1_ = kappa2_ * piY_ + piR_;
+	k2_ = kappa1_ * piR_ + piY_;
+
+  freq_[0] = piA_;
+  freq_[1] = piC_;
+  freq_[2] = piG_;
+  freq_[3] = piT_;
+		
+	generator_(0, 0) = -(                       piC_ + kappa1_*piG_ +         piT_);
+	generator_(1, 1) = -(        piA_ +                        piG_ + kappa2_*piT_); 
+	generator_(2, 2) = -(kappa1_*piA_ +         piC_                +         piT_);
+	generator_(3, 3) = -(        piA_ + kappa2_*piC_ +         piG_               );
+
+	generator_(1, 0) = piA_;
+	generator_(3, 0) = piA_;
+	generator_(0, 1) = piC_;
+	generator_(2, 1) = piC_;
+	generator_(1, 2) = piG_;
+	generator_(3, 2) = piG_;
+	generator_(0, 3) = piT_;
+	generator_(2, 3) = piT_;
+	
+	generator_(2, 0) = kappa1_ * piA_;
+	generator_(3, 1) = kappa2_ * piC_;
+	generator_(0, 2) = kappa1_ * piG_;
+	generator_(1, 3) = kappa2_ * piT_;
+	
+	// Normalization:
+	MatrixTools::scale(generator_, r_);
+	
+	// Exchangeability:
+	exchangeability_(0,0) = generator_(0,0) / piA_;
+	exchangeability_(0,1) = generator_(0,1) / piC_; 
+	exchangeability_(0,2) = generator_(0,2) / piG_; 
+	exchangeability_(0,3) = generator_(0,3) / piT_;
+
+	exchangeability_(1,0) = generator_(1,0) / piA_; 
+	exchangeability_(1,1) = generator_(1,1) / piC_; 
+	exchangeability_(1,2) = generator_(1,2) / piG_; 
+	exchangeability_(1,3) = generator_(1,3) / piT_; 
+	
+	exchangeability_(2,0) = generator_(2,0) / piA_; 
+	exchangeability_(2,1) = generator_(2,1) / piC_; 
+	exchangeability_(2,2) = generator_(2,2) / piG_; 
+	exchangeability_(2,3) = generator_(2,3) / piT_; 
+	
+	exchangeability_(3,0) = generator_(3,0) / piA_;
+	exchangeability_(3,1) = generator_(3,1) / piC_; 
+	exchangeability_(3,2) = generator_(3,2) / piG_; 
+	exchangeability_(3,3) = generator_(3,3) / piT_;
+
+	// We are not sure that the values are computed in this order :p
+	// Eigen values:
+	//eigenValues_[0] = 0;
+	//eigenValues_[1] = -r * (kappa2 * piY + piR);
+	//eigenValues_[2] = -r * (kappa1 * piR + piY); 
+	//eigenValues_[3] = -r;
+	
+	// Eigen vectors and values:
+	EigenValue<double> ev(generator_);
+	rightEigenVectors_ = ev.getV();
+	MatrixTools::inv(rightEigenVectors_, leftEigenVectors_);
+	eigenValues_ = ev.getRealEigenValues();
+}
+	
+/******************************************************************************/
+
+double TN93::Pij_t(int i, int j, double d) const
+{
+  l_ = rate_ * r_ * d;
+	exp1_ = exp(-l_);
+	exp22_ = exp(-k2_ * l_);
+	exp21_ = exp(-k1_ * l_);
+	
+	switch(i)
+  {
+		//A
+		case 0 : {
+			switch(j) {
+				case 0 : return piA_ * (1. + (piY_/piR_) * exp1_) + (piG_/piR_) * exp22_; //A
+				case 1 : return piC_ * (1. -               exp1_);                        //C
+				case 2 : return piG_ * (1. + (piY_/piR_) * exp1_) - (piG_/piR_) * exp22_; //G
+				case 3 : return piT_ * (1. -               exp1_);                        //T, U
+			}
+		} 
+		//C
+		case 1 : {
+			switch(j) {
+				case 0 : return piA_ * (1. -               exp1_);                         //A
+				case 1 : return piC_ * (1. + (piR_/piY_) * exp1_) + (piT_/piY_) * exp21_; //C
+				case 2 : return piG_ * (1. -               exp1_);                        //G
+				case 3 : return piT_ * (1. + (piR_/piY_) * exp1_) - (piT_/piY_) * exp21_; //T, U
+			}
+		}
+		//G
+		case 2 : {
+			switch(j) {
+				case 0 : return piA_ * (1. + (piY_/piR_) * exp1_) - (piA_/piR_) * exp22_; //A
+				case 1 : return piC_ * (1. -               exp1_);                        //C
+				case 2 : return piG_ * (1. + (piY_/piR_) * exp1_) + (piA_/piR_) * exp22_; //G
+				case 3 : return piT_ * (1. -               exp1_);                        //T, U
+			}
+		}
+		//T, U
+		case 3 : {
+			switch(j) {
+				case 0 : return piA_ * (1. -               exp1_);                        //A
+				case 1 : return piC_ * (1. + (piR_/piY_) * exp1_) - (piC_/piY_) * exp21_; //C
+				case 2 : return piG_ * (1. -               exp1_);                        //G
+				case 3 : return piT_ * (1. + (piR_/piY_) * exp1_) + (piC_/piY_) * exp21_; //T, U
+			}
+		}
+	}
+	return 0;
+}
+
+/******************************************************************************/
+
+double TN93::dPij_dt(int i, int j, double d) const
+{
+  l_ = rate_ * r_ * d;
+	exp1_ = exp(-l_);
+	exp22_ = exp(-k2_ * l_);
+	exp21_ = exp(-k1_ * l_);
+	
+	switch(i)
+  {
+		//A
+		case 0 : {
+			switch(j) {
+				case 0 : return rate_ * r_ * (piA_ * -(piY_/piR_) * exp1_ - (piG_/piR_) * k2_ * exp22_); //A
+				case 1 : return rate_ * r_ * (piC_ *                exp1_);                              //C
+				case 2 : return rate_ * r_ * (piG_ * -(piY_/piR_) * exp1_ + (piG_/piR_) * k2_ * exp22_); //G
+				case 3 : return rate_ * r_ * (piT_ *                exp1_);                              //T, U
+			}
+		} 
+		//C
+		case 1 : {
+			switch(j) {
+				case 0 : return rate_ * r_ * (piA_ *                exp1_);                              //A
+				case 1 : return rate_ * r_ * (piC_ * -(piR_/piY_) * exp1_ - (piT_/piY_) * k1_ * exp21_); //C
+				case 2 : return rate_ * r_ * (piG_ *                exp1_);                              //G
+				case 3 : return rate_ * r_ * (piT_ * -(piR_/piY_) * exp1_ + (piT_/piY_) * k1_ * exp21_); //T, U
+			}
+		}
+		//G
+		case 2 : {
+			switch(j) {
+				case 0 : return rate_ * r_ * (piA_ * -(piY_/piR_) * exp1_ + (piA_/piR_) * k2_ * exp22_); //A
+				case 1 : return rate_ * r_ * (piC_ *                exp1_);                              //C
+				case 2 : return rate_ * r_ * (piG_ * -(piY_/piR_) * exp1_ - (piA_/piR_) * k2_ * exp22_); //G
+				case 3 : return rate_ * r_ * (piT_ *                exp1_);                              //T, U
+			}
+		}
+		//T, U
+		case 3 : {
+			switch(j) {
+				case 0 : return rate_ * r_ * (piA_ *                exp1_);                              //A
+				case 1 : return rate_ * r_ * (piC_ * -(piR_/piY_) * exp1_ + (piC_/piY_) * k1_ * exp21_); //C
+				case 2 : return rate_ * r_ * (piG_ *                exp1_);                              //G
+				case 3 : return rate_ * r_ * (piT_ * -(piR_/piY_) * exp1_ - (piC_/piY_) * k1_ * exp21_); //T, U
+			}
+		}
+	}
+	return 0;
+}
+
+/******************************************************************************/
+
+double TN93::d2Pij_dt2(int i, int j, double d) const
+{
+  double r_2 = rate_ * rate_ * r_ * r_;
+  l_ = rate_ * r_ * d;
+	double k1_2 = k1_ * k1_;
+	double k2_2 = k2_ * k2_;
+	exp1_ = exp(-l_);
+	exp22_ = exp(-k2_ * l_);
+	exp21_ = exp(-k1_ * l_);
+
+	switch(i)
+  {
+		//A
+		case 0 : {
+			switch(j) {
+				case 0 : return r_2 * (piA_ * (piY_/piR_) * exp1_ + (piG_/piR_) * k2_2 * exp22_); //A
+				case 1 : return r_2 * (piC_ *             - exp1_);                               //C
+				case 2 : return r_2 * (piG_ * (piY_/piR_) * exp1_ - (piG_/piR_) * k2_2 * exp22_); //G
+				case 3 : return r_2 * (piT_ *             - exp1_);                               //T, U
+			}
+		}
+		//C
+		case 1 : {
+			switch(j) {
+				case 0 : return r_2 * (piA_ *             - exp1_);                               //A
+				case 1 : return r_2 * (piC_ * (piR_/piY_) * exp1_ + (piT_/piY_) * k1_2 * exp21_); //C
+				case 2 : return r_2 * (piG_ *             - exp1_);                               //G
+				case 3 : return r_2 * (piT_ * (piR_/piY_) * exp1_ - (piT_/piY_) * k1_2 * exp21_); //T, U
+			}
+		}
+		//G
+		case 2 : {
+			switch(j) {
+				case 0 : return r_2 * (piA_ * (piY_/piR_) * exp1_ - (piA_/piR_) * k2_2 * exp22_); //A
+				case 1 : return r_2 * (piC_ *             - exp1_);                               //C
+				case 2 : return r_2 * (piG_ * (piY_/piR_) * exp1_ + (piA_/piR_) * k2_2 * exp22_); //G
+				case 3 : return r_2 * (piT_ *             - exp1_);                               //T, U
+			}
+		}
+		//T, U
+		case 3 : {
+			switch(j) {
+				case 0 : return r_2 * (piA_ *             - exp1_);                               //A
+				case 1 : return r_2 * (piC_ * (piR_/piY_) * exp1_ - (piC_/piY_) * k1_2 * exp21_); //C
+				case 2 : return r_2 * (piG_ *             - exp1_);                               //G
+				case 3 : return r_2 * (piT_ * (piR_/piY_) * exp1_ + (piC_/piY_) * k1_2 * exp21_); //T, U
+			}
+		}
+	}
+	return 0;
+}
+
+/******************************************************************************/
+
+const Matrix<double> & TN93::getPij_t(double d) const
+{
+  l_ = rate_ * r_ * d;
+	exp1_ = exp(-l_);
+	exp22_ = exp(-k2_ * l_);
+	exp21_ = exp(-k1_ * l_);
+
+	//A
+	p_(0, 0) = piA_ * (1. + (piY_/piR_) * exp1_) + (piG_/piR_) * exp22_; //A
+	p_(0, 1) = piC_ * (1. -               exp1_);                        //C
+	p_(0, 2) = piG_ * (1. + (piY_/piR_) * exp1_) - (piG_/piR_) * exp22_; //G
+	p_(0, 3) = piT_ * (1. -               exp1_);                        //T, U
+
+	//C
+	p_(1, 0) = piA_ * (1. -               exp1_);                        //A
+	p_(1, 1) = piC_ * (1. + (piR_/piY_) * exp1_) + (piT_/piY_) * exp21_; //C
+	p_(1, 2) = piG_ * (1. -               exp1_);                        //G
+	p_(1, 3) = piT_ * (1. + (piR_/piY_) * exp1_) - (piT_/piY_) * exp21_; //T, U
+
+	//G
+	p_(2, 0) = piA_ * (1. + (piY_/piR_) * exp1_) - (piA_/piR_) * exp22_; //A
+	p_(2, 1) = piC_ * (1. -               exp1_);                        //C
+	p_(2, 2) = piG_ * (1. + (piY_/piR_) * exp1_) + (piA_/piR_) * exp22_; //G
+	p_(2, 3) = piT_ * (1. -               exp1_);                        //T, U
+
+	//T, U
+	p_(3, 0) = piA_ * (1. -               exp1_);                        //A
+	p_(3, 1) = piC_ * (1. + (piR_/piY_) * exp1_) - (piC_/piY_) * exp21_; //C
+	p_(3, 2) = piG_ * (1. -               exp1_);                        //G
+	p_(3, 3) = piT_ * (1. + (piR_/piY_) * exp1_) + (piC_/piY_) * exp21_; //T, U
+
+	return p_;
+}
+
+const Matrix<double> & TN93::getdPij_dt(double d) const
+{
+  l_ = rate_ * r_ * d;
+	exp1_ = exp(-l_);
+	exp22_ = exp(-k2_ * l_);
+	exp21_ = exp(-k1_ * l_);
+
+	//A
+	p_(0, 0) = rate_ * r_ * (piA_ * -(piY_/piR_) * exp1_ - (piG_/piR_) * k2_ * exp22_); //A
+	p_(0, 1) = rate_ * r_ * (piC_ *                exp1_);                              //C
+	p_(0, 2) = rate_ * r_ * (piG_ * -(piY_/piR_) * exp1_ + (piG_/piR_) * k2_ * exp22_); //G
+	p_(0, 3) = rate_ * r_ * (piT_ *                exp1_);                              //T, U
+
+	//C
+	p_(1, 0) = rate_ * r_ * (piA_ *                exp1_);                              //A
+	p_(1, 1) = rate_ * r_ * (piC_ * -(piR_/piY_) * exp1_ - (piT_/piY_) * k1_ * exp21_); //C
+	p_(1, 2) = rate_ * r_ * (piG_ *                exp1_);                              //G
+	p_(1, 3) = rate_ * r_ * (piT_ * -(piR_/piY_) * exp1_ + (piT_/piY_) * k1_ * exp21_); //T, U
+
+	//G
+	p_(2, 0) = rate_ * r_ * (piA_ * -(piY_/piR_) * exp1_ + (piA_/piR_) * k2_ * exp22_); //A
+	p_(2, 1) = rate_ * r_ * (piC_ *                exp1_);                              //C
+	p_(2, 2) = rate_ * r_ * (piG_ * -(piY_/piR_) * exp1_ - (piA_/piR_) * k2_ * exp22_); //G
+	p_(2, 3) = rate_ * r_ * (piT_ *                exp1_);                              //T, U
+
+	//T, U
+	p_(3, 0) = rate_ * r_ * (piA_ *                exp1_);                              //A
+	p_(3, 1) = rate_ * r_ * (piC_ * -(piR_/piY_) * exp1_ + (piC_/piY_) * k1_ * exp21_); //C
+	p_(3, 2) = rate_ * r_ * (piG_ *                exp1_);                              //G
+	p_(3, 3) = rate_ * r_ * (piT_ * -(piR_/piY_) * exp1_ - (piC_/piY_) * k1_ * exp21_); //T, U
+
+	return p_;
+}
+
+const Matrix<double> & TN93::getd2Pij_dt2(double d) const
+{
+  double r_2 = rate_ * rate_ * r_ * r_;
+  l_ = rate_ * r_ * d;
+	double k1_2 = k1_ * k1_;
+	double k2_2 = k2_ * k2_;
+	exp1_ = exp(-l_);
+	exp22_ = exp(-k2_ * l_);
+	exp21_ = exp(-k1_ * l_);
+
+	//A
+	p_(0, 0) = r_2 * (piA_ * (piY_/piR_) * exp1_ + (piG_/piR_) * k2_2 * exp22_); //A
+	p_(0, 1) = r_2 * (piC_ *             - exp1_);                               //C
+	p_(0, 2) = r_2 * (piG_ * (piY_/piR_) * exp1_ - (piG_/piR_) * k2_2 * exp22_); //G
+	p_(0, 3) = r_2 * (piT_ *             - exp1_);                               //T, U
+
+	//C
+	p_(1, 0) = r_2 * (piA_ *             - exp1_);                               //A
+	p_(1, 1) = r_2 * (piC_ * (piR_/piY_) * exp1_ + (piT_/piY_) * k1_2 * exp21_); //C
+	p_(1, 2) = r_2 * (piG_ *             - exp1_);                               //G
+	p_(1, 3) = r_2 * (piT_ * (piR_/piY_) * exp1_ - (piT_/piY_) * k1_2 * exp21_); //T, U
+
+	//G
+	p_(2, 0) = r_2 * (piA_ * (piY_/piR_) * exp1_ - (piA_/piR_) * k2_2 * exp22_); //A
+	p_(2, 1) = r_2 * (piC_ *             - exp1_);                               //C
+	p_(2, 2) = r_2 * (piG_ * (piY_/piR_) * exp1_ + (piA_/piR_) * k2_2 * exp22_); //G
+	p_(2, 3) = r_2 * (piT_ *             - exp1_);                               //T, U
+
+	//T, U
+	p_(3, 0) = r_2 * (piA_ *             - exp1_);                               //A
+	p_(3, 1) = r_2 * (piC_ * (piR_/piY_) * exp1_ - (piC_/piY_) * k1_2 * exp21_); //C
+	p_(3, 2) = r_2 * (piG_ *             - exp1_);                               //G
+	p_(3, 3) = r_2 * (piT_ * (piR_/piY_) * exp1_ + (piC_/piY_) * k1_2 * exp21_); //T, U
+
+	return p_;
+}
+
+/******************************************************************************/
+
+void TN93::setFreq(std::map<int, double>& freqs)
+{
+  piA_ = freqs[0];
+  piC_ = freqs[1];
+  piG_ = freqs[2];
+  piT_ = freqs[3];
+  vector<string> thetas(3);
+  thetas[0] = getNamespace() + "theta";
+  thetas[1] = getNamespace() + "theta1";
+  thetas[2] = getNamespace() + "theta2";
+  ParameterList pl = getParameters().subList(thetas);
+  pl[0].setValue(piC_ + piG_);
+  pl[1].setValue(piA_ / (piA_ + piT_));
+  pl[2].setValue(piG_ / (piC_ + piG_));
+  setParametersValues(pl);
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/TN93.h b/src/Bpp/Phyl/Model/Nucleotide/TN93.h
new file mode 100755
index 0000000..0f31570
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/TN93.h
@@ -0,0 +1,181 @@
+//
+// File: TN93.h
+// Created by: Julien Dutheil
+// Created on: Thu Jan 22 10:26:51 2004
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _TN93_H_
+#define _TN93_H_
+
+#include "NucleotideSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+
+#include <Bpp/Numeric/Constraints.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+#include <Bpp/Seq/Container/SequenceContainer.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The Tamura and Nei (1993) substitution model for nucleotides.
+ *
+ * This model has two rate of transitions and one rate of transversion.
+ * It also allows distinct equilibrium frequencies between A, C, G and T.
+ * This models hence includes six parameters, two transition / transversion
+ * relative rates \f$\kappa_1\f$ and \f$\kappa_2\f$, and four frequencies \f$\pi_A, \pi_C, \pi_G, \pi_T\f$.
+ * These four frequencies are not independent parameters, since they have the constraint to
+ * sum to 1. Usually, these parameters are measured from the data and not optimized.
+ * \f[
+ * S = \begin{pmatrix}
+ * \cdots & r & \kappa_1 r & r \\ 
+ * r & \cdots & r & \kappa_2 r \\ 
+ * \kappa_1 r & r & \cdots & r \\ 
+ * r & \kappa_2 r & r & \cdots \\ 
+ * \end{pmatrix}
+ * \f]
+ * \f[
+ * \pi = \left(\pi_A, \pi_C, \pi_G, \pi_T\right)
+ * \f]
+ * This models hence includes five parameters, two transition / transversion
+ * relative rates \f$\kappa_1, \kappa_2\f$ and four frequencies \f$\pi_A, \pi_C, \pi_G, \pi_T\f$.
+ * These four frequencies are not independent parameters, since they have the constraint to
+ * sum to 1.
+ * We use instead a different parametrization to remove this constraint:
+ * \f[
+ * \begin{cases}
+ * \theta = \pi_C + \pi_G\\
+ * \theta_1 = \frac{\pi_A}{1 - \theta} = \frac{\pi_A}{\pi_A + \pi_T}\\
+ * \theta_2 = \frac{\pi_G}{\theta} = \frac{\pi_G}{\pi_C + \pi_G}\\
+ * \end{cases}
+ * \Longleftrightarrow
+ * \begin{cases}
+ * \pi_A = \theta_1 (1 - \theta)\\
+ * \pi_C = (1 - \theta_2) \theta\\
+ * \pi_G = \theta_2 \theta\\
+ * \pi_T = (1 - \theta_1)(1 - \theta).
+ * \end{cases}
+ * \f]
+ * These parameters can also be measured from the data and not optimized.
+ *
+ * Normalization: \f$r\f$ is set so that \f$\sum_i Q_{i,i}\pi_i = -1\f$:
+ * \f[
+ * S = \frac{1}{P}\begin{pmatrix}
+ * \frac{-\pi_T-\kappa_1\pi_G-\pi_C}{\pi_A} & 1 & \kappa_1 & 1 \\ 
+ * 1 & \frac{-\kappa_2\pi_T-\pi_G-\pi_A}{\pi_C} & 1 & \kappa_2 \\ 
+ * \kappa_1 & 1 & \frac{-\pi_T-\pi_C-\kappa_1\pi_A}{\pi_G} & 1 \\ 
+ * 1 & \kappa_2 & 1 & \frac{-\pi_G-\kappa_2\pi_C-\pi_A}{\pi_T} \\ 
+ * \end{pmatrix}
+ * \f]
+ * with \f$P=2\left(\pi_A \pi_C + \pi_C \pi_G + \pi_A \pi_T + \pi_G \pi_T + \kappa_2 \pi_C \pi_T + \kappa_1 \pi_A \pi_G\right)\f$.
+ *
+ * The normalized generator is obtained by taking the dot product of \f$S\f$ and \f$\pi\f$:
+ * \f[
+ * Q = S . \pi = \frac{1}{P}\begin{pmatrix}
+ * -\pi_T-\kappa_1\pi_G-\pi_C & \pi_C & \kappa_1\pi_G & \pi_T \\ 
+ * \pi_A & -\kappa_2\pi_T-\pi_G-\pi_A & \pi_G & \kappa_2\pi_T \\ 
+ * \kappa_1\pi_A & \pi_C & -\pi_T-\pi_C-\kappa_1\pi_A & \pi_T \\ 
+ * \pi_A & \kappa_2\pi_C & \pi_G & -\pi_G-\kappa_2\pi_C-\pi_A \\ 
+ * \end{pmatrix}
+ * \f]
+ *
+ * For now, the generator of this model is diagonalized numericaly.
+ * See AbstractSubstitutionModel for details of how the porbabilities are computed.
+ *
+ * The parameters are named \c "kappa1", \c "kappa2", \c "theta", \c "theta1" and \c "theta2"
+ * and their values may be retrieve with the command 
+ * \code
+ * getParameterValue("kappa1")
+ * \endcode
+ * for instance.
+ *
+ * Reference:
+ * - Tamura N and Nei K (1993), Molecular_ Biology And Evolution_ 10(3) 512-26. 
+ */
+class TN93 :
+  public virtual NucleotideSubstitutionModel,
+  public AbstractReversibleSubstitutionModel
+{
+	private:
+    double kappa1_, kappa2_, piA_, piC_, piG_, piT_, piY_, piR_, r_, k1_, k2_, theta_, theta1_, theta2_;
+    mutable double exp1_, exp21_, exp22_, l_;
+    mutable RowMatrix<double> p_;
+
+	public:
+		TN93(
+			const NucleicAlphabet * alpha,
+			double kappa1 = 1.,
+			double kappa2 = 1.,
+			double piA = 0.25,
+			double piC = 0.25,
+			double piG = 0.25,
+			double piT = 0.25);
+	
+		virtual ~TN93() {}
+
+#ifndef NO_VIRTUAL_COV
+    TN93*
+#else
+    Clonable*
+#endif
+    clone() const { return new TN93(*this); }
+
+  public:
+
+		double Pij_t    (int i, int j, double d) const;
+		double dPij_dt  (int i, int j, double d) const;
+		double d2Pij_dt2(int i, int j, double d) const;
+		const Matrix<double>& getPij_t    (double d) const;
+		const Matrix<double>& getdPij_dt  (double d) const;
+		const Matrix<double>& getd2Pij_dt2(double d) const;
+
+    std::string getName() const { return "TN93"; }
+	
+  /**
+   * @brief This method is over-defined to actualize the corresponding parameters piA, piT, piG and piC too.
+   */
+  void setFreq(std::map<int, double>& freqs);
+
+  void updateMatrices();
+
+};
+
+} //end of namespace bpp.
+
+#endif	//_TN93_H_
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/YpR.cpp b/src/Bpp/Phyl/Model/Nucleotide/YpR.cpp
new file mode 100644
index 0000000..7ec134d
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/YpR.cpp
@@ -0,0 +1,468 @@
+//
+// File: YpR.cpp
+// Created by: Laurent Gueguen
+// Created on: Thu August 2 2007
+//
+
+/*
+   Copyright or � or Copr. CNRS, (November 16, 2004)
+   This software is a computer program whose purpose is to provide
+   classes for phylogenetic data analysis.
+
+   This software is governed by the CeCILL license under French law and
+   abiding by the rules of distribution of free software. You can use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and rights to copy,
+   modify and redistribute granted by the license, users are provided
+   only with a limited warranty and the software's author, the holder of
+   the economic rights, and the successive licensors have only limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading, using, modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean that it is complicated to manipulate, and that also
+   therefore means that it is reserved for developers and experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards
+   their requirements in conditions enabling the security of their
+   systems and/or data to be ensured and, more generally, to use and
+   operate it in the same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "YpR.h"
+
+// From the STL:
+#include <cmath>
+
+using namespace bpp;
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Matrix/EigenValue.h>
+
+#include <Bpp/Text/TextTools.h>
+
+/******************************************************************************/
+
+YpR::YpR(const RNY* alph, SubstitutionModel* const pm, const std::string& prefix) :
+  AbstractParameterAliasable(prefix),
+  AbstractSubstitutionModel(alph,prefix),
+  _pmodel(pm->clone()),
+  _nestedPrefix(pm->getNamespace())
+{
+  _pmodel->setNamespace(prefix + _nestedPrefix);
+  _pmodel->enableEigenDecomposition(0);
+  addParameters_(_pmodel->getParameters());
+}
+
+YpR::YpR(const YpR& ypr, const std::string& prefix) :
+  AbstractParameterAliasable(ypr),
+  AbstractSubstitutionModel(ypr),
+  _pmodel(ypr._pmodel->clone()),
+  _nestedPrefix(ypr.getNestedPrefix())
+
+{
+  _pmodel->setNamespace(prefix + _nestedPrefix);
+}
+
+YpR::YpR(const YpR& ypr) :
+  AbstractParameterAliasable(ypr),
+  AbstractSubstitutionModel(ypr),
+  _pmodel(ypr._pmodel->clone()),
+  _nestedPrefix(ypr.getNestedPrefix())
+{}
+
+void YpR::updateMatrices()
+{
+  updateMatrices(0, 0, 0, 0, 0, 0, 0, 0);
+}
+
+
+void YpR::updateMatrices(double CgT, double cGA,
+                         double TgC, double tGA,
+                         double CaT, double cAG,
+                         double TaC, double tAC)
+{
+  //  check_model(_pmodel);
+
+  // Generator:
+  const Alphabet* alph = _pmodel->getAlphabet();
+  std::vector<int> l(4);
+
+  l[0] = alph->charToInt("A");
+  l[1] = alph->charToInt("G");
+  l[2] = alph->charToInt("C");
+  l[3] = alph->charToInt("T");
+
+  unsigned int i,j,i1,i2,i3,j1,j2,j3;
+
+  std::vector<double> a(4);  // a[A], a[G], a[C], a[T]
+  std::vector<double> b(4);  // b[A], b[G], b[C], b[T]
+
+  for (i = 0; i < 2; i++)
+  {
+    a[i] = _pmodel->Qij(l[1 - i],l[i]);
+    b[i] = _pmodel->Qij(l[3 - i],l[i]);
+    a[i + 2] = _pmodel->Qij(l[3 - i],l[i + 2]);
+    b[i + 2] = _pmodel->Qij(l[1 - i],l[i + 2]);
+  }
+
+  // M_1
+  RowMatrix<double> M1(3,3);
+
+  M1(0,0) = 0;
+  M1(0,1) = b[2];
+  M1(0,2) = b[3];
+  M1(1,0) = b[0] + b[1];
+  M1(1,1) = 0;
+  M1(1,2) = a[3];
+  M1(2,0) = b[0] + b[1];
+  M1(2,1) = a[2];
+  M1(2,2) = 0;
+
+  // M_2
+  RowMatrix<double> M2(4,4);
+
+  M2(0,0) = 0;
+  M2(0,1) = a[1];
+  M2(0,2) = b[2];
+  M2(0,3) = b[3];
+  M2(1,0) = a[0];
+  M2(1,1) = 0;
+  M2(1,2) = b[2];
+  M2(1,3) = b[3];
+  M2(2,0) = b[0];
+  M2(2,1) = b[1];
+  M2(2,2) = 0;
+  M2(2,3) = a[3];
+  M2(3,0) = b[0];
+  M2(3,1) = b[1];
+  M2(3,2) = a[2];
+  M2(3,3) = 0;
+
+  // M_3
+  RowMatrix<double> M3(3,3);
+
+  M3(0,0) = 0;
+  M3(0,1) = a[1];
+  M3(0,2) = b[2] + b[3];
+  M3(1,0) = a[0];
+  M3(1,1) = 0;
+  M3(1,2) = b[2] + b[3];
+  M3(2,0) = b[0];
+  M3(2,1) = b[1];
+  M3(2,2) = 0;
+
+
+  for (i1 = 0; i1 < 3; i1++)
+  {
+    for (i2 = 0; i2 < 4; i2++)
+    {
+      for (i3 = 0; i3 < 3; i3++)
+      {
+        i = 12 * i1 + 3 * i2 + i3;
+        for (j1 = 0; j1 < 3; j1++)
+        {
+          for (j2 = 0; j2 < 4; j2++)
+          {
+            for (j3 = 0; j3 < 3; j3++)
+            {
+              j = 12 * j1 + 3 * j2 + j3;
+              if ((i1 == j1) && (i2 == j2))
+                generator_(i,j) = M3(i3,j3);
+              else if ((i1 == j1) && (i3 == j3))
+                generator_(i,j) = M2(i2,j2);
+              else if ((i2 == j2) && (i3 == j3))
+                generator_(i,j) = M1(i1,j1);
+              else
+                generator_(i,j) = 0;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // Introduction des dependances
+
+  for (i3 = 0; i3 < 3; i3++)
+  {
+    generator_(15 + i3,12 + i3) += cGA * a[0]; // CG -> CA
+    generator_(12 * i3 + 7,12 * i3 + 6) += cGA * a[0];
+
+    generator_(15 + i3,27 + i3) += CgT * a[3]; // CG -> TG
+    generator_(12 * i3 + 7,12 * i3 + 10) += CgT * a[3];
+
+    generator_(27 + i3,24 + i3) += tGA * a[0]; // TG -> TA
+    generator_(12 * i3 + 10,12 * i3 + 9) += tGA * a[0];
+
+    generator_(27 + i3,15 + i3) += TgC * a[2]; // TG -> CG
+    generator_(12 * i3 + 10,12 * i3 + 7) += TgC * a[2];
+
+    generator_(12 + i3,24 + i3) += CaT * a[3]; // CA -> TA
+    generator_(12 * i3 + 6,12 * i3 + 9) += CaT * a[3];
+
+    generator_(12 + i3,15 + i3) += cAG * a[1]; // CA -> CG
+    generator_(12 * i3 + 6,12 * i3 + 7) += cAG * a[1];
+
+    generator_(24 + i3,27 + i3) += tAC * a[1]; // TA -> TG
+    generator_(12 * i3 + 9,12 * i3 + 10) += tAC * a[1];
+
+    generator_(24 + i3,12 + i3) += TaC * a[2]; // TA -> CA
+    generator_(12 * i3 + 9,12 * i3 + 6) += TaC * a[2];
+  }
+
+  double x;
+
+  for (i = 0; i < 36; i++)
+  {
+    x = 0;
+    for (j = 0; j < 36; j++)
+    {
+      if (j != i)
+        x += generator_(i,j);
+    }
+    generator_(i,i) = -x;
+  }
+
+  // calcul spectral
+
+  EigenValue<double> ev(generator_);
+  eigenValues_ = ev.getRealEigenValues();
+  iEigenValues_ = ev.getImagEigenValues();
+
+  rightEigenVectors_ = ev.getV();
+
+   try {
+     MatrixTools::inv(rightEigenVectors_,leftEigenVectors_);
+
+     isNonSingular_=true;
+     isDiagonalizable_=true;
+     for (i=0; i<size_; i++)
+       if (abs(iEigenValues_[i])> NumConstants::TINY()){
+         isDiagonalizable_=false;
+       }
+
+     // frequence stationnaire
+    
+     x = 0;
+     j = 0;
+     while (j < 36){
+       if (abs(eigenValues_[j]) < NumConstants::SMALL() &&
+           abs(iEigenValues_[j]) < NumConstants::SMALL()) {
+         eigenValues_[j]=0; //to avoid approximation problems in the future
+         for (i = 0; i < 36; i++)
+           {
+             freq_[i] = leftEigenVectors_(j,i);
+             x += freq_[i];
+           }
+         break;
+       }
+       j++;
+     }
+     for (i = 0; i < 36; i++)
+       freq_[i] /= x;
+   }
+   catch (ZeroDivisionException& e){
+     ApplicationTools::displayMessage("Singularity during  diagonalization. Taylor series used instead.");
+     isNonSingular_=false;
+     isDiagonalizable_=false;
+
+     if (vPowGen_.size()==0)
+       vPowGen_.resize(30);
+
+     double min=generator_(0,0);
+     for (i = 1; i < 36; i++)
+       if (min>generator_(i,i))
+         min=generator_(i,i);
+     
+     MatrixTools::scale(generator_,-1/min);
+     
+     MatrixTools::getId(36,tmpMat_);    // to compute the equilibrium frequency  (Q+Id)^256
+     
+     MatrixTools::add(tmpMat_,generator_);
+     MatrixTools::pow(tmpMat_,256,vPowGen_[0]);
+     
+     for (i=0;i<36;i++)
+       freq_[i]=vPowGen_[0](0,i);
+     
+     MatrixTools::getId(36,vPowGen_[0]);
+   }
+  
+  // mise a l'echelle
+
+  x = 0;
+  for (i1 = 0; i1 < 3; i1++)
+  {
+    for (i2 = 0; i2 < 4; i2++)
+    {
+      for (i3 = 0; i3 < 3; i3++)
+      {
+        i = 12 * i1 + 3 * i2 + i3;
+        for (j2 = 0; j2 < 4; j2++)
+        {
+          if (j2 != i2)
+          {
+            j = 12 * i1 + 3 * j2 + i3;
+            x += freq_[i] * generator_(i,j);
+          }
+        }
+      }
+    }
+  }
+
+  MatrixTools::scale(generator_,1 / x);
+
+  if (!isNonSingular_)
+    MatrixTools::Taylor(generator_,30,vPowGen_);
+
+  for (i = 0; i < 36; i++){
+    eigenValues_[i] /= x;
+    iEigenValues_[i] /= x;
+  }
+
+  // and the exchangeability_
+  for ( i = 0; i < size_; i++)
+    for ( j = 0; j < size_; j++)
+      exchangeability_(i,j) = generator_(i,j) / freq_[j];
+
+}
+
+void YpR::check_model(SubstitutionModel* const pm) const
+throw (Exception)
+{
+  if (!pm)
+    throw Exception("No Model ");
+
+  const Alphabet* alph = pm->getAlphabet();
+  if (alph->getAlphabetType() != "DNA alphabet")
+    throw Exception("Need a DNA model");
+
+  std::vector<int> l(4);
+
+  l[0] = alph->charToInt("A");
+  l[1] = alph->charToInt("G");
+  l[2] = alph->charToInt("C");
+  l[3] = alph->charToInt("T");
+
+  // Check that the model is good for YpR
+
+  int i;
+
+  for (i = 0; i < 2; i++)
+  {
+    if (pm->Qij(l[2],l[i]) != pm->Qij(l[3],l[i]))
+      throw Exception("Not R/Y Model " + pm->getName());
+  }
+  for (i = 2; i < 4; i++)
+  {
+    if (pm->Qij(l[0],l[i]) != pm->Qij(l[1],l[i]))
+      throw Exception("Not R/Y Model " + pm->getName());
+  }
+}
+
+void YpR::setNamespace(const std::string& prefix)
+{
+   AbstractSubstitutionModel::setNamespace(prefix);
+  // We also need to update the namespace of the nested model:
+  _pmodel->setNamespace(prefix + _nestedPrefix);
+}
+
+// ///////////////////////////////////////////////
+// ///////////////////////////////////////////////
+
+
+/******************************************************************************/
+
+YpR_Sym::YpR_Sym(const RNY* alph,
+                 SubstitutionModel* const pm,
+                 double CgT, double TgC,
+                 double CaT, double TaC) : AbstractParameterAliasable("YpR_Sym."), YpR(alph, pm,"YpR_Sym.")
+{
+  addParameter_(new Parameter("YpR_Sym.rCgT", CgT, &Parameter::R_PLUS));
+  addParameter_(new Parameter("YpR_Sym.rTgC", TgC, &Parameter::R_PLUS));
+  addParameter_(new Parameter("YpR_Sym.rCaT", CaT, &Parameter::R_PLUS));
+  addParameter_(new Parameter("YpR_Sym.rTaC", TaC, &Parameter::R_PLUS));
+
+  updateMatrices();
+}
+
+void YpR_Sym::updateMatrices()
+{
+   double rCgT = getParameterValue("rCgT");
+   double rTgC = getParameterValue("rTgC");
+   double rCaT = getParameterValue("rCaT");
+   double rTaC = getParameterValue("rTaC");
+
+   YpR::updateMatrices(rCgT, rCgT, rTgC, rTgC, rCaT, rCaT, rTaC, rTaC);
+}
+
+YpR_Sym::YpR_Sym(const YpR_Sym& ypr) : AbstractParameterAliasable(ypr), YpR(ypr,"YpR_Sym.")
+{}
+
+/******************************************************************************/
+
+std::string YpR_Sym::getName() const
+{
+  return "YpR_Sym";
+}
+
+
+// ///////////////////////////////////////////////
+// ///////////////////////////////////////////////
+
+/******************************************************************************/
+
+YpR_Gen::YpR_Gen(const RNY* alph,
+                 SubstitutionModel* const pm,
+                 double CgT, double cGA,
+                 double TgC, double tGA,
+                 double CaT, double cAG,
+                 double TaC, double tAG) : AbstractParameterAliasable("YpR_Gen."), YpR(alph, pm,"YpR_Gen.")
+{
+  addParameter_(new Parameter("YpR_Gen.rCgT", CgT, &Parameter::R_PLUS));
+  addParameter_(new Parameter("YpR_Gen.rcGA", cGA, &Parameter::R_PLUS));
+  addParameter_(new Parameter("YpR_Gen.rTgC", TgC, &Parameter::R_PLUS));
+  addParameter_(new Parameter("YpR_Gen.rtGA", tGA, &Parameter::R_PLUS));
+  addParameter_(new Parameter("YpR_Gen.rCaT", CaT, &Parameter::R_PLUS));
+  addParameter_(new Parameter("YpR_Gen.rcAG", cAG, &Parameter::R_PLUS));
+  addParameter_(new Parameter("YpR_Gen.rTaC", TaC, &Parameter::R_PLUS));
+  addParameter_(new Parameter("YpR_Gen.rtAG", tAG, &Parameter::R_PLUS));
+
+  updateMatrices();
+}
+
+void YpR_Gen::updateMatrices()
+{
+   double rCgT = getParameterValue("rCgT");
+   double rcGA = getParameterValue("rcGA");
+   double rTgC = getParameterValue("rTgC");
+   double rtGA = getParameterValue("rtGA");
+   double rCaT = getParameterValue("rCaT");
+   double rcAG = getParameterValue("rcAG");
+   double rTaC = getParameterValue("rTaC");
+   double rtAG = getParameterValue("rtAG");
+
+   YpR::updateMatrices(rCgT, rcGA, rTgC, rtGA, rCaT, rcAG, rTaC, rtAG);
+}
+
+YpR_Gen::YpR_Gen(const YpR_Gen& ypr) : AbstractParameterAliasable(ypr), YpR(ypr,"YpR_Gen.")
+{
+  updateMatrices();
+}
+
+/******************************************************************************/
+
+std::string YpR_Gen::getName() const
+{
+  return "YpR_Gen";
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/YpR.h b/src/Bpp/Phyl/Model/Nucleotide/YpR.h
new file mode 100644
index 0000000..3e39ab6
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/YpR.h
@@ -0,0 +1,290 @@
+//
+// File: YpR.h
+// Created by: Laurent Gueguen
+// Created on: Wed Aug 3 2007
+//
+
+/*
+   Copyright or � or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _YpR_H_
+#define _YpR_H_
+
+#include "../AbstractSubstitutionModel.h"
+
+#include <Bpp/Seq/Alphabet/RNY.h>
+
+
+// From Utils:
+#include <Bpp/Exceptions.h>
+
+using namespace std;
+
+namespace bpp
+{
+/**
+ * @brief YpR  model.
+ * @author Laurent Gu�guen
+ *
+ * Model YpR, on RNY triplets, with independent positions.
+ *
+ * This model is made from neighbourhood parameters and
+ * a nucleotidic probabilistic model such that the R/Y
+ * condition is respected : with letters A, T, C, G
+ * @f[
+ * M=\begin{pmatrix}
+ * . & \beta_T & \beta_C & \alpha_G \\
+ * \beta_A & . & \alpha_C & \beta_G \\
+ * \beta_A & \alpha_T & . & \beta_G \\
+ * \alpha_A & \beta_T & \beta_C & .
+ * \end{pmatrix}
+ * @f]
+ *
+ * From this model, the rates are a multiplication of the rates for the
+ * letters of the triplet.
+ * For the first letter, on alphabet R, C, T:
+ * @f[
+ * M_1=\begin{pmatrix}
+ * . & \beta_C & \beta_T \\
+ * \beta_A + \beta_G & . & \alpha_T \\
+ * \beta_A + \beta_G & \alpha_C & .
+ * \end{pmatrix}
+ * @f]
+ * For the second letter, on alphabet A, G, C, T:
+ * @f[
+ * M_2=\begin{pmatrix}
+ * . & \alpha_G & \beta_C & \beta_T \\
+ * \alpha_A & . & \beta_C & \beta_T \\
+ * \beta_A & \beta_G & . & \alpha_T \\
+ * \beta_A & \beta_G & \alpha_C & .
+ * \end{pmatrix}
+ * @f]
+ * For the third letter, on alphabet A, G, Y:
+ * @f[
+ * M_3 = \begin{pmatrix}
+ * . & \alpha_G & \beta_C + \beta_T\\
+ * \alpha_A & . & \beta_C + \beta_T\\
+ * \beta_A & \beta_G & .
+ * \end{pmatrix}.
+ * @f]
+ * And the model is the "union" of the 3 matrices, since in the
+ * model  only the mutations concerning only one position  are
+ * not null.
+ * In addition to this, neighbour dependency parameters
+ * (in inherited models) give the extra mutation rates for transitions
+ * inside YpR dinucleotides.
+ * For example from CpG to CpA and TpG, in relative proportion
+ * to the single transition rate:
+ *  CGx -> CAx   += rcGA*G->A
+ *  CGx -> TGx   += rCgT*C->T
+ *  xCG -> xCA   += rcGA*G->A
+ *  xCG -> xTG   += rCgT*C->T
+ *
+ * Other YpR neighbour dependency rates are:
+ *   TG -> CG, TG -> TA, CA -> TA, CA -> CG, TA -> CA, TA -> TC
+ *
+ * The generator in normalized such that there is on average
+ *  a substitution per site per unit of time ON THE CENTRAL POSITION
+ *  of the triplet.
+ * @see AbstractSubstitutionModel
+ *
+ */
+
+class YpR :
+  public AbstractSubstitutionModel
+{
+protected:
+  SubstitutionModel*  _pmodel;
+
+  // Check that the model is good for YpR
+  void check_model(SubstitutionModel* const) const
+  throw (Exception);
+
+  std::string _nestedPrefix;
+
+protected:
+  /**
+   * @brief Build a new YpR substitution model, with no dependency
+   *   parameters
+   */
+
+  YpR(const RNY*, SubstitutionModel* const, const std::string& prefix);
+
+  YpR(const YpR&, const std::string& prefix);
+
+  YpR(const YpR& ypr);
+
+  YpR& operator=(const YpR& ypr)
+  {
+    AbstractParameterAliasable::operator=(ypr);
+    AbstractSubstitutionModel::operator=(ypr);
+    _nestedPrefix = ypr._nestedPrefix;
+    _pmodel = ypr._pmodel->clone();
+    return *this;
+  }
+
+public:
+  virtual ~YpR()
+  {
+    if (_pmodel)
+      delete _pmodel;
+    _pmodel = 0;
+  }
+
+protected:
+  void updateMatrices(double, double, double, double,
+                      double, double, double, double);
+
+  string getNestedPrefix() const
+  {
+    return _nestedPrefix;
+  }
+
+public:
+  //  virtual std::string getName() const;
+
+  const SubstitutionModel* getNestedModel() const {return _pmodel;}
+  
+  size_t getNumberOfStates() const { return 36; }
+
+  virtual void updateMatrices();
+
+  virtual void setNamespace(const std::string&);
+
+  void fireParameterChanged(const ParameterList& parameters)
+  {
+    AbstractSubstitutionModel::fireParameterChanged(parameters);
+   _pmodel->matchParametersValues(parameters);
+   updateMatrices();
+  }
+};
+}
+
+
+// //////////////////////////////////////
+// //////// YpR_symetrical
+
+namespace bpp
+{
+/**
+ * @brief symetrical YpR  model.
+ *
+ * Model YpR, on RNY triplets with symetrical dependency parameters
+ *
+ * The neighbour dependency parameters are noted as: XyZ for
+ *  XpY -> ZpY substitution. Since the process are symetrical,
+ *  only these are necessary.
+ * @see YpR
+ *
+ */
+
+class YpR_Sym :
+  public YpR
+{
+public:
+  /**
+   * @brief Build a new YpR_Sym substitution model.
+   * @param CgT, TgC, CaT, TaC neighbour dependency parameters
+   * @param alph RNY alphabet
+   * @param pm Substitution model.
+   */
+
+  YpR_Sym(const RNY* alph,
+          SubstitutionModel* pm,
+          double CgT = 0., double TgC = 0.,
+          double CaT = 0., double TaC = 0.);
+
+  YpR_Sym(const YpR_Sym&);
+
+  virtual ~YpR_Sym() {}
+
+  YpR_Sym* clone() const { return new YpR_Sym(*this); }
+
+  std::string getName() const;
+
+  void updateMatrices();
+};
+}
+
+// //////////////////////////////////////
+// //////// YpR_general
+
+namespace bpp
+{
+/**
+ * @brief General YpR  model.
+ *
+ * Model YpR, on RNY triplets with general dependency parameters
+ *
+ * The neighbour dependency parameters are noted as: XyZ for
+ *  XpY -> ZpY substitution and xYZ for XpY -> XpZ substitution.
+ *
+ * @see YpR
+ *
+ */
+
+class YpR_Gen :
+  public YpR
+{
+public:
+  /**
+   * @brief Build a new YpR_Gen substitution model.
+   * @param CgT, cGA, TgC, tGA, CaT, cAG, TaC, tAG neighbour
+   * dependency parameters
+   * @param alph RNY alphabet
+   * @param pm Substitution model.
+   */
+
+  YpR_Gen(const RNY* alph,
+          SubstitutionModel* pm,
+          double CgT = 0., double cGA = 0.,
+          double TgC = 0., double tGA = 0.,
+          double CaT = 0., double cAG = 0.,
+          double TaC = 0., double tAG = 0.);
+
+  YpR_Gen(const YpR_Gen&);
+
+  virtual ~YpR_Gen() {}
+
+  YpR_Gen* clone() const { return new YpR_Gen(*this); }
+
+  std::string getName() const;
+
+  void updateMatrices();
+};
+}
+
+
+#endif // _YpR_H_
+
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/gBGC.cpp b/src/Bpp/Phyl/Model/Nucleotide/gBGC.cpp
new file mode 100644
index 0000000..2eca8c9
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/gBGC.cpp
@@ -0,0 +1,178 @@
+//
+// File: gBGC.cpp
+// Created by: Laurent Gueguen
+// Created on: lundi 13 f�vrier 2012, � 09h 42
+//
+
+/*
+   Copyright or � or Copr. CNRS, (November 16, 2004)
+   This software is a computer program whose purpose is to provide
+   classes for phylogenetic data analysis.
+
+   This software is governed by the CeCILL license under French law and
+   abiding by the rules of distribution of free software. You can use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and rights to copy,
+   modify and redistribute granted by the license, users are provided
+   only with a limited warranty and the software's author, the holder of
+   the economic rights, and the successive licensors have only limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading, using, modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean that it is complicated to manipulate, and that also
+   therefore means that it is reserved for developers and experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards
+   their requirements in conditions enabling the security of their
+   systems and/or data to be ensured and, more generally, to use and
+   operate it in the same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "gBGC.h"
+
+// From the STL:
+#include <cmath>
+
+using namespace bpp;
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Matrix/EigenValue.h>
+
+/******************************************************************************/
+
+gBGC::gBGC(const NucleicAlphabet* alph, NucleotideSubstitutionModel* const pm, double gamma) :
+  AbstractParameterAliasable("gBGC."),
+  AbstractSubstitutionModel(alph,"gBGC."),
+  pmodel_(pm->clone()),
+  nestedPrefix_(pm->getNamespace()),
+  gamma_(gamma)
+{
+  pmodel_->setNamespace("gBGC."+nestedPrefix_);
+  pmodel_->enableEigenDecomposition(0);
+  addParameters_(pmodel_->getParameters());
+  addParameter_(new Parameter("gBGC.gamma", gamma_,new IntervalConstraint(-999, 10, true, true), true));
+
+  updateMatrices();
+}
+
+gBGC::gBGC(const gBGC& gbgc) :
+  AbstractParameterAliasable(gbgc),
+  AbstractSubstitutionModel(gbgc),
+  pmodel_(gbgc.pmodel_->clone()),
+  nestedPrefix_(gbgc.nestedPrefix_),
+  gamma_(gbgc.gamma_)
+{
+}
+
+gBGC& gBGC::operator=(const gBGC& gbgc)
+{
+  AbstractParameterAliasable::operator=(gbgc);
+  AbstractSubstitutionModel::operator=(gbgc);
+  pmodel_ = gbgc.pmodel_->clone();
+  nestedPrefix_ = gbgc.nestedPrefix_;
+  gamma_=gbgc.gamma_;
+  return *this;
+}
+
+void gBGC::fireParameterChanged(const ParameterList& parameters)
+{
+  pmodel_->matchParametersValues(parameters);
+  AbstractSubstitutionModel::matchParametersValues(parameters);
+  updateMatrices();
+}
+
+void gBGC::updateMatrices()
+{
+  gamma_=getParameterValue("gamma");
+  unsigned int i,j;
+  // Generator:
+  double eg=exp(gamma_);
+  for ( i = 0; i < 4; i++)
+    for ( j = 0; j < 4; j++)
+      generator_(i,j)=pmodel_->Qij(i,j);
+
+  generator_(0,1) *= eg;
+  generator_(0,2) *= eg;
+  generator_(3,1) *= eg;
+  generator_(3,2) *= eg;
+
+  generator_(0,0) -= (generator_(0,1)+generator_(0,2))*(1-1/eg);
+  generator_(3,3) -= (generator_(3,1)+generator_(3,2))*(1-1/eg);
+
+  // calcul spectral
+
+  EigenValue<double> ev(generator_);
+  eigenValues_ = ev.getRealEigenValues();
+  
+  rightEigenVectors_ = ev.getV();
+  MatrixTools::inv(rightEigenVectors_,leftEigenVectors_);
+
+  iEigenValues_ = ev.getImagEigenValues();
+
+  // frequence stationnaire
+  double x = 0;
+  j = 0;
+  while (j < 4){
+    if (abs(eigenValues_[j]) < 0.000001 && abs(iEigenValues_[j]) < 0.000001) {
+      eigenValues_[j]=0; //to avoid approximation problems in the future
+      iEigenValues_[j]=0; //to avoid approximation problems in the future
+      for (i = 0; i < 4; i++)
+        {
+          freq_[i] = leftEigenVectors_(j,i);
+          x += freq_[i];
+        }
+      break;
+    }
+    j++;
+  }
+
+  for (i = 0; i < 4; i++)
+    freq_[i] /= x;
+
+  // mise a l'echelle
+
+  x = 0;
+  for (i = 0; i < 4; i++)
+    x += freq_[i] * generator_(i,i);
+
+  MatrixTools::scale(generator_,-1 / x);
+
+  for (i = 0; i < 4; i++)
+    eigenValues_[i] /= -x;
+  
+  isDiagonalizable_=true;
+  for (i = 0; i < size_ && isDiagonalizable_; i++)
+    if (abs(iEigenValues_[i])> NumConstants::SMALL()){
+      isDiagonalizable_=false;
+      break;
+    }
+
+  // and the exchangeability_
+  for ( i = 0; i < size_; i++)
+    for ( j = 0; j < size_; j++)
+      exchangeability_(i,j) = generator_(i,j) / freq_[j];
+
+}
+
+void gBGC::setNamespace(const std::string& prefix)
+{
+  AbstractSubstitutionModel::setNamespace(prefix);
+  // We also need to update the namespace of the nested model:
+  pmodel_->setNamespace(prefix + nestedPrefix_);
+}
+
+
+std::string gBGC::getName() const
+{
+  return "gBGC(model=" + pmodel_->getName()+")";
+}
+
diff --git a/src/Bpp/Phyl/Model/Nucleotide/gBGC.h b/src/Bpp/Phyl/Model/Nucleotide/gBGC.h
new file mode 100644
index 0000000..d8448b4
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Nucleotide/gBGC.h
@@ -0,0 +1,131 @@
+//
+// File: gBGC.h
+// Created by: Laurent Gueguen
+// Created on: lundi 13 f�vrier 2012, � 09h 43
+//
+
+/*
+   Copyright or � or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _GBGC_H_
+#define _GBGC_H_
+
+#include "NucleotideSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+
+#include <Bpp/Numeric/Constraints.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+
+// From Utils:
+
+using namespace std;
+
+namespace bpp
+{
+/**
+ * @brief gBGC  model.
+ * @author Laurent Gu�guen
+ *
+ * modelling of GC biased gene-conversion.
+ *
+ * This model adds strand symetric GC biased gene conversion to a
+ * given nucleotidic substitution model.
+ *
+ * In addition to the parameters of the basic nucleic model, the
+ * biased gene conversion effect is parametrized by @f$ \gamma @f$
+ * (denoted \c "gamma"), and the mutation rates from A<->T nucleotides
+ * to C<->G nucleotides are multiplied by @f$ exp(\gamma)@f$.
+ *
+ * @see AbstractSubstitutionModel
+ *
+ */
+
+class gBGC :
+    public virtual NucleotideSubstitutionModel,
+    public AbstractSubstitutionModel
+{
+private:
+  NucleotideSubstitutionModel*  pmodel_;
+  std::string nestedPrefix_;
+
+  /*
+   * @brief the value of the bias.
+   *
+   */
+  
+  double gamma_;
+  
+public:
+  /*
+   * @brief Build a new YpR substitution model, with no dependency
+   *   parameters
+   */
+
+  gBGC(const NucleicAlphabet*, NucleotideSubstitutionModel* const, double gamma=0);
+
+  gBGC(const gBGC&);
+
+  gBGC& operator=(const gBGC& gbgc);
+
+#ifndef NOVIRTUAL_COV_
+  gBGC*
+#else
+  Clonable*
+#endif
+  clone() const { return new gBGC(*this); }
+
+  ~gBGC()
+  {
+    if (pmodel_)
+      delete pmodel_;
+    pmodel_ = 0;
+  }
+
+public:
+  std::string getName() const;
+
+  size_t getNumberOfStates() const { return pmodel_->getNumberOfStates(); }
+
+  void fireParameterChanged(const ParameterList&);
+
+  void updateMatrices();
+
+  void setNamespace(const std::string&);
+};
+}
+
+#endif // _GBGC_H
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/Coala.cpp b/src/Bpp/Phyl/Model/Protein/Coala.cpp
new file mode 100644
index 0000000..a44b77b
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/Coala.cpp
@@ -0,0 +1,223 @@
+//
+// File: Coala.cpp
+// Created by: Mathieu Groussin
+// Created on: Sun Mar 13 12:00:00 2011
+//
+
+/*
+   Copyright or � or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+
+#include "Coala.h"
+
+#include <Bpp/Io/FileTools.h>
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Text/StringTokenizer.h>
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Numeric/Stat/Mva/CorrespondenceAnalysis.h>
+
+#include <Bpp/Seq/SequenceTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+#include <fstream>
+#include <string>
+
+using namespace std;
+
+
+/******************************************************************************/
+
+Coala::Coala(
+  const ProteicAlphabet* alpha,
+  unsigned int nbAxes,
+  string exch,
+  string file) :
+  AbstractParameterAliasable("Coala."),
+  AbstractSubstitutionModel(alpha, "Coala."),
+  ProteinSubstitutionModel(),
+  AbstractReversibleSubstitutionModel(alpha, "Coala."),
+  CoalaCore(nbAxes, exch),
+  init_(true),
+  nbrOfAxes_(nbAxes),
+  exch_(exch),
+  file_(file)
+{
+  setNamespace(getName() + ".");
+
+  // Setting the exchangeability matrix
+  if (exch == "JC69")
+  {
+    for (unsigned int i = 0; i < 20; i++)
+    {
+      for (unsigned int j = 0; j < 20; j++)
+      {
+        generator_(i, j) = (i == j) ? -1. : 1. / 19.;
+        exchangeability_(i, j) = generator_(i, j) * 20.;
+      }
+    }
+  }
+  else if (exch == "DSO78")
+  {
+#include "__DSO78ExchangeabilityCode"
+  }
+  else if (exch == "JTT92")
+  {
+#include "__JTT92ExchangeabilityCode"
+  }
+  else if (exch == "WAG01")
+  {
+#include "__WAG01ExchangeabilityCode"
+  }
+  else if (exch == "LG08")
+  {
+#include "__LG08ExchangeabilityCode"
+  }
+  else if (exch == "Empirical")
+  {
+    readFromFile(file_);
+  }
+  else
+  {
+    throw Exception("Model '" + exch + "' unknown.");
+  }
+  updateMatrices();
+}
+
+/******************************************************************************/
+
+void Coala::readFromFile(string& file)
+{
+  ifstream in(file.c_str(), ios::in);
+  // Read exchangeability matrix:
+  for (unsigned int i = 1; i < 20; i++)
+  {
+    string line = FileTools::getNextLine(in);
+    StringTokenizer st(line);
+    for (unsigned int j = 0; j < i; j++)
+    {
+      double s = TextTools::toDouble(st.nextToken());
+      exchangeability_(i, j) = exchangeability_(j, i) = s;
+    }
+  }
+
+  // Now build diagonal of the exchangeability matrix:
+  for (unsigned int i = 0; i < 20; i++)
+  {
+    double sum = 0;
+    for (unsigned int j = 0; j < 20; j++)
+    {
+      if (j != i)
+        sum += exchangeability_(i, j);
+    }
+    exchangeability_(i, i) = -sum;
+  }
+
+  // Closing stream:
+  in.close();
+}
+
+
+/******************************************************************************/
+void Coala::computeEquilibriumFrequencies()
+{
+  // Computes the equilibrium frequencies from a set of coordinates along the principal axes of the COA.
+  if (init_)
+    init_ = false;
+  else
+  {
+    // We get the coordinates:
+    vector<double> coord;
+    for (unsigned int i = 0; i < nbrOfAxes_; i++)
+    {
+      coord.push_back(getParameter("AxPos" + TextTools::toString(i)).getValue());
+    }
+
+    // Now, frequencies are computed from the vector of coordinates and the transpose of the principal axes matrix (P_):
+    vector<double> tmpFreqs;
+    tmpFreqs = prodMatrixVector(P_, coord);
+    for (unsigned int i = 0; i < tmpFreqs.size(); i++)
+    {
+      tmpFreqs[i] = (tmpFreqs[i] + 1) * colWeights_[i];
+    }
+    freq_ = tmpFreqs;
+
+    // Frequencies are not allowed to be lower than 10^-3 or higher than 0.5:
+    bool norm = false;
+    for (unsigned int i = 0; i < 20; i++)
+    {
+      if (freq_[i] < 0.001)
+      {
+        norm = true;
+        freq_[i] = 0.001;
+      }
+      if (freq_[i] > 0.2)
+      {
+        norm = true;
+        freq_[i] = 0.2;
+      }
+    }
+    if (norm == true)
+    {
+      double s = VectorTools::sum(freq_);
+      for (int i = 0; i < 20; i++)
+      {
+        freq_[i] = freq_[i] / s;
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+
+void Coala::updateMatrices()
+{
+  computeEquilibriumFrequencies();
+  AbstractReversibleSubstitutionModel::updateMatrices();
+}
+
+/******************************************************************************/
+
+void Coala::setFreqFromData(const SequenceContainer& data, bool param)
+{
+  // Compute the COA from the observed frequencies, add the axis position parameters and update the Markov matrix
+  ParameterList pList = computeCOA(data, param);
+  addParameters_(pList);
+  updateMatrices();
+}
+
+/******************************************************************************/
diff --git a/src/Bpp/Phyl/Model/Protein/Coala.h b/src/Bpp/Phyl/Model/Protein/Coala.h
new file mode 100644
index 0000000..4ed61d7
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/Coala.h
@@ -0,0 +1,113 @@
+//
+// File: Coala.h
+// Created by: Bastien Boussau
+// Created on: Tue May 18 15:23:20 2010
+// Modified by: Mathieu Groussin
+// Modified on: Sun Mar 13 12:00:00 2011
+//
+
+/*
+   Copyright or � or Copr. CNRS, (November 16, 2004)
+   PCA
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+
+#ifndef _COALA_H_
+#define _COALA_H_
+
+#include "ProteinSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+#include "CoalaCore.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/ProteicAlphabet.h>
+
+using namespace std;
+
+
+namespace bpp
+{
+/**
+ * @brief The Coala branch-heterogeneous amino-acid substitution model.
+ *
+ * This branch-heterogeneous model allows each branch to have its own set of amino acid equilibrium frequencies. It makes use of a Correspondence Analysis to reduce the number of parameters to be
+ * optimized through Maximum Likelihood, focusing on most of the compositional variation observed in the data. The same COA is used for all branches.
+ * An empirical exchangeability matrix is used, common to all branches. The choice of this matrix is up to the user. A user-defined empirical matrix can also be employed.
+ * The model may also be used as a branch-homogeneous but non-stationary model, where the same estimated equilibrium frequencies are used for all branches, but different equilibrium frequencies
+ * (that are optimized) are used on the root. Finally, the model may be employed as a branch-homogeneous and stationary model, where the frequencies at the root are similar to the ones on branches.
+ *
+ * @author Mathieu Groussin
+ * @param alpha The alphabet (Protein)
+ * @param nbAxes The number of principal axes of the COA that have to be taken into account to optimize the 20 branch-specific equilibrium frequencies. This number is common to all branches, as
+ * well as on the root, where frequencies are optimized with a MVAprotein object (See the ProteinFrequenciesSet class).
+ * @param exch The exchangeability matrix. The matrices currently available are DSO78, JTT92, WAG01 or LG08. A user-defined matrix can be specified with the 'file' argument.
+ * @param file [optional] Used only to specify the file containing the user-defined exchangeabilities, written in PAML format.
+ */
+
+class Coala :
+  public ProteinSubstitutionModel,
+  public AbstractReversibleSubstitutionModel,
+  public CoalaCore
+{
+protected:
+  bool init_;
+  unsigned int nbrOfAxes_;
+  string exch_;
+  string file_;
+
+public:
+  Coala(const ProteicAlphabet* alpha,
+        unsigned int nbAxes = 0,
+        const string exch = "LG08",
+        string file = "");
+
+  virtual ~Coala() {}
+
+#ifndef NO_VIRTUAL_COV
+  Coala*
+#else
+  Clonable*
+#endif
+  clone() const { return new Coala(*this); }
+
+public:
+  string getName() const {return "Coala"; }
+  string getExch() const {return exch_; }
+  void setFreqFromData(const SequenceContainer& data, bool param = true);
+  string getEmpiricalMatrixFile() const {return file_; }
+
+protected:
+  void readFromFile(string& file);
+  void computeEquilibriumFrequencies();
+  void updateMatrices();
+};
+} // end of namespace bpp.
+#endif  // _COALA_H_
diff --git a/src/Bpp/Phyl/Model/Protein/CoalaCore.cpp b/src/Bpp/Phyl/Model/Protein/CoalaCore.cpp
new file mode 100644
index 0000000..dd06dff
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/CoalaCore.cpp
@@ -0,0 +1,190 @@
+//
+// File: CoalaCore.cpp
+// Created by: Mathieu Groussin
+// Created on: Sun Mar 13 12:00:00 2011
+//
+
+/*
+   Copyright or � or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+
+#include "CoalaCore.h"
+
+// #include <Bpp/Io/FileTools.h>
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Text/StringTokenizer.h>
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Numeric/Stat/Mva/CorrespondenceAnalysis.h>
+
+#include <Bpp/Seq/SequenceTools.h>
+
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+#include <fstream>
+#include <string>
+
+using namespace std;
+
+/******************************************************************************/
+
+CoalaCore::CoalaCore(size_t nbAxes, const string& exch) :
+  init_(true),
+  nbrOfAxes_(nbAxes),
+  exch_(exch),
+  P_(),
+  R_(),
+  colWeights_(),
+  paramValues_()
+{}
+
+/******************************************************************************/
+
+ParameterList CoalaCore::computeCOA(const SequenceContainer& data, bool param)
+{
+  ParameterList pList;
+  // Now we perform the Correspondence Analysis on from the matrix of observed frequencies computed on the alignment, to obtain the matrix of principal axes.
+  // First, the matrix of amino acid frequencies is calculated from the alignment:
+  vector<string> names = data.getSequencesNames();
+  vector< map<int, double> > freqs(names.size()); // One map per sequence
+  // Each map is filled with the corresponding frequencies, which are then normalized.
+  for (size_t i = 0; i < names.size(); i++)
+  {
+    Sequence* seq = new BasicSequence(data.getSequence(names[i]));
+    SymbolListTools::changeGapsToUnknownCharacters(*seq);
+    SequenceTools::getFrequencies(*seq, freqs.at(i));
+    // Unknown characters are now ignored:
+    double t = 0;
+    for (unsigned int k = 0; k < 20; k++)
+    {
+      t += freqs.at(i)[k];
+    }
+    for (unsigned int k = 0; k < 20; k++)
+    {
+      freqs.at(i)[k] /= t;
+    }
+    delete seq;
+  }
+
+  // The matrix of observed frequencies is filled. If an amino acid is completely absent from the alignment, its frequency is set to 10^-6.
+  RowMatrix<double> freqMatrix(names.size(), 20);
+  for (size_t i = 0; i < freqs.size(); i++)
+  {
+    bool normalize = false;
+    for (int j = 0; j < 20; j++)
+    {
+      if (freqs[i].find(j) != freqs[i].end())
+      {
+        map<int, double>::iterator it = freqs[i].find(j);
+        freqMatrix(i, j) = (*it).second;
+      }
+      else
+      {
+        freqMatrix(i, j) = 0.000001;
+        normalize = true;
+      }
+    }
+    if (normalize)
+    {
+      double sum = 0;
+      for (unsigned int k = 0; k < 20; k++)
+      {
+        sum += freqMatrix(i, k);
+      }
+      for (unsigned int l = 0; l < 20; l++)
+      {
+        freqMatrix(i, l) = freqMatrix(i, l) / sum;
+      }
+    }
+  }
+
+  // The COA analysis:
+  CorrespondenceAnalysis* coa = new CorrespondenceAnalysis(freqMatrix, 19);
+  // Matrix of principal axes:
+  RowMatrix<double> ppalAxes = coa->getPrincipalAxes();
+  // The transpose of the matrix of principal axes is computed:
+  MatrixTools::transpose(ppalAxes, P_);
+  // The matrix of row coordinates is stored:
+  R_ = coa->getRowCoordinates();
+  // The column weights are retrieved:
+  colWeights_ = coa->getColumnWeights();
+
+  if (param)
+  {
+    // Parameters are defined:
+    size_t nbAxesConserved = coa->getNbOfKeptAxes();
+    if (nbrOfAxes_ > nbAxesConserved)
+    {
+      ApplicationTools::displayWarning("The specified number of parameters per branch (" + TextTools::toString(nbrOfAxes_) +
+                                       ") is higher than the number of axes (" + TextTools::toString(nbAxesConserved) +
+                                       ")... The number of parameters per branch is now equal to the number of axes kept by the COA analysis (" + TextTools::toString(nbAxesConserved) + ")");
+      nbrOfAxes_ = nbAxesConserved;
+    }
+    for (unsigned int i = 0; i < nbrOfAxes_; i++)
+    {
+      const vector<double> rCoords = R_.col(i);
+      double maxCoord = VectorTools::max(rCoords);
+      double minCoord = VectorTools::min(rCoords);
+      double sd = VectorTools::sd<double, double>(rCoords);
+      IntervalConstraint* constraint = new IntervalConstraint(minCoord - sd, maxCoord + sd, true, true);
+      if (paramValues_.find("AxPos" + TextTools::toString(i)) != paramValues_.end())
+        pList.addParameter(Parameter("COaLA.AxPos" + TextTools::toString(i), TextTools::toDouble(paramValues_["AxPos" + TextTools::toString(i)].substr(0, 8)), constraint));
+      else
+        pList.addParameter(Parameter("COaLA.AxPos" + TextTools::toString(i), 0., constraint));
+    }
+  }
+  return pList;
+}
+
+/******************************************************************************/
+/* Function that computes the product of a matrix P of size nbrOfAxes_x20 with a vector V of size nbrOfAxes_, and returns a vector of size 20.*/
+
+vector<double> CoalaCore::prodMatrixVector(RowMatrix<double>& P, vector<double>& V)
+{
+  vector<double> E(20, 0.0);
+
+  for (unsigned int i = 0; i < 20; i++)
+  {
+    for (unsigned int j = 0; j < V.size(); j++)
+    {
+      E[i] = E[i] + P(j, i) * V[j];
+    }
+  }
+  return E;
+}
+
+/******************************************************************************/
diff --git a/src/Bpp/Phyl/Model/Protein/CoalaCore.h b/src/Bpp/Phyl/Model/Protein/CoalaCore.h
new file mode 100644
index 0000000..c573660
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/CoalaCore.h
@@ -0,0 +1,103 @@
+//
+// File: CoalaCore.h
+// Created by: Mathieu Groussin
+// Modified on: Sun Mar 13 12:00:00 2011
+//
+
+/*
+   Copyright or � or Copr. Bio++ Development Team, (November 16, 2004)
+   PCA
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+
+#ifndef _COALACORE_H_
+#define _COALACORE_H_
+
+// From Core:
+#include <Bpp/Numeric/Matrix/Matrix.h>
+
+#include <Bpp/Numeric/ParameterList.h>
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/ProteicAlphabet.h>
+#include <Bpp/Seq/Container/SequenceContainer.h>
+
+
+using namespace std;
+
+namespace bpp
+{
+/**
+ * @brief This class is the core class inherited by the Coala class. COaLA is a branch-heterogeneous amino-acid substitution model.
+ *
+ * This class allows to compute the COA from the alignment, to define the parameter (axis positions), and implements a function used to compute the equilibrium frequencies from a set of
+ * coordinates along the principal axes of the COA.
+ *
+ * @author Mathieu Groussin
+ * @param nbAxes The number of principal axes of the COA that have to be taken into account to optimize the 20 branch-specific equilibrium frequencies. This number is common to all branches, as
+ * well as on the root, where frequencies are optimized with a MVAprotein object (See the ProteinFrequenciesSet class).
+ * @param exch The exchangeability matrix. The matrices currently available are DSO78, JTT92, WAG01 or LG08. A user-defined matrix can be specified with the 'file' argument.
+ */
+
+class CoalaCore
+{
+protected:
+  bool init_;
+  size_t nbrOfAxes_;
+  string exch_;
+  RowMatrix<double> P_;
+  RowMatrix<double> R_;
+  vector<double> colWeights_;
+  map<string, string> paramValues_;
+
+public:
+  CoalaCore(size_t nbAxes = 0, const string& exch = "LG08");
+
+  virtual ~CoalaCore() {}
+
+  CoalaCore* clone() const { return new CoalaCore(*this); }
+
+public:
+  size_t getNbrOfAxes() const { return nbrOfAxes_; }
+  const RowMatrix<double>& getTppalAxesMatrix() const { return P_; }
+  const RowMatrix<double>& getRowCoordinates() const { return R_; }
+  const vector<double>& getColumnWeights() const { return colWeights_; }
+  void setParamValues(const map<string, string>& valuesSettings) { paramValues_ = valuesSettings; }
+
+protected:
+  ParameterList computeCOA(const SequenceContainer& data, bool param = true);
+  
+  vector<double> prodMatrixVector(RowMatrix<double>& P, vector<double>& V);
+};
+
+} // end of namespace bpp.
+
+#endif  // _COALACORE_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/DSO78.cpp b/src/Bpp/Phyl/Model/Protein/DSO78.cpp
new file mode 100755
index 0000000..9cbb0d8
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/DSO78.cpp
@@ -0,0 +1,91 @@
+//
+// File: DSO78.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Oct 05 18:48:19 2004
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "DSO78.h"
+
+//From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+
+/******************************************************************************/
+
+DSO78::DSO78(const ProteicAlphabet* alpha) :
+  AbstractParameterAliasable("DSO78."),
+  AbstractSubstitutionModel(alpha, "DSO78."),
+  AbstractReversibleSubstitutionModel(alpha, "DSO78."),
+  freqSet_(0)
+{
+  #include "__DSO78ExchangeabilityCode"
+  #include "__DSO78FrequenciesCode"
+  freqSet_ = new FixedProteinFrequenciesSet(alpha, freq_);
+  updateMatrices();
+}
+
+DSO78::DSO78(const ProteicAlphabet* alpha, ProteinFrequenciesSet* freqSet, bool initFreqs) :
+  AbstractParameterAliasable("DSO78+F."),
+  AbstractSubstitutionModel(alpha, "DSO78+F."),
+  AbstractReversibleSubstitutionModel(alpha, "DSO78+F."),
+  freqSet_(freqSet)
+{
+  #include "__DSO78ExchangeabilityCode"
+  #include "__DSO78FrequenciesCode"
+  if (initFreqs) freqSet_->setFrequencies(freq_);
+  else freq_ = freqSet_->getFrequencies();
+  freqSet_->setNamespace("DSO78+F."+freqSet_->getNamespace());
+  addParameters_(freqSet_->getParameters());
+  updateMatrices();  
+}
+
+/******************************************************************************/
+
+void DSO78::setFreqFromData(const SequenceContainer& data)
+{
+  std::map<int, double> freqs;
+  SequenceContainerTools::getFrequencies(data, freqs);
+  double t = 0;
+  for (size_t i = 0; i < size_; i++) t += freqs[static_cast<int>(i)];
+  for (size_t i = 0; i < size_; i++) freq_[i] = freqs[static_cast<int>(i)] / t;
+  freqSet_->setFrequencies(freq_);
+  //Update parameters and re-compute generator and eigen values:
+  matchParametersValues(freqSet_->getParameters());
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Protein/DSO78.h b/src/Bpp/Phyl/Model/Protein/DSO78.h
new file mode 100755
index 0000000..8d26bd6
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/DSO78.h
@@ -0,0 +1,150 @@
+//
+// File: DSO78.h
+// Created by: Julien Dutheil
+// Created on: Tue Oct 05 18:49:44 2004
+//
+
+/*
+  Copyright or © or Copr. CNRS, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _DSO78_H_
+#define _DSO78_H_
+
+#include "ProteinSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+#include "../FrequenciesSet/ProteinFrequenciesSet.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/ProteicAlphabet.h>
+
+namespace bpp
+{
+
+  /**
+   * @brief The Dayhoff, Schwartz and Orcutt substitution model for proteins.
+   *
+   * Exchangeabilities have been computed using the DCMut method of Kosiol and Goldman.
+   * The exchangability matrix is normalized so that \f$Q = S . \pi\f$ and \f$\sum_i Q_{i,i}\pi_i = -1\f$.
+   * The original frequencies can be used, or alternatively a parametrized version, corresponding to the
+   * so-called JTT92+F model.
+   * Eigen values and vectors are obtained numerically.
+   * 
+   * References:
+   * - Dayhoff MO, Schwartz RM and Orcutt BC (1978), _A model of evolutionary change in proteins_, 5(3) 345-352, in _Atlas of Protein Sequence and Structure_. 
+   * - Kosiol C and Goldman N (2005), _Molecular Biology And Evolution_ 22(2) 193-9. 
+   */
+  class DSO78 :
+    public virtual ProteinSubstitutionModel,
+    public AbstractReversibleSubstitutionModel
+  {
+  private:
+    ProteinFrequenciesSet* freqSet_;
+
+  public:
+    /**
+     * @brief Build a simple DSO78 model, with original equilibrium frequencies.
+     *
+     * @param alpha A proteic alphabet.
+     */
+    DSO78(const ProteicAlphabet* alpha);
+
+    /**
+     * @brief Build a DSO78 model with special equilibrium frequencies.
+     *
+     * @param alpha A proteic alphabet.
+     * @param freqSet A pointer toward a protein frequencies set, which will be owned by this instance.
+     * @param initFreqs Tell if the frequency set should be initialized with the original JTT92 values.
+     * Otherwise, the values of the set will be used.
+     */
+    DSO78(const ProteicAlphabet* alpha, ProteinFrequenciesSet* freqSet, bool initFreqs=false);
+
+    DSO78(const DSO78& model) :
+      AbstractParameterAliasable(model),
+      AbstractSubstitutionModel(model),
+      AbstractReversibleSubstitutionModel(model),
+      freqSet_(dynamic_cast<ProteinFrequenciesSet *>(model.freqSet_->clone()))
+    {}
+
+    DSO78& operator=(const DSO78& model)
+    {
+      AbstractParameterAliasable::operator=(model);
+      AbstractSubstitutionModel::operator=(model);
+      AbstractReversibleSubstitutionModel::operator=(model);
+      if (freqSet_) delete freqSet_;
+      freqSet_ = dynamic_cast<ProteinFrequenciesSet *>(model.freqSet_->clone());
+      return *this;
+    }
+
+    virtual ~DSO78() { delete freqSet_; }
+
+#ifndef NO_VIRTUAL_COV
+    DSO78*
+#else
+    Clonable*
+#endif
+    clone() const { return new DSO78(*this); }
+    
+  public:
+    std::string getName() const 
+    { 
+      if (freqSet_->getNamespace().find("DSO78+F.")!=std::string::npos)
+        return "DSO78+F"; 
+      else 
+        return "DSO78"; 
+    }
+
+    void fireParameterChanged(const ParameterList& parameters)
+    {
+      freqSet_->matchParametersValues(parameters);
+      freq_ = freqSet_->getFrequencies();
+      AbstractReversibleSubstitutionModel::fireParameterChanged(parameters);
+    }
+
+    void setFrequenciesSet(const ProteinFrequenciesSet& freqSet)
+    {
+      delete freqSet_;
+      freqSet_ = dynamic_cast<ProteinFrequenciesSet*>(freqSet.clone());
+      resetParameters_();
+      addParameters_(freqSet_->getParameters());
+    }
+
+    const FrequenciesSet* getFrequenciesSet() const { return freqSet_; }
+
+    void setFreqFromData(const SequenceContainer& data);
+
+  };
+
+} //end of namespace bpp.
+
+#endif	//_DSO78_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/JCprot.cpp b/src/Bpp/Phyl/Model/Protein/JCprot.cpp
new file mode 100755
index 0000000..5c25c2f
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/JCprot.cpp
@@ -0,0 +1,194 @@
+//
+// File: JCprot.cpp
+// Created by: Julien Dutheil
+// Created on: Tue May 27 16:04:36 2003
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "JCprot.h"
+
+//From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+
+#include <cmath>
+
+using namespace std;
+
+/******************************************************************************/
+
+JCprot::JCprot(const ProteicAlphabet* alpha) :
+  AbstractParameterAliasable("JC69."),
+  AbstractSubstitutionModel(alpha, "JC69."),
+  AbstractReversibleSubstitutionModel(alpha, "JC69."),
+  exp_(), p_(size_, size_), freqSet_(0)
+{
+  freqSet_ = new FixedProteinFrequenciesSet(alpha, freq_);
+  updateMatrices();
+}
+
+JCprot::JCprot(const ProteicAlphabet* alpha, ProteinFrequenciesSet* freqSet, bool initFreqs) :
+  AbstractParameterAliasable("JC69+F."),
+  AbstractSubstitutionModel(alpha, "JC69+F."),
+  AbstractReversibleSubstitutionModel(alpha, "JC69+F."),
+  exp_(), p_(size_, size_), freqSet_(freqSet)
+{
+  if (initFreqs) freqSet_->setFrequencies(freq_);
+  else freq_ = freqSet_->getFrequencies();
+  freqSet_->setNamespace("JC69+F."+freqSet_->getNamespace());
+  addParameters_(freqSet_->getParameters());
+  updateMatrices();  
+}
+
+
+/******************************************************************************/
+	
+void JCprot::updateMatrices()
+{
+	// Frequencies:
+	for (unsigned int i = 0; i < 20; i++) freq_[i] = 1. / 20.;
+
+	// Generator:
+	for (unsigned int i = 0; i < 20; i++)
+  {
+		for (unsigned int j = 0; j < 20; j++)
+    {
+			generator_(i, j) = (i == j) ? -1. : 1./19.;
+			exchangeability_(i, j) = generator_(i, j) * 20.;
+		}
+	}
+	
+	// Eigen values:
+	eigenValues_[0] = 0;
+	for (unsigned int i = 1; i < 20; i++) eigenValues_[i] = -20. / 19.;
+	
+	// Eigen vectors:
+	for (unsigned int i = 0; i < 20; i++) leftEigenVectors_(0,i) = 1./20.;
+	for (unsigned int i = 1; i < 20; i++) 
+		for (unsigned int j = 0; j < 20; j++)
+			leftEigenVectors_(i,j) = -1./20.;
+	for (unsigned int i = 0; i < 19; i++) leftEigenVectors_(19-i,i) = 19./20.;
+
+	for (unsigned int i = 0; i < 20; i++) rightEigenVectors_(i,0) = 1.;
+	for (unsigned int i = 1; i < 20; i++) rightEigenVectors_(19,i) = -1.;
+	for (unsigned int i = 0; i < 19; i++) 
+		for (unsigned int j = 1; j < 20; j++)
+			rightEigenVectors_(i,j) = 0.;
+	for (unsigned int i = 1; i < 20; i++) rightEigenVectors_(19-i,i) = 1.;
+
+}
+	
+/******************************************************************************/
+
+double JCprot::Pij_t(int i, int j, double d) const
+{
+  if(i == j) return 1./20. + 19./20. * exp(-  rate_ * 20./19. * d);
+  else       return 1./20. -  1./20. * exp(-  rate_ * 20./19. * d);
+}
+
+/******************************************************************************/
+
+double JCprot::dPij_dt(int i, int j, double d) const
+{
+  if(i == j) return -  rate_ *        exp(-  rate_ * 20./19. * d);
+  else       return  rate_ * 1./19. * exp(-  rate_ * 20./19. * d);
+}
+
+/******************************************************************************/
+
+double JCprot::d2Pij_dt2(int i, int j, double d) const
+{
+  if(i == j) return    rate_ *  rate_ * 20./19.  * exp(-  rate_ * 20./19. * d);
+  else       return -  rate_ *  rate_ * 20./361. * exp(-  rate_ * 20./19. * d);
+}
+
+/******************************************************************************/
+
+const Matrix<double>& JCprot::getPij_t(double d) const
+{
+  exp_ = exp(-  rate_ * 20./19. * d);
+	for(unsigned int i = 0; i < size_; i++)
+  {
+		for(unsigned int j = 0; j < size_; j++)
+    {
+			p_(i,j) = (i==j) ? 1./20. + 19./20. * exp_ : 1./20. - 1./20. * exp_;
+		}
+	}
+	return p_;
+}
+
+const Matrix<double>& JCprot::getdPij_dt(double d) const
+{
+  exp_ = exp(-  rate_ * 20./19. * d);
+	for(unsigned int i = 0; i < size_; i++)
+  {
+		for(unsigned int j = 0; j < size_; j++)
+    {
+      p_(i,j) =  rate_ * ((i==j) ? - exp_ : 1./19. * exp_);
+		}
+	}
+	return p_;
+}
+
+const Matrix<double>& JCprot::getd2Pij_dt2(double d) const
+{
+  exp_ = exp( rate_ * - 20./19. * d);
+	for(unsigned int i = 0; i < size_; i++)
+  {
+		for(unsigned int j = 0; j < size_; j++)
+    {
+      p_(i,j) =  rate_ *  rate_ * ((i==j) ? 20./19. * exp_ : - 20./361. * exp_);
+		}
+	}
+	return p_;
+}
+
+/******************************************************************************/
+
+void JCprot::setFreqFromData(const SequenceContainer& data)
+{
+  std::map<int, double> freqs;
+  SequenceContainerTools::getFrequencies(data, freqs);
+  double t = 0;
+  for (unsigned int i = 0; i < size_; i++) t += freqs[i];
+  for (unsigned int i = 0; i < size_; i++) freq_[i] = freqs[i] / t;
+  freqSet_->setFrequencies(freq_);
+  //Update parameters and re-compute generator and eigen values:
+  matchParametersValues(freqSet_->getParameters());
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Protein/JCprot.h b/src/Bpp/Phyl/Model/Protein/JCprot.h
new file mode 100755
index 0000000..05967f9
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/JCprot.h
@@ -0,0 +1,240 @@
+//
+// File: JCprot.h
+// Created by: Julien Dutheil
+// Created on: Tue May 25 16:04:36 2003
+//
+
+/*
+  Copyright or © or Copr. CNRS, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _JCPROT_H_
+#define _JCPROT_H_
+
+#include <Bpp/Seq/Alphabet/ProteicAlphabet.h>
+#include "ProteinSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+#include "../FrequenciesSet/ProteinFrequenciesSet.h"
+
+namespace bpp
+{
+
+  /**
+   * @brief The Jukes-Cantor substitution model for proteins.
+   *
+   * All rates equal:
+   * \f[
+   * \begin{pmatrix}
+   * \ddots & r      & \ldots & r \\ 
+   * r      & \ddots & \ddots & \vdots \\ 
+   * \vdots & \ddots & \ddots & r \\
+   * r      & \ldots & r      & \ddots \\ 
+   * \end{pmatrix}
+   * \f]
+   * \f[
+   * \pi = diag\left(\frac{1}{20}, \ldots, \frac{1}{20}\right)
+   * \f]
+   * Normalization: \f$r\f$ is set so that \f$\sum_i Q_{i,i}\pi_i = -1\f$:
+   * \f[
+   * S = \begin{pmatrix}
+   * -20           & \frac{20}{19} & \ldots        & \frac{20}{19} \\ 
+   * \frac{20}{19} &           -20 & \ddots        & \vdots \\ 
+   * \vdots        & \ddots        & \ddots        & \frac{20}{19} \\
+   * \frac{20}{19} & \ldots        & \frac{20}{19} & -20 \\ 
+   * \end{pmatrix}
+   * \f]
+   * The normalized generator is obtained by taking the dot product of \f$S\f$ and \f$pi\f$:
+   * \f[
+   * Q = S . \pi = \begin{pmatrix}
+   * -1 & \frac{1}{19}     & \ldots & \frac{1}{19} \\ 
+   * \frac{1}{19} & -1     & \ddots & \vdots \\ 
+   * \vdots       & \ddots & \ddots & \frac{1}{19} \\ 
+   * \frac{1}{19} & \ldots & \frac{1}{19} & -1 \\ 
+   * \end{pmatrix}
+   * \f]
+   *
+   * The eigen values are \f$\left(0, -\frac{20}{19}, \ldots, -\frac{20}{19}\right)\f$, 
+   * the left eigen vectors are, by row:
+   * \f[
+   * U = \begin{pmatrix}
+   *   \frac{1}{20} &        \ldots &  \frac{1}{20} &   \frac{1}{20} &  \frac{1}{20} \\
+   *  -\frac{1}{20} &        \ldots & -\frac{1}{20} &  \frac{19}{20} & -\frac{1}{20} \\
+   *         \vdots &        \ddots & \frac{19}{20} & -\frac{1}{20}  & -\frac{1}{20} \\
+   *  -\frac{1}{20} &        \ddots &        \ddots &         \vdots &        \vdots \\
+   *  \frac{19}{20} & -\frac{1}{20} &        \ldots &  -\frac{1}{20} & -\frac{1}{20} \\
+   * \end{pmatrix}
+   * \f]
+   * and the right eigen vectors are, by column:
+   * \f[
+   * U^-1 = \begin{pmatrix}
+   *      1 &      0 &  \ldots &      0 &  1 \\
+   * \vdots & \vdots &  \ddots & \ddots &  0 \\
+   *      1 &      0 &       1 & \ddots & \vdots \\
+   *      1 &      1 &       0 & \ldots &  0 \\
+   *      1 &     -1 &      -1 & \ldots & -1 \\
+   * \end{pmatrix}
+   * \f]
+   *
+   * In addition, a rate_ factor defines the mean rate of the model.
+   *
+   * The probabilities of changes are computed analytically using the formulas:
+   * \f[
+   * P_{i,j}(t) = \begin{cases}
+   * \frac{1}{20} + \frac{19}{20}e^{- rate\_ * \frac{20}{19}t}& \text{if $i=j$}, \\
+   * \frac{1}{20} - \frac{1}{20}e^{- rate\_ * \frac{20}{19}t} & \text{otherwise}.
+   * \end{cases}
+   * \f]
+   *
+   * First and second order derivatives are also computed analytically using the formulas:
+   * \f[
+   * \frac{\partial P_{i,j}(t)}{\partial t} = rate\_ * \begin{cases}
+   * -e^{- rate\_ * \frac{20}{19}t}           & \text{if $i=j$}, \\
+   * \frac{1}{19}e^{- rate\_ * \frac{20}{19}t} & \text{otherwise}.
+   * \end{cases}
+   * \f]
+   * \f[
+   * \frac{\partial^2 P_{i,j}(t)}{\partial t^2} =  rate\_^2 * \begin{cases}
+   * \frac{20}{19}e^{- rate\_ * \frac{20}{19}t}  & \text{if $i=j$}, \\
+   * -\frac{20}{361}e^{- rate\_ * \frac{20}{19}t} & \text{otherwise}.
+   * \end{cases}
+   * \f]
+   *
+   * Reference:
+   * - Jukes TH and Cantor CR (1969), Evolution_ of proteins molecules_, 121-123, in Mammalian_ protein metabolism_. 
+   */
+  class JCprot:
+    public virtual ProteinSubstitutionModel,
+    public AbstractReversibleSubstitutionModel
+  {
+  private:
+    mutable double exp_;
+    mutable RowMatrix<double> p_;
+    ProteinFrequenciesSet* freqSet_;
+
+  public:
+    /**
+     * @brief Build a simple JC69 model, with original equilibrium frequencies.
+     *
+     * @param alpha A proteic alphabet.
+     */
+    JCprot(const ProteicAlphabet* alpha);
+
+    /**
+     * @brief Build a JC69 model with special equilibrium frequencies.
+     *
+     * @param alpha A proteic alphabet.
+     * @param freqSet A pointer toward a protein frequencies set, which will be owned by this instance.
+     * @param initFreqs Tell if the frequency set should be initialized with the original JTT92 values.
+     * Otherwise, the values of the set will be used.
+     */
+    JCprot(const ProteicAlphabet* alpha, ProteinFrequenciesSet* freqSet, bool initFreqs = false);
+
+    JCprot(const JCprot& model) :
+      AbstractParameterAliasable(model),
+      AbstractSubstitutionModel(model),
+      AbstractReversibleSubstitutionModel(model),
+      exp_(model.exp_),
+      p_(model.p_),
+      freqSet_(dynamic_cast<ProteinFrequenciesSet*>(model.freqSet_->clone()))
+    {}
+
+    JCprot& operator=(const JCprot& model)
+    {
+      AbstractParameterAliasable::operator=(model);
+      AbstractSubstitutionModel::operator=(model);
+      AbstractReversibleSubstitutionModel::operator=(model);
+      exp_ = model.exp_;
+      p_   = model.p_;
+      if (freqSet_) delete freqSet_;
+      freqSet_ = dynamic_cast<ProteinFrequenciesSet*>(model.freqSet_->clone());
+      return *this;
+    }
+
+    virtual ~JCprot() { delete freqSet_; }
+	
+#ifndef NO_VIRTUAL_COV
+    JCprot*
+#else
+    Clonable*
+#endif
+    clone() const { return new JCprot(*this); }
+
+  public:
+    double Pij_t    (int i, int j, double d) const;
+    double dPij_dt  (int i, int j, double d) const;
+    double d2Pij_dt2(int i, int j, double d) const;
+    const Matrix<double>& getPij_t    (double d) const;
+    const Matrix<double>& getdPij_dt  (double d) const;
+    const Matrix<double>& getd2Pij_dt2(double d) const;
+
+    std::string getName() const 
+    { 
+      if (freqSet_->getNamespace().find("+F.")!=std::string::npos)
+        return "JC69+F"; 
+      else 
+        return "JC69"; 
+    }
+	
+    void fireParameterChanged(const ParameterList& parameters)
+    {
+      freqSet_->matchParametersValues(parameters);
+      freq_ = freqSet_->getFrequencies();
+      AbstractReversibleSubstitutionModel::fireParameterChanged(parameters);
+    }
+
+    void setFrequenciesSet(const ProteinFrequenciesSet& freqSet)
+    {
+      delete freqSet_;
+      freqSet_ = dynamic_cast<ProteinFrequenciesSet*>(freqSet.clone());
+      resetParameters_();
+      addParameters_(freqSet_->getParameters());
+    }
+
+    const FrequenciesSet* getFrequenciesSet() const { return freqSet_; }
+
+    void setFreqFromData(const SequenceContainer& data);
+
+  protected:
+    /**
+     * In the case of the model of Jukes & Cantor, this method is useless since
+     * the generator is fixed! No matrice can be changed... This method is only
+     * used in the constructor of the class.
+     */
+    void updateMatrices();
+
+    
+  };
+
+} //end of namespace bpp.
+
+#endif	//_JCPROT_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/JTT92.cpp b/src/Bpp/Phyl/Model/Protein/JTT92.cpp
new file mode 100755
index 0000000..8513689
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/JTT92.cpp
@@ -0,0 +1,92 @@
+//
+// File: JTT92.cpp
+// Created by: Julien Dutheil
+// Created on: Wed Jan 21 14:09:43 2004
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "JTT92.h"
+
+//From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+JTT92::JTT92(const ProteicAlphabet* alpha) :
+  AbstractParameterAliasable("JTT92."),
+  AbstractSubstitutionModel(alpha, "JTT92."),
+  AbstractReversibleSubstitutionModel(alpha, "JTT92."),
+  freqSet_(0)
+{
+  #include "__JTT92ExchangeabilityCode"
+  #include "__JTT92FrequenciesCode"
+  freqSet_ = new FixedProteinFrequenciesSet(alpha, freq_);
+  updateMatrices();  
+}
+
+JTT92::JTT92(const ProteicAlphabet* alpha, ProteinFrequenciesSet* freqSet, bool initFreqs) :
+  AbstractParameterAliasable("JTT92+F."),
+  AbstractSubstitutionModel(alpha, "JTT92+F."),
+  AbstractReversibleSubstitutionModel(alpha, "JTT92+F."),
+  freqSet_(freqSet)
+{
+  #include "__JTT92ExchangeabilityCode"
+  #include "__JTT92FrequenciesCode"
+  if (initFreqs) freqSet_->setFrequencies(freq_);
+  else freq_ = freqSet_->getFrequencies();
+  freqSet_->setNamespace("JTT92+F."+freqSet_->getNamespace());
+  addParameters_(freqSet_->getParameters());
+  updateMatrices();  
+}
+
+/******************************************************************************/
+
+void JTT92::setFreqFromData(const SequenceContainer& data)
+{
+  std::map<int, double> freqs;
+  SequenceContainerTools::getFrequencies(data, freqs);
+  double t = 0;
+  for (unsigned int i = 0; i < size_; i++) t += freqs[i];
+  for (unsigned int i = 0; i < size_; i++) freq_[i] = freqs[i] / t;
+  freqSet_->setFrequencies(freq_);
+  //Update parameters and re-compute generator and eigen values:
+  matchParametersValues(freqSet_->getParameters());
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Protein/JTT92.h b/src/Bpp/Phyl/Model/Protein/JTT92.h
new file mode 100755
index 0000000..545757f
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/JTT92.h
@@ -0,0 +1,150 @@
+//
+// File: JTT92.h
+// Created by: Julien Dutheil
+// Created on: Wed Jan 21 14:09:43 2004
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _JTT92_H_
+#define _JTT92_H_
+
+#include "ProteinSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+#include "../FrequenciesSet/ProteinFrequenciesSet.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/ProteicAlphabet.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The Jones, Taylor and Thornton substitution model for proteins.
+ *
+ * Exchangeabilities have been computed using the DCMut method of Kosiol and Goldman.
+ * The exchangability matrix is normalized so that \f$Q = S . \pi\f$ and \f$\sum_i Q_{i,i}\pi_i = -1\f$.
+ * The original frequencies can be used, or alternatively a parametrized version, corresponding to the
+ * so-called JTT92+F model.
+ * Eigen values and vectors are obtained numerically.
+ * 
+ * References:
+ * - Jones DT, Taylor WR and Thornton JM (1992), _Computer Applications In The Biosciences_, 8(3) 275-82. 
+ * - Kosiol C and Goldman N (2005), _Molecular Biology And Evolution_ 22(2) 193-9. 
+ */
+class JTT92 :
+  public virtual ProteinSubstitutionModel,
+  public AbstractReversibleSubstitutionModel
+{
+  private:
+    ProteinFrequenciesSet* freqSet_;
+
+	public:
+    /**
+     * @brief Build a simple JTT92 model, with original equilibrium frequencies.
+     *
+     * @param alpha A proteic alphabet.
+     */
+		JTT92(const ProteicAlphabet* alpha);
+
+    /**
+     * @brief Build a JTT92 model with special equilibrium frequencies.
+     *
+     * @param alpha A proteic alphabet.
+     * @param freqSet A pointer toward a protein frequencies set, which will be owned by this instance.
+     * @param initFreqs Tell if the frequency set should be initialized with the original JTT92 values.
+     * Otherwise, the values of the set will be used.
+     */
+		JTT92(const ProteicAlphabet* alpha, ProteinFrequenciesSet* freqSet, bool initFreqs=false);
+
+    JTT92(const JTT92& model) :
+      AbstractParameterAliasable(model),
+      AbstractSubstitutionModel(model),
+      AbstractReversibleSubstitutionModel(model),
+      freqSet_(dynamic_cast<ProteinFrequenciesSet *>(model.freqSet_->clone()))
+    {}
+
+    JTT92& operator=(const JTT92& model)
+    {
+      AbstractParameterAliasable::operator=(model);
+      AbstractSubstitutionModel::operator=(model);
+      AbstractReversibleSubstitutionModel::operator=(model);
+      if (freqSet_) delete freqSet_;
+      freqSet_ = dynamic_cast<ProteinFrequenciesSet *>(model.freqSet_->clone());
+      return *this;
+    }
+
+		virtual ~JTT92() { delete freqSet_; }
+
+#ifndef NO_VIRTUAL_COV
+    JTT92*
+#else
+    Clonable*
+#endif
+    clone() const { return new JTT92(*this); }
+
+	public:
+    std::string getName() const 
+    { 
+      if (freqSet_->getNamespace().find("JTT92+F.")!=std::string::npos)
+        return "JTT92+F"; 
+      else 
+        return "JTT92"; 
+    }
+
+    void fireParameterChanged(const ParameterList& parameters)
+    {
+      freqSet_->matchParametersValues(parameters);
+      freq_ = freqSet_->getFrequencies();
+      AbstractReversibleSubstitutionModel::fireParameterChanged(parameters);
+    }
+
+    void setFrequenciesSet(const ProteinFrequenciesSet& freqSet)
+    {
+      delete freqSet_;
+      freqSet_ = dynamic_cast<ProteinFrequenciesSet*>(freqSet.clone());
+      resetParameters_();
+      addParameters_(freqSet_->getParameters());
+    }
+
+    const FrequenciesSet* getFrequenciesSet() const { return freqSet_; }
+
+    void setFreqFromData(const SequenceContainer& data);
+
+};
+
+} //end of namespace bpp.
+
+#endif	//_JTT92_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/LG08.cpp b/src/Bpp/Phyl/Model/Protein/LG08.cpp
new file mode 100644
index 0000000..7e01925
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LG08.cpp
@@ -0,0 +1,92 @@
+//
+// File: LG08.cpp
+// Created by: Laurent Gueguen
+// Created on: lundi 13 septembre 2010, à 13h 28
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "LG08.h"
+
+//From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+LG08::LG08(const ProteicAlphabet* alpha) :
+  AbstractParameterAliasable("LG08."),
+  AbstractSubstitutionModel(alpha, "LG08."),
+  AbstractReversibleSubstitutionModel(alpha, "LG08."),
+  freqSet_(0)
+{
+  #include "__LG08ExchangeabilityCode"
+  #include "__LG08FrequenciesCode"
+  freqSet_ = new FixedProteinFrequenciesSet(alpha, freq_);
+  updateMatrices();  
+}
+
+LG08::LG08(const ProteicAlphabet* alpha, ProteinFrequenciesSet* freqSet, bool initFreqs) :
+  AbstractParameterAliasable("LG08+F."),
+  AbstractSubstitutionModel(alpha, "LG08+F."),
+  AbstractReversibleSubstitutionModel(alpha, "LG08+F."),
+  freqSet_(freqSet)
+{
+  #include "__LG08ExchangeabilityCode"
+  #include "__LG08FrequenciesCode"
+  if (initFreqs) freqSet_->setFrequencies(freq_);
+  else freq_ = freqSet_->getFrequencies();
+  freqSet_->setNamespace("LG08+F."+freqSet_->getNamespace());
+  addParameters_(freqSet_->getParameters());
+  updateMatrices();  
+}
+
+/******************************************************************************/
+
+void LG08::setFreqFromData(const SequenceContainer& data)
+{
+  std::map<int, double> freqs;
+  SequenceContainerTools::getFrequencies(data, freqs);
+  double t = 0;
+  for (unsigned int i = 0; i < size_; i++) t += freqs[i];
+  for (unsigned int i = 0; i < size_; i++) freq_[i] = freqs[i] / t;
+  freqSet_->setFrequencies(freq_);
+  //Update parameters and re-compute generator and eigen values:
+  matchParametersValues(freqSet_->getParameters());
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Protein/LG08.h b/src/Bpp/Phyl/Model/Protein/LG08.h
new file mode 100644
index 0000000..6708ade
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LG08.h
@@ -0,0 +1,148 @@
+//
+// File: LG08.h
+// Created by: Laurent Gueguen
+// Created on: Wed lundi 13 septembre 2010, à 13h 26
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _LG08_H_
+#define _LG08_H_
+
+#include "ProteinSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+#include "../FrequenciesSet/ProteinFrequenciesSet.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/ProteicAlphabet.h>
+
+namespace bpp
+{
+
+  /**
+   * @brief The Le and Gascuel substitution model for proteins.
+   *
+   * The exchangability matrix is normalized so that \f$Q = S . \pi\f$ and \f$\sum_i Q_{i,i}\pi_i = -1\f$.
+   * The original frequencies can be used, or alternatively a parametrized version, corresponding to the
+   * so-called LG08+F model.
+   * Eigen values and vectors are obtained numerically.
+   * 
+   * Reference:
+   * - Le, Si Q. and Gascuel, O. (2008), _Molecular Biology And Evolution_ 25, 1307--1320. 
+   */
+  class LG08 :
+    public virtual ProteinSubstitutionModel,
+    public AbstractReversibleSubstitutionModel
+  {
+  private:
+    ProteinFrequenciesSet* freqSet_;
+
+  public:
+    /**
+     * @brief Build a simple LG08 model, with original equilibrium frequencies.
+     *
+     * @param alpha A proteic alphabet.
+     */
+    LG08(const ProteicAlphabet* alpha);
+
+    /**
+     * @brief Build a LG08 model with special equilibrium frequencies.
+     *
+     * @param alpha A proteic alphabet.
+     * @param freqSet A pointer toward a protein frequencies set, which will be owned by this instance.
+     * @param initFreqs Tell if the frequency set should be initialized with the original LG08 values.
+     * Otherwise, the values of the set will be used.
+     */
+    LG08(const ProteicAlphabet* alpha, ProteinFrequenciesSet* freqSet, bool initFreqs=false);
+
+    LG08(const LG08& model) :
+      AbstractParameterAliasable(model),
+      AbstractSubstitutionModel(model),
+      AbstractReversibleSubstitutionModel(model),
+      freqSet_(dynamic_cast<ProteinFrequenciesSet*>(model.freqSet_->clone()))
+    {}
+
+    LG08& operator=(const LG08& model)
+    {
+      AbstractParameterAliasable::operator=(model);
+      AbstractSubstitutionModel::operator=(model);
+      AbstractReversibleSubstitutionModel::operator=(model);
+      if (freqSet_) delete freqSet_;
+      freqSet_ = dynamic_cast<ProteinFrequenciesSet*>(model.freqSet_->clone());
+      return *this;
+    }
+
+    virtual ~LG08() { delete freqSet_; }
+
+#ifndef NO_VIRTUAL_COV
+    LG08*
+#else
+    Clonable*
+#endif
+    clone() const { return new LG08(*this); }
+
+  public:
+    std::string getName() const 
+    { 
+      if (freqSet_->getNamespace().find("LG08+F.")!=std::string::npos)
+        return "LG08+F"; 
+      else 
+        return "LG08"; 
+    }
+
+    void fireParameterChanged(const ParameterList& parameters)
+    {
+      freqSet_->matchParametersValues(parameters);
+      freq_ = freqSet_->getFrequencies();
+      AbstractReversibleSubstitutionModel::fireParameterChanged(parameters);
+    }
+
+    void setFrequenciesSet(const ProteinFrequenciesSet& freqSet)
+    {
+      delete freqSet_;
+      freqSet_ = dynamic_cast<ProteinFrequenciesSet*>(freqSet.clone());
+      resetParameters_();
+      addParameters_(freqSet_->getParameters());
+    }
+
+    const FrequenciesSet* getFrequenciesSet() const { return freqSet_; }
+
+    void setFreqFromData(const SequenceContainer& data);
+
+  };
+
+} //end of namespace bpp.
+
+#endif	//_LG08_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/LGL08_CAT.cpp b/src/Bpp/Phyl/Model/Protein/LGL08_CAT.cpp
new file mode 100644
index 0000000..ac9dbba
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LGL08_CAT.cpp
@@ -0,0 +1,159 @@
+//
+// File: LGL08_CAT.cpp
+// Created by:  Mathieu Groussin
+// Created on: Tuesday 11 December 2012
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "LGL08_CAT.h"
+#include "../FrequenciesSet/ProteinFrequenciesSet.h"
+
+#include <Bpp/Numeric/Prob/SimpleDiscreteDistribution.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+LGL08_CAT::LGL08_CAT(const ProteicAlphabet* alpha, unsigned int nbCat) :
+  AbstractBiblioMixedSubstitutionModel("LGL08_CAT."),
+  pmixmodel_(0)
+{
+  // build the submodel
+
+  vector<SubstitutionModel*> vpSM;
+  for(unsigned int i = 1; i < nbCat + 1; i++)
+	vpSM.push_back(new LGL08_CAT::EmbeddedModel(alpha, "C" + TextTools::toString(i), nbCat));
+
+  Vdouble vrate, vproba;
+
+  for (size_t i = 0; i < vpSM.size(); i++)
+  {
+    vproba.push_back((dynamic_cast<LGL08_CAT::EmbeddedModel*>(vpSM[i]))->getProportion());
+    vrate.push_back(vpSM[i]->getRate());
+  }
+
+  pmixmodel_.reset(new MixtureOfSubstitutionModels(alpha, vpSM, vproba, vrate));
+
+  string name, st;
+  ParameterList pl = pmixmodel_->getParameters();
+  for (unsigned int i = 0; i < pl.size(); i++)
+  {
+    name = pl[i].getName();
+    lParPmodel_.addParameter(Parameter(pl[i]));
+    st = pmixmodel_->getParameterNameWithoutNamespace(name);
+    mapParNamesFromPmodel_[name] = st;
+    addParameter_(new Parameter("LGL08_CAT." + st,
+                            pmixmodel_->getParameterValue(st),
+                            pmixmodel_->getParameter(st).hasConstraint() ? pmixmodel_->getParameter(st).getConstraint()->clone() : 0, true));
+  }
+
+  updateMatrices();
+}
+
+LGL08_CAT::LGL08_CAT(const LGL08_CAT& mod2) : AbstractBiblioMixedSubstitutionModel(mod2),
+  pmixmodel_(new MixtureOfSubstitutionModels(*mod2.pmixmodel_))
+{}
+
+LGL08_CAT& LGL08_CAT::operator=(const LGL08_CAT& mod2)
+{
+  AbstractBiblioMixedSubstitutionModel::operator=(mod2);
+
+  pmixmodel_.reset(new MixtureOfSubstitutionModels(*mod2.pmixmodel_));
+
+  return *this;
+}
+
+LGL08_CAT::~LGL08_CAT() {}
+
+/**************** sub model classes */ // ////////
+
+LGL08_CAT::EmbeddedModel::EmbeddedModel(const ProteicAlphabet* alpha, string name, unsigned int nbCat) :
+  AbstractParameterAliasable(name),
+  AbstractSubstitutionModel(alpha, name),
+  AbstractReversibleSubstitutionModel(alpha, name),
+  proportion_(1),
+  name_(name)
+{
+  //Exchangeabilities:
+  for(unsigned int i = 0; i < 20; i++)
+  {
+	for(unsigned int j = 0; j < 20; j++)
+	{
+	  if(i == j)
+		exchangeability_(i,i) = -19.;
+	  else
+		exchangeability_(i,j) = 1.;
+	}
+  }
+  
+  //Equilibrium frequencies, rates and proportions:
+  if(nbCat == 10)
+  {
+#include "__CATC10FrequenciesCode"
+#include "__CATC10RatesProps"
+  }
+  else if(nbCat == 20)
+  {
+#include "__CATC20FrequenciesCode"
+#include "__CATC20RatesProps"	
+  }
+  else if(nbCat == 30)
+  {
+#include "__CATC30FrequenciesCode"
+#include "__CATC30RatesProps"	
+  }
+  else if(nbCat == 40)
+  {
+#include "__CATC40FrequenciesCode"
+#include "__CATC40RatesProps"	
+  }
+  else if(nbCat == 50)
+  {
+#include "__CATC50FrequenciesCode"
+#include "__CATC50RatesProps"	
+  }
+  else if(nbCat == 60)
+  {
+#include "__CATC60FrequenciesCode"
+#include "__CATC60RatesProps"	
+  }
+  else
+	throw Exception("LGL08_CAT.cpp: incorrect number of profiles. This number has to be 10, 20, 30, 40, 50 or 60.");
+  
+  updateMatrices();
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/LGL08_CAT.h b/src/Bpp/Phyl/Model/Protein/LGL08_CAT.h
new file mode 100644
index 0000000..97f916b
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LGL08_CAT.h
@@ -0,0 +1,130 @@
+//
+// File: LGL08_CAT.h
+// Created by: Mathieu Groussin
+// Created on: Tuesday 11 December 2012
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _LGL08_CAT_H_
+#define _LGL08_CAT_H_
+
+#include "../MixtureOfSubstitutionModels.h"
+#include "ProteinSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+#include "../AbstractBiblioMixedSubstitutionModel.h"
+
+using namespace std;
+
+namespace bpp
+{
+/**
+ * @brief The Le et al  (2008) CAT substitution model for proteins.
+ * @author Mathieu Groussin
+ *
+ * This model is a mixture of N profiles empirically built with an EM algorithm
+ * (see ref). The submodels are called C1, C2, ..., CN. For each model, exchangeabilities are equal (F81 model).
+ *
+ *
+ * This model includes 2N-2 parameters :
+ *
+ * - relrate1, ..., relrate(N-1) are the relative rates of model C1, ..., C(N-1);
+ * - relproba1, ..., relproba(N-1) are the relative proportions of model C1, ..., C(N-1);
+ *
+ * Important: See the relation between these parameters and the
+ * rates and probabilities of the models in the description of
+ * MixtureOfSubstitutionModels class.
+ *
+ * Reference:
+ *
+ * Le S.Q., Gascuel O. & Lartillot N. (2008) Bioinformatics 24:2317–2323.
+ */
+
+class LGL08_CAT :
+  public AbstractBiblioMixedSubstitutionModel
+{
+public:
+  class EmbeddedModel :
+    public virtual ProteinSubstitutionModel,
+    public AbstractReversibleSubstitutionModel
+  {
+private:
+    double proportion_;
+    string name_;
+
+public:
+    EmbeddedModel(const ProteicAlphabet* alpha, string name, unsigned int nbCat = 10);
+    ~EmbeddedModel(){}
+    EmbeddedModel* clone() const { return new EmbeddedModel(*this); }
+    string getName() const { return name_;}
+    double getProportion() const { return proportion_;}
+  };
+
+private:
+  std::auto_ptr<MixtureOfSubstitutionModels> pmixmodel_;
+
+public:
+  /**
+   * @brief Build a CAT model, with original equilibrium frequencies, probabilities and rates.
+   *
+   * @param alpha A proteic alphabet.
+   * @param nbCat number of profiles
+   *
+   */
+  LGL08_CAT(const ProteicAlphabet* alpha, unsigned int nbCat = 10);
+
+  ~LGL08_CAT();
+
+  LGL08_CAT* clone() const { return new LGL08_CAT(*this); }
+
+  LGL08_CAT(const LGL08_CAT&);
+
+  LGL08_CAT& operator=(const LGL08_CAT&);
+
+  const SubstitutionModel& getModel() const { return *pmixmodel_.get(); }
+
+  const MixedSubstitutionModel& getMixedModel() const { return *pmixmodel_.get(); }
+
+  std::string getName() const { return "LGL08_CAT"; }
+  
+private:
+  SubstitutionModel& getModel() { return *pmixmodel_.get(); }
+
+  MixedSubstitutionModel& getMixedModel() { return *pmixmodel_.get(); }
+
+};
+} // end of namespace bpp.
+
+#endif  // _LGL08_CAT_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/LLG08_EHO.cpp b/src/Bpp/Phyl/Model/Protein/LLG08_EHO.cpp
new file mode 100644
index 0000000..7ddae3d
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LLG08_EHO.cpp
@@ -0,0 +1,116 @@
+//
+// File: LLG08_EHO.cpp
+// Created by:  Laurent Gueguen
+// Created on: jeudi 7 octobre 2010, à 21h 47
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "LLG08_EHO.h"
+#include "../FrequenciesSet/ProteinFrequenciesSet.h"
+
+#include <Bpp/Numeric/Prob/SimpleDiscreteDistribution.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+LLG08_EHO::LLG08_EHO(const ProteicAlphabet* alpha) :
+  AbstractBiblioMixedSubstitutionModel("LLG08_EHO."),
+  pmixmodel_(0)
+{
+  // build the submodel
+
+  vector<SubstitutionModel*> vpSM;
+  vpSM.push_back(new LLG08_EHO::EmbeddedModel(alpha, "Extended"));
+  vpSM.push_back(new LLG08_EHO::EmbeddedModel(alpha, "Helix"));
+  vpSM.push_back(new LLG08_EHO::EmbeddedModel(alpha, "Other"));
+
+  Vdouble vrate, vproba;
+
+  for (unsigned int i = 0; i < 3; i++)
+  {
+    vproba.push_back((dynamic_cast<LLG08_EHO::EmbeddedModel*>(vpSM[i]))->getProportion());
+    vrate.push_back(vpSM[i]->getRate());
+  }
+
+  pmixmodel_.reset(new MixtureOfSubstitutionModels(alpha, vpSM, vproba, vrate));
+
+  string name, st;
+  ParameterList pl = pmixmodel_->getParameters();
+  for (size_t i = 0; i < pl.size(); i++)
+  {
+    name = pl[i].getName();
+    lParPmodel_.addParameter(Parameter(pl[i]));
+    st = pmixmodel_->getParameterNameWithoutNamespace(name);
+    mapParNamesFromPmodel_[name] = st;
+    addParameter_(new Parameter("LLG08_EHO." + st,
+                                pmixmodel_->getParameterValue(st),
+                                pmixmodel_->getParameter(st).hasConstraint() ? pmixmodel_->getParameter(st).getConstraint()->clone() : 0, true));
+  }
+
+  updateMatrices();
+}
+
+LLG08_EHO::LLG08_EHO(const LLG08_EHO& mod2) : AbstractBiblioMixedSubstitutionModel(mod2),
+  pmixmodel_(new MixtureOfSubstitutionModels(*mod2.pmixmodel_))
+{}
+
+LLG08_EHO& LLG08_EHO::operator=(const LLG08_EHO& mod2)
+{
+  AbstractBiblioMixedSubstitutionModel::operator=(mod2);
+
+  pmixmodel_.reset(new MixtureOfSubstitutionModels(*mod2.pmixmodel_));
+  return *this;
+}
+
+LLG08_EHO::~LLG08_EHO() {}
+
+/**************** sub model classes */ // ////////
+
+LLG08_EHO::EmbeddedModel::EmbeddedModel(const ProteicAlphabet* alpha, string name) :
+  AbstractParameterAliasable(name),
+  AbstractSubstitutionModel(alpha, name),
+  AbstractReversibleSubstitutionModel(alpha, name),
+  proportion_(1),
+  name_(name)
+{
+#include "__LLG08_EHOExchangeabilityCode"
+#include "__LLG08_EHOFrequenciesCode"
+#include "__LLG08_EHORatesProps"
+  updateMatrices();
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/LLG08_EHO.h b/src/Bpp/Phyl/Model/Protein/LLG08_EHO.h
new file mode 100644
index 0000000..844def4
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LLG08_EHO.h
@@ -0,0 +1,134 @@
+//
+// File: LLG08_EHO.h
+// Created by: Laurent Gueguen
+// Created on: jeudi 7 octobre 2010, à 21h 47
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _LLG08_EHO_H_
+#define _LLG08_EHO_H_
+
+#include "../MixtureOfSubstitutionModels.h"
+#include "ProteinSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+#include "../AbstractBiblioMixedSubstitutionModel.h"
+
+using namespace std;
+
+namespace bpp
+{
+/**
+ * @brief The Le et al  (2008) EH0 substitution model for proteins.
+ * @author Laurent Guéguen
+ *
+ * This model is a mixture of three models corresponding to
+ * extended/helix/other sites in proteins. The models are considered
+ * in this order.
+ *
+ *
+ * This model includes 4 parameters :
+ *
+ * - relrate1 is the relative rate of model of extended sites;
+ * - relrate2 is the relative rate of helix sites;
+ * - relproba1 is the proportion  of extended sites;
+ * - relproba2 is the ratio of the proportions of helix sites over the sum of
+ * the proportion of helix sites plus the proportion of other sites.
+ *
+ * Important: See the relation between these parameters and the rates
+ * and probabilities of the models in the description of
+ * MixtureOfSubstitutionModels class.
+ *
+ * Reference:
+ *
+ * Le S.Q., Lartillot N., Gascuel O. (2008) Phil. Trans. R. Soc. B 363:3965--3976.
+ */
+
+class LLG08_EHO :
+  public AbstractBiblioMixedSubstitutionModel
+{
+public:
+  class EmbeddedModel :
+    public virtual ProteinSubstitutionModel,
+    public AbstractReversibleSubstitutionModel
+  {
+private:
+    double proportion_;
+    string name_;
+
+public:
+    EmbeddedModel(const ProteicAlphabet* alpha, string name);
+    ~EmbeddedModel(){}
+    EmbeddedModel* clone() const { return new EmbeddedModel(*this); }
+    string getName() const { return name_;}
+    double getProportion() const { return proportion_;}
+  };
+
+private:
+  auto_ptr<MixtureOfSubstitutionModels> pmixmodel_;
+
+public:
+  /**
+   * @brief Build a  EH0 model, with original equilibrium frequencies, probabilities and rates.
+   *
+   * @param alpha A proteic alphabet.
+   *
+   */
+
+  LLG08_EHO(const ProteicAlphabet* alpha);
+
+  ~LLG08_EHO();
+
+  LLG08_EHO* clone() const { return new LLG08_EHO(*this); }
+
+  LLG08_EHO(const LLG08_EHO&);
+
+  LLG08_EHO& operator=(const LLG08_EHO&);
+
+  const SubstitutionModel& getModel() const { return *pmixmodel_.get(); }
+
+  const MixedSubstitutionModel& getMixedModel() const { return *pmixmodel_.get(); }
+
+  std::string getName() const { return "LLG08_EHO"; }
+  
+private:
+  SubstitutionModel& getModel() { return *pmixmodel_.get(); }
+
+  MixedSubstitutionModel& getMixedModel() { return *pmixmodel_.get(); }
+
+};
+} // end of namespace bpp.
+
+#endif  // _LLG08_EHO_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/LLG08_EX2.cpp b/src/Bpp/Phyl/Model/Protein/LLG08_EX2.cpp
new file mode 100644
index 0000000..e50520c
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LLG08_EX2.cpp
@@ -0,0 +1,116 @@
+//
+// File: LLG08_EX2.cpp
+// Created by:  Laurent Gueguen
+// Created on: mardi 12 octobre 2010, à 09h 43
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "LLG08_EX2.h"
+#include "../FrequenciesSet/ProteinFrequenciesSet.h"
+
+#include <Bpp/Numeric/Prob/SimpleDiscreteDistribution.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+LLG08_EX2::LLG08_EX2(const ProteicAlphabet* alpha) :
+  AbstractBiblioMixedSubstitutionModel("LLG08_EX2."),
+  pmixmodel_(0)
+{
+  // build the submodel
+
+  vector<SubstitutionModel*> vpSM;
+  vpSM.push_back(new LLG08_EX2::EmbeddedModel(alpha, "Buried"));
+  vpSM.push_back(new LLG08_EX2::EmbeddedModel(alpha, "Exposed"));
+
+  Vdouble vrate, vproba;
+
+  for (unsigned int i = 0; i < vpSM.size(); i++)
+  {
+    vproba.push_back((dynamic_cast<LLG08_EX2::EmbeddedModel*>(vpSM[i]))->getProportion());
+    vrate.push_back(vpSM[i]->getRate());
+  }
+
+  pmixmodel_.reset(new MixtureOfSubstitutionModels(alpha, vpSM, vproba, vrate));
+
+  string name, st;
+  ParameterList pl = pmixmodel_->getParameters();
+  for (size_t i = 0; i < pl.size(); i++)
+  {
+    name = pl[i].getName();
+    lParPmodel_.addParameter(Parameter(pl[i]));
+    st = pmixmodel_->getParameterNameWithoutNamespace(name);
+    mapParNamesFromPmodel_[name] = st;
+    addParameter_(new Parameter("LLG08_EX2." + st,
+                                pmixmodel_->getParameterValue(st),
+                                pmixmodel_->getParameter(st).hasConstraint() ? pmixmodel_->getParameter(st).getConstraint()->clone() : 0, true));
+  }
+
+  updateMatrices();
+}
+
+LLG08_EX2::LLG08_EX2(const LLG08_EX2& mod2) : AbstractBiblioMixedSubstitutionModel(mod2),
+  pmixmodel_(new MixtureOfSubstitutionModels(*mod2.pmixmodel_))
+{}
+
+LLG08_EX2& LLG08_EX2::operator=(const LLG08_EX2& mod2)
+{
+  AbstractBiblioMixedSubstitutionModel::operator=(mod2);
+
+  pmixmodel_.reset(new MixtureOfSubstitutionModels(*mod2.pmixmodel_));
+
+  return *this;
+}
+
+LLG08_EX2::~LLG08_EX2() {}
+
+/**************** sub model classes */ // ////////
+
+LLG08_EX2::EmbeddedModel::EmbeddedModel(const ProteicAlphabet* alpha, string name) :
+  AbstractParameterAliasable(name),
+  AbstractSubstitutionModel(alpha, name),
+  AbstractReversibleSubstitutionModel(alpha, name),
+  proportion_(1),
+  name_(name)
+{
+#include "__LLG08_EX2ExchangeabilityCode"
+#include "__LLG08_EX2FrequenciesCode"
+#include "__LLG08_EX2RatesProps"
+  updateMatrices();
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/LLG08_EX2.h b/src/Bpp/Phyl/Model/Protein/LLG08_EX2.h
new file mode 100644
index 0000000..ec50265
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LLG08_EX2.h
@@ -0,0 +1,130 @@
+//
+// File: LLG08_EX2.h
+// Created by: Laurent Gueguen
+// Created on: mardi 12 octobre 2010, à 09h 42
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _LLG08_EX2_H_
+#define _LLG08_EX2_H_
+
+#include "../MixtureOfSubstitutionModels.h"
+#include "ProteinSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+#include "../AbstractBiblioMixedSubstitutionModel.h"
+
+using namespace std;
+
+namespace bpp
+{
+/**
+ * @brief The Le et al  (2008) EX2 substitution model for proteins.
+ * @author Laurent Guéguen
+ *
+ * This model is a mixture of three models corresponding to
+ * buried/exposed sites in proteins.
+ *
+ *
+ * This model includes 2 parameters :
+ *
+ * - relrate1 is the relative rate of model of buried sites;
+ * - relproba1 is the proportion of buried sites;
+ *
+ * Important: See the relation between these parameters and the
+ * rates and probabilities of the models in the description of
+ * MixtureOfSubstitutionModels class.
+ *
+ * Reference:
+ *
+ * Le S.Q., Lartillot N., Gascuel O. (2008) Phil. Trans. R. Soc. B 363:3965--3976.
+ */
+
+class LLG08_EX2 :
+  public AbstractBiblioMixedSubstitutionModel
+{
+public:
+  class EmbeddedModel :
+    public virtual ProteinSubstitutionModel,
+    public AbstractReversibleSubstitutionModel
+  {
+private:
+    double proportion_;
+    string name_;
+
+public:
+    EmbeddedModel(const ProteicAlphabet* alpha, string name);
+    ~EmbeddedModel(){}
+    EmbeddedModel* clone() const { return new EmbeddedModel(*this); }
+    string getName() const { return name_;}
+    double getProportion() const { return proportion_;}
+  };
+
+private:
+  std::auto_ptr<MixtureOfSubstitutionModels> pmixmodel_;
+
+public:
+  /**
+   * @brief Build a  EX2 model, with original equilibrium frequencies, probabilities and rates.
+   *
+   * @param alpha A proteic alphabet.
+   *
+   */
+
+  LLG08_EX2(const ProteicAlphabet* alpha);
+
+  ~LLG08_EX2();
+
+  LLG08_EX2* clone() const { return new LLG08_EX2(*this); }
+
+  LLG08_EX2(const LLG08_EX2&);
+
+  LLG08_EX2& operator=(const LLG08_EX2&);
+
+  const SubstitutionModel& getModel() const { return *pmixmodel_.get(); }
+
+  const MixedSubstitutionModel& getMixedModel() const { return *pmixmodel_.get(); }
+
+  std::string getName() const { return "LLG08_EX2"; }
+  
+private:
+  SubstitutionModel& getModel() { return *pmixmodel_.get(); }
+
+  MixedSubstitutionModel& getMixedModel() { return *pmixmodel_.get(); }
+
+};
+} // end of namespace bpp.
+
+#endif  // _LLG08_EX2_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/LLG08_EX3.cpp b/src/Bpp/Phyl/Model/Protein/LLG08_EX3.cpp
new file mode 100644
index 0000000..efc7ee7
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LLG08_EX3.cpp
@@ -0,0 +1,117 @@
+//
+// File: LLG08_EX3.cpp
+// Created by:  Laurent Gueguen
+// Created on: jeudi 21 octobre 2010, à 13h 50
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "LLG08_EX3.h"
+#include "../FrequenciesSet/ProteinFrequenciesSet.h"
+
+#include <Bpp/Numeric/Prob/SimpleDiscreteDistribution.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+LLG08_EX3::LLG08_EX3(const ProteicAlphabet* alpha) :
+  AbstractBiblioMixedSubstitutionModel("LLG08_EX3."),
+  pmixmodel_(0)
+{
+  // build the submodel
+
+  vector<SubstitutionModel*> vpSM;
+  vpSM.push_back(new LLG08_EX3::EmbeddedModel(alpha, "Buried"));
+  vpSM.push_back(new LLG08_EX3::EmbeddedModel(alpha, "Intermediate"));
+  vpSM.push_back(new LLG08_EX3::EmbeddedModel(alpha, "HExposed"));
+
+  Vdouble vrate, vproba;
+
+  for (unsigned int i = 0; i < vpSM.size(); i++)
+  {
+    vproba.push_back((dynamic_cast<LLG08_EX3::EmbeddedModel*>(vpSM[i]))->getProportion());
+    vrate.push_back(vpSM[i]->getRate());
+  }
+
+  pmixmodel_.reset(new MixtureOfSubstitutionModels(alpha, vpSM, vproba, vrate));
+
+  string name, st;
+  ParameterList pl = pmixmodel_->getParameters();
+  for (size_t i = 0; i < pl.size(); i++)
+  {
+    name = pl[i].getName();
+    lParPmodel_.addParameter(Parameter(pl[i]));
+    st = pmixmodel_->getParameterNameWithoutNamespace(name);
+    mapParNamesFromPmodel_[name] = st;
+    addParameter_(new Parameter("LLG08_EX3." + st,
+                            pmixmodel_->getParameterValue(st),
+                            pmixmodel_->getParameter(st).hasConstraint() ? pmixmodel_->getParameter(st).getConstraint()->clone() : 0, true));
+  }
+
+  updateMatrices();
+}
+
+LLG08_EX3::LLG08_EX3(const LLG08_EX3& mod2) : AbstractBiblioMixedSubstitutionModel(mod2),
+  pmixmodel_(new MixtureOfSubstitutionModels(*mod2.pmixmodel_))
+{}
+
+LLG08_EX3& LLG08_EX3::operator=(const LLG08_EX3& mod2)
+{
+  AbstractBiblioMixedSubstitutionModel::operator=(mod2);
+
+  pmixmodel_.reset(new MixtureOfSubstitutionModels(*mod2.pmixmodel_));
+
+  return *this;
+}
+
+LLG08_EX3::~LLG08_EX3() {}
+
+/**************** sub model classes */ // ////////
+
+LLG08_EX3::EmbeddedModel::EmbeddedModel(const ProteicAlphabet* alpha, string name) :
+  AbstractParameterAliasable(name),
+  AbstractSubstitutionModel(alpha, name),
+  AbstractReversibleSubstitutionModel(alpha, name),
+  proportion_(1),
+  name_(name)
+{
+#include "__LLG08_EX3ExchangeabilityCode"
+#include "__LLG08_EX3FrequenciesCode"
+#include "__LLG08_EX3RatesProps"
+  updateMatrices();
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/LLG08_EX3.h b/src/Bpp/Phyl/Model/Protein/LLG08_EX3.h
new file mode 100644
index 0000000..8b50333
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LLG08_EX3.h
@@ -0,0 +1,135 @@
+//
+// File: LLG08_EX3.h
+// Created by: Laurent Gueguen
+// Created on: jeudi 21 octobre 2010, à 13h 50
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _LLG08_EX3_H_
+#define _LLG08_EX3_H_
+
+#include "../MixtureOfSubstitutionModels.h"
+#include "ProteinSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+#include "../AbstractBiblioMixedSubstitutionModel.h"
+
+using namespace std;
+
+namespace bpp
+{
+/**
+ * @brief The Le et al  (2008) EX3 substitution model for proteins.
+ * @author Laurent Guéguen
+ *
+ * This model is a mixture of three models corresponding to
+ * buried/intermediate/highly exposed sites in proteins. The models
+ * are considered in this order.
+ *
+ *
+ * This model includes 4 parameters :
+ *
+ * - relrate1 is the relative rate of model of buried sites;
+ * - relrate2 is the relative rate of intermediate sites;
+ * - relproba1 is the proportion  of buried sites;
+ * - relproba2 is the ratio of the proportions of intermediate sites
+ * over the sum of the proportion of intermediate sites plus the
+ * proportion of highly exposed sites.
+ *
+ * Important: See the relation between these parameters and the
+ * rates and probabilities of the models in the description of
+ * MixtureOfSubstitutionModels class.
+ *
+ * Reference:
+ *
+ * Le S.Q., Lartillot N., Gascuel O. (2008) Phil. Trans. R. Soc. B 363:3965--3976.
+ */
+
+class LLG08_EX3 :
+  public AbstractBiblioMixedSubstitutionModel
+{
+public:
+  class EmbeddedModel :
+    public virtual ProteinSubstitutionModel,
+    public AbstractReversibleSubstitutionModel
+  {
+private:
+    double proportion_;
+    string name_;
+
+public:
+    EmbeddedModel(const ProteicAlphabet* alpha, string name);
+    ~EmbeddedModel(){}
+    EmbeddedModel* clone() const { return new EmbeddedModel(*this); }
+    string getName() const { return name_;}
+    double getProportion() const { return proportion_;}
+  };
+
+private:
+  std::auto_ptr<MixtureOfSubstitutionModels> pmixmodel_;
+
+public:
+  /**
+   * @brief Build a  EX3 model, with original equilibrium frequencies, probabilities and rates.
+   *
+   * @param alpha A proteic alphabet.
+   *
+   */
+
+  LLG08_EX3(const ProteicAlphabet* alpha);
+
+  ~LLG08_EX3();
+
+  LLG08_EX3* clone() const { return new LLG08_EX3(*this); }
+
+  LLG08_EX3(const LLG08_EX3&);
+
+  LLG08_EX3& operator=(const LLG08_EX3&);
+
+  const SubstitutionModel& getModel() const { return *pmixmodel_.get(); }
+
+  const MixedSubstitutionModel& getMixedModel() const { return *pmixmodel_.get(); }
+
+  std::string getName() const { return "LLG08_EX3"; }
+  
+private:
+  SubstitutionModel& getModel() { return *pmixmodel_.get(); }
+
+  MixedSubstitutionModel& getMixedModel() { return *pmixmodel_.get(); }
+
+};
+} // end of namespace bpp.
+
+#endif  // _LLG08_EX3_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/LLG08_UL2.cpp b/src/Bpp/Phyl/Model/Protein/LLG08_UL2.cpp
new file mode 100644
index 0000000..482963c
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LLG08_UL2.cpp
@@ -0,0 +1,116 @@
+//
+// File: LLG08_UL2.cpp
+// Created by:  Laurent Gueguen
+// Created on: jeudi 21 octobre 2010, à 14h 28
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "LLG08_UL2.h"
+#include "../FrequenciesSet/ProteinFrequenciesSet.h"
+
+#include <Bpp/Numeric/Prob/SimpleDiscreteDistribution.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+LLG08_UL2::LLG08_UL2(const ProteicAlphabet* alpha) :
+  AbstractBiblioMixedSubstitutionModel("LLG08_UL2."),
+  pmixmodel_(0)
+{
+  // build the submodel
+
+  vector<SubstitutionModel*> vpSM;
+  vpSM.push_back(new LLG08_UL2::EmbeddedModel(alpha, "M1"));
+  vpSM.push_back(new LLG08_UL2::EmbeddedModel(alpha, "M2"));
+
+  Vdouble vrate, vproba;
+
+  for (unsigned int i = 0; i < vpSM.size(); i++)
+  {
+    vproba.push_back((dynamic_cast<LLG08_UL2::EmbeddedModel*>(vpSM[i]))->getProportion());
+    vrate.push_back(vpSM[i]->getRate());
+  }
+
+  pmixmodel_.reset(new MixtureOfSubstitutionModels(alpha, vpSM, vproba, vrate));
+
+  string name, st;
+  ParameterList pl = pmixmodel_->getParameters();
+  for (size_t i = 0; i < pl.size(); i++)
+  {
+    name = pl[i].getName();
+    lParPmodel_.addParameter(Parameter(pl[i]));
+    st = pmixmodel_->getParameterNameWithoutNamespace(name);
+    mapParNamesFromPmodel_[name] = st;
+    addParameter_(new Parameter("LLG08_UL2." + st,
+                            pmixmodel_->getParameterValue(st),
+                            pmixmodel_->getParameter(st).hasConstraint() ? pmixmodel_->getParameter(st).getConstraint()->clone() : 0, true));
+  }
+
+  updateMatrices();
+}
+
+LLG08_UL2::LLG08_UL2(const LLG08_UL2& mod2) : AbstractBiblioMixedSubstitutionModel(mod2),
+  pmixmodel_(new MixtureOfSubstitutionModels(*mod2.pmixmodel_))
+{}
+
+LLG08_UL2& LLG08_UL2::operator=(const LLG08_UL2& mod2)
+{
+  AbstractBiblioMixedSubstitutionModel::operator=(mod2);
+
+  pmixmodel_.reset(new MixtureOfSubstitutionModels(*mod2.pmixmodel_));
+
+  return *this;
+}
+
+LLG08_UL2::~LLG08_UL2() {}
+
+/**************** sub model classes */ // ////////
+
+LLG08_UL2::EmbeddedModel::EmbeddedModel(const ProteicAlphabet* alpha, string name) :
+  AbstractParameterAliasable(name),
+  AbstractSubstitutionModel(alpha, name),
+  AbstractReversibleSubstitutionModel(alpha, name),
+  proportion_(1),
+  name_(name)
+{
+#include "__LLG08_UL2ExchangeabilityCode"
+#include "__LLG08_UL2FrequenciesCode"
+#include "__LLG08_UL2RatesProps"
+  updateMatrices();
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/LLG08_UL2.h b/src/Bpp/Phyl/Model/Protein/LLG08_UL2.h
new file mode 100644
index 0000000..58e6a9c
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LLG08_UL2.h
@@ -0,0 +1,130 @@
+//
+// File: LLG08_UL2.h
+// Created by: Laurent Gueguen
+// Created on: jeudi 21 octobre 2010, à 14h 29
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _LLG08_UL2_H_
+#define _LLG08_UL2_H_
+
+#include "../MixtureOfSubstitutionModels.h"
+#include "ProteinSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+#include "../AbstractBiblioMixedSubstitutionModel.h"
+
+using namespace std;
+
+namespace bpp
+{
+/**
+ * @brief The Le et al  (2008) UL2 substitution model for proteins.
+ * @author Laurent Guéguen
+ *
+ * This model is a mixture of two models built by an unsupervised
+ * method (see ref). The submodels are called M1 & M2.
+ *
+ *
+ * This model includes 2 parameters :
+ *
+ * - relrate1 is the relative rate of model of M1;
+ * - relproba1 is the proportion of model M1;
+ *
+ * Important: See the relation between these parameters and the
+ * rates and probabilities of the models in the description of
+ * MixtureOfSubstitutionModels class.
+ *
+ * Reference:
+ *
+ * Le S.Q., Lartillot N., Gascuel O. (2008) Phil. Trans. R. Soc. B 363:3965--3976.
+ */
+
+class LLG08_UL2 :
+  public AbstractBiblioMixedSubstitutionModel
+{
+public:
+  class EmbeddedModel :
+    public virtual ProteinSubstitutionModel,
+    public AbstractReversibleSubstitutionModel
+  {
+private:
+    double proportion_;
+    string name_;
+
+public:
+    EmbeddedModel(const ProteicAlphabet* alpha, string name);
+    ~EmbeddedModel(){}
+    EmbeddedModel* clone() const { return new EmbeddedModel(*this); }
+    string getName() const { return name_;}
+    double getProportion() const { return proportion_;}
+  };
+
+private:
+  std::auto_ptr<MixtureOfSubstitutionModels> pmixmodel_;
+
+public:
+  /**
+   * @brief Build a  UL2 model, with original equilibrium frequencies, probabilities and rates.
+   *
+   * @param alpha A proteic alphabet.
+   *
+   */
+
+  LLG08_UL2(const ProteicAlphabet* alpha);
+
+  ~LLG08_UL2();
+
+  LLG08_UL2* clone() const { return new LLG08_UL2(*this); }
+
+  LLG08_UL2(const LLG08_UL2&);
+
+  LLG08_UL2& operator=(const LLG08_UL2&);
+
+  const SubstitutionModel& getModel() const { return *pmixmodel_.get(); }
+
+  const MixedSubstitutionModel& getMixedModel() const { return *pmixmodel_.get(); }
+
+  std::string getName() const { return "LLG08_UL2"; }
+  
+private:
+  SubstitutionModel& getModel() { return *pmixmodel_.get(); }
+
+  MixedSubstitutionModel& getMixedModel() { return *pmixmodel_.get(); }
+
+};
+} // end of namespace bpp.
+
+#endif  // _LLG08_UL2_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/LLG08_UL3.cpp b/src/Bpp/Phyl/Model/Protein/LLG08_UL3.cpp
new file mode 100644
index 0000000..13f005e
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LLG08_UL3.cpp
@@ -0,0 +1,117 @@
+//
+// File: LLG08_UL3.cpp
+// Created by:  Laurent Gueguen
+// Created on: jeudi 21 octobre 2010, à 14h 35
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "LLG08_UL3.h"
+#include "../FrequenciesSet/ProteinFrequenciesSet.h"
+
+#include <Bpp/Numeric/Prob/SimpleDiscreteDistribution.h>
+
+using namespace bpp;
+
+using namespace std;
+
+/******************************************************************************/
+
+LLG08_UL3::LLG08_UL3(const ProteicAlphabet* alpha) :
+  AbstractBiblioMixedSubstitutionModel("LLG08_UL3."),
+  pmixmodel_(0)
+{
+  // build the submodel
+
+  vector<SubstitutionModel*> vpSM;
+  vpSM.push_back(new LLG08_UL3::EmbeddedModel(alpha, "Q1"));
+  vpSM.push_back(new LLG08_UL3::EmbeddedModel(alpha, "Q2"));
+  vpSM.push_back(new LLG08_UL3::EmbeddedModel(alpha, "Q3"));
+
+  Vdouble vrate, vproba;
+
+  for (size_t i = 0; i < vpSM.size(); i++)
+  {
+    vproba.push_back((dynamic_cast<LLG08_UL3::EmbeddedModel*>(vpSM[i]))->getProportion());
+    vrate.push_back(vpSM[i]->getRate());
+  }
+
+  pmixmodel_.reset(new MixtureOfSubstitutionModels(alpha, vpSM, vproba, vrate));
+
+  string name, st;
+  ParameterList pl = pmixmodel_->getParameters();
+  for (size_t i = 0; i < pl.size(); i++)
+  {
+    name = pl[i].getName();
+    lParPmodel_.addParameter(Parameter(pl[i]));
+    st = pmixmodel_->getParameterNameWithoutNamespace(name);
+    mapParNamesFromPmodel_[name] = st;
+    addParameter_(new Parameter("LLG08_UL3." + st,
+                            pmixmodel_->getParameterValue(st),
+                            pmixmodel_->getParameter(st).hasConstraint() ? pmixmodel_->getParameter(st).getConstraint()->clone() : 0, true));
+  }
+
+  updateMatrices();
+}
+
+LLG08_UL3::LLG08_UL3(const LLG08_UL3& mod2) : AbstractBiblioMixedSubstitutionModel(mod2),
+  pmixmodel_(new MixtureOfSubstitutionModels(*mod2.pmixmodel_))
+{}
+
+LLG08_UL3& LLG08_UL3::operator=(const LLG08_UL3& mod2)
+{
+  AbstractBiblioMixedSubstitutionModel::operator=(mod2);
+
+  pmixmodel_.reset(new MixtureOfSubstitutionModels(*mod2.pmixmodel_));
+
+  return *this;
+}
+
+LLG08_UL3::~LLG08_UL3() {}
+
+/**************** sub model classes */ // ////////
+
+LLG08_UL3::EmbeddedModel::EmbeddedModel(const ProteicAlphabet* alpha, string name) :
+  AbstractParameterAliasable(name),
+  AbstractSubstitutionModel(alpha, name),
+  AbstractReversibleSubstitutionModel(alpha, name),
+  proportion_(1),
+  name_(name)
+{
+#include "__LLG08_UL3ExchangeabilityCode"
+#include "__LLG08_UL3FrequenciesCode"
+#include "__LLG08_UL3RatesProps"
+  updateMatrices();
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/LLG08_UL3.h b/src/Bpp/Phyl/Model/Protein/LLG08_UL3.h
new file mode 100644
index 0000000..1ccce18
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/LLG08_UL3.h
@@ -0,0 +1,134 @@
+//
+// File: LLG08_UL3.h
+// Created by: Laurent Gueguen
+// Created on: jeudi 21 octobre 2010, à 13h 50
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _LLG08_UL3_H_
+#define _LLG08_UL3_H_
+
+#include "../MixtureOfSubstitutionModels.h"
+#include "ProteinSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+#include "../AbstractBiblioMixedSubstitutionModel.h"
+
+using namespace std;
+
+namespace bpp
+{
+/**
+ * @brief The Le et al  (2008) UL3 substitution model for proteins.
+ * @author Laurent Guéguen
+ *
+ * This model is a mixture of three models built by an unsupervised
+ * method (see ref). The submodels are called Q1, Q2 & Q3.
+ *
+ *
+ * This model includes 4 parameters :
+ *
+ * - relrate1 is the relative rate of model Q1;
+ * - relrate2 is the relative rate of model Q2;
+ * - relproba1 is the proportion  of model Q1;
+ * - relproba2 is the ratio of the proportions of model Q2 over the
+ * sum of the proportion of model Q2 plus the proportion of model
+ * Q3.
+ *
+ * Important: See the relation between these parameters and the
+ * rates and probabilities of the models in the description of
+ * MixtureOfSubstitutionModels class.
+ *
+ * Reference:
+ *
+ * Le S.Q., Lartillot N., Gascuel O. (2008) Phil. Trans. R. Soc. B 363:3965--3976.
+ */
+
+class LLG08_UL3 :
+  public AbstractBiblioMixedSubstitutionModel
+{
+public:
+  class EmbeddedModel :
+    public virtual ProteinSubstitutionModel,
+    public AbstractReversibleSubstitutionModel
+  {
+private:
+    double proportion_;
+    string name_;
+
+public:
+    EmbeddedModel(const ProteicAlphabet* alpha, string name);
+    ~EmbeddedModel(){}
+    EmbeddedModel* clone() const { return new EmbeddedModel(*this); }
+    string getName() const { return name_;}
+    double getProportion() const { return proportion_;}
+  };
+
+private:
+  std::auto_ptr<MixtureOfSubstitutionModels> pmixmodel_;
+
+public:
+  /**
+   * @brief Build a  UL3 model, with original equilibrium frequencies, probabilities and rates.
+   *
+   * @param alpha A proteic alphabet.
+   *
+   */
+
+  LLG08_UL3(const ProteicAlphabet* alpha);
+
+  ~LLG08_UL3();
+
+  LLG08_UL3* clone() const { return new LLG08_UL3(*this); }
+
+  LLG08_UL3(const LLG08_UL3&);
+
+  LLG08_UL3& operator=(const LLG08_UL3&);
+
+  const SubstitutionModel& getModel() const { return *pmixmodel_.get(); }
+
+  const MixedSubstitutionModel& getMixedModel() const { return *pmixmodel_.get(); }
+
+  std::string getName() const { return "LLG08_UL3"; }
+  
+private:
+  SubstitutionModel& getModel() { return *pmixmodel_.get(); }
+
+  MixedSubstitutionModel& getMixedModel() { return *pmixmodel_.get(); }
+
+};
+} // end of namespace bpp.
+
+#endif  // _LLG08_UL3_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/ProteinSubstitutionModel.h b/src/Bpp/Phyl/Model/Protein/ProteinSubstitutionModel.h
new file mode 100755
index 0000000..ad4c40c
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/ProteinSubstitutionModel.h
@@ -0,0 +1,75 @@
+//
+// File: ProteinSubstitutionModel.h
+// Created by: Julien Dutheil
+// Created on: Wed Jan 21 13:59:18 2004
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _PROTEINSUBSTITUTIONMODEL_H_
+#define _PROTEINSUBSTITUTIONMODEL_H_
+
+#include "../SubstitutionModel.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/ProteicAlphabet.h>
+
+namespace bpp
+{
+
+/**
+ * @brief Specialized interface for protein substitution model.
+ */
+class ProteinSubstitutionModel:
+  public virtual SubstitutionModel
+{
+	public:
+		virtual ~ProteinSubstitutionModel() {}
+
+#ifndef NO_VIRTUAL_COV
+    ProteinSubstitutionModel*
+#else
+    Clonable*
+#endif
+    clone() const = 0;
+		
+  public:
+    size_t getNumberOfStates() const { return 20; };
+
+};
+
+} //end of namespace bpp.
+
+#endif	//_PROTEINSUBSTITUTIONMODEL_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/UserProteinSubstitutionModel.cpp b/src/Bpp/Phyl/Model/Protein/UserProteinSubstitutionModel.cpp
new file mode 100755
index 0000000..6ae12e1
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/UserProteinSubstitutionModel.cpp
@@ -0,0 +1,167 @@
+//
+// File: UserProteinSubstitutionModel.cpp
+// Created by: Julien Dutheil
+// Created on: Wed Aug 26 16:27 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "UserProteinSubstitutionModel.h"
+
+#include <Bpp/Io/FileTools.h>
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Text/StringTokenizer.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+//From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+#include <fstream>
+#include <string>
+
+using namespace std;
+
+/******************************************************************************/
+
+UserProteinSubstitutionModel::UserProteinSubstitutionModel(
+    const ProteicAlphabet* alpha, const std::string& path, const std::string& prefix) : 
+  AbstractParameterAliasable(prefix),
+  AbstractSubstitutionModel(alpha, prefix),
+  AbstractReversibleSubstitutionModel(alpha, prefix),
+  path_(path),
+  freqSet_(0)
+{
+  readFromFile();
+  freqSet_ = new FixedProteinFrequenciesSet(alpha, freq_);
+  updateMatrices();  
+}
+
+UserProteinSubstitutionModel::UserProteinSubstitutionModel(
+    const ProteicAlphabet* alpha, const std::string& path,
+    ProteinFrequenciesSet* freqSet, const std::string& prefix,
+    bool initFreqs) : 
+  AbstractParameterAliasable(prefix),
+  AbstractSubstitutionModel(alpha, prefix),
+  AbstractReversibleSubstitutionModel(alpha, prefix),
+  path_(path),
+  freqSet_(freqSet)
+{
+  readFromFile();
+  if (initFreqs) freqSet->setFrequencies(freq_);
+  else freq_ = freqSet_->getFrequencies();
+  freqSet_->setNamespace(prefix+freqSet_->getNamespace());
+  addParameters_(freqSet_->getParameters());
+  updateMatrices();  
+}
+
+/******************************************************************************/
+
+std::string UserProteinSubstitutionModel::getName() const
+{
+  if (TextTools::hasSubstring(freqSet_->getNamespace(), "+F.") )
+    return "Empirical+F"; 
+  else  
+    return "Empirical";
+}
+
+/******************************************************************************/
+
+void UserProteinSubstitutionModel::readFromFile()
+{
+  ifstream in(path_.c_str(), ios::in);
+  //Read exchangeability matrix:
+  for (unsigned int i = 1; i < 20; i++)
+  {
+    string line = FileTools::getNextLine(in);
+    StringTokenizer st(line);
+    for(unsigned int j = 0; j < i; j++) {
+      double s = TextTools::toDouble(st.nextToken());
+      exchangeability_(i,j) = exchangeability_(j,i) = s;
+    }
+  }
+  //Read frequencies:
+  unsigned int fCount = 0;
+  while (in && fCount < 20)
+  {
+    string line = FileTools::getNextLine(in);
+    StringTokenizer st(line);
+    while(st.hasMoreToken() && fCount < 20)
+    {
+      freq_[fCount] = TextTools::toDouble(st.nextToken());
+      fCount++;
+    }
+  }
+  double sf = VectorTools::sum(freq_);
+  if (sf - 1 > 0.000001)
+  {
+    ApplicationTools::displayMessage("WARNING!!! Frequencies sum to " + TextTools::toString(sf) + ", frequencies have been scaled.");
+    sf *= 1./sf;
+  }
+
+  //Now build diagonal of the exchangeability matrix:
+  for (unsigned int i = 0; i < 20; i++)
+  {
+    double sum = 0;
+    for(unsigned int j = 0; j < 20; j++)
+    {
+      if(j!=i) sum += exchangeability_(i,j);
+    }
+    exchangeability_(i,i) = -sum;
+  }
+
+  //Closing stream:
+  in.close();
+}
+
+/******************************************************************************/
+
+void UserProteinSubstitutionModel::setFreqFromData(const SequenceContainer& data)
+{
+  std::map<int, double> freqs;
+  SequenceContainerTools::getFrequencies(data, freqs);
+  double t = 0;
+  for (unsigned int i = 0; i < size_; i++) t += freqs[i];
+  for (unsigned int i = 0; i < size_; i++) freq_[i] = freqs[i] / t;
+  freqSet_->setFrequencies(freq_);
+  //Update parametrers and re-compute generator and eigen values:
+  matchParametersValues(freqSet_->getParameters());
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Protein/UserProteinSubstitutionModel.h b/src/Bpp/Phyl/Model/Protein/UserProteinSubstitutionModel.h
new file mode 100755
index 0000000..c9316f4
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/UserProteinSubstitutionModel.h
@@ -0,0 +1,161 @@
+//
+// File: UserProteinSubstitutionModel.h
+// Created by: Julien Dutheil
+// Created on: Wed Aug 26 16:27 2005
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _USERPROTEINSUBSTITUTIONMODEL_H_
+#define _USERPROTEINSUBSTITUTIONMODEL_H_
+
+#include "ProteinSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+#include "../FrequenciesSet/ProteinFrequenciesSet.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/ProteicAlphabet.h>
+
+// From the STL:
+#include <string>
+
+namespace bpp
+{
+
+  /**
+   * @brief Build an empirical protein substitution model from a file.
+   * 
+   * The file must follow PAML's format, and contain the exchangeabilities components (\f$S_{i,j}\f$)
+   * and all equilibrium frequencies (\f$\pi_{i}\f$).
+   * The generator is build so that \f$Q_{i,j} = \pi_i . S_{i,j}\f$, and is normalized
+   * so that \f$\sum_i Q_{i,i} \times \pi_i = -1\f$.
+   */
+  class UserProteinSubstitutionModel:
+    public virtual ProteinSubstitutionModel,
+    public AbstractReversibleSubstitutionModel
+  {
+  private:
+    std::string path_;
+    ProteinFrequenciesSet* freqSet_;
+  
+  public:
+    /**
+     * @brief Build a protein model from a PAML file, with original equilibrium frequencies.
+     *
+     * @param alpha A proteic alphabet.
+     * @param path The path toward the file to parse.
+     * @param prefix The parameter namespace to use.
+     */
+    UserProteinSubstitutionModel(
+                                 const ProteicAlphabet* alpha,
+                                 const std::string& path,
+                                 const std::string& prefix);
+
+    /**
+     * @brief Build a protein model from a PAML file, with special equilibrium frequencies.
+     *
+     * @param alpha A proteic alphabet.
+     * @param freqSet A pointer toward a protein frequencies set, which will be owned by this instance.
+     * @param path The path toward the file to parse.
+     * @param prefix The parameter namespace to use.
+     * @param initFreqs Tell if the frequency set should be initialized with the original JTT92 values.
+     * Otherwise, the values of the set will be used.
+     */
+    UserProteinSubstitutionModel(
+                                 const ProteicAlphabet* alpha,
+                                 const std::string& path,
+                                 ProteinFrequenciesSet* freqSet,
+                                 const std::string& prefix,
+                                 bool initFreqs = false
+                                 );
+
+    UserProteinSubstitutionModel(const UserProteinSubstitutionModel& model) :
+      AbstractParameterAliasable(model),
+      AbstractSubstitutionModel(model),
+      AbstractReversibleSubstitutionModel(model),
+      path_(model.path_),
+      freqSet_(dynamic_cast<ProteinFrequenciesSet*>(model.freqSet_->clone()))
+    {}
+ 
+    UserProteinSubstitutionModel& operator=(const UserProteinSubstitutionModel& model)
+    {
+      AbstractParameterAliasable::operator=(model);
+      AbstractSubstitutionModel::operator=(model);
+      AbstractReversibleSubstitutionModel::operator=(model);
+      path_ = model.path_;
+      freqSet_ = dynamic_cast<ProteinFrequenciesSet*>(model.freqSet_->clone());
+      return *this;
+    }
+ 
+    virtual ~UserProteinSubstitutionModel() { delete freqSet_; }
+
+#ifndef NO_VIRTUAL_COV
+    UserProteinSubstitutionModel*
+#else
+    Clonable*
+#endif
+    clone() const { return new UserProteinSubstitutionModel(*this); }
+      
+  public:
+    std::string getName() const;
+    const std::string& getPath() const { return path_; }
+
+    void fireParameterChanged(const ParameterList& parameters)
+    {
+      freqSet_->matchParametersValues(parameters);
+      freq_ = freqSet_->getFrequencies();
+      AbstractReversibleSubstitutionModel::fireParameterChanged(parameters);
+    }
+
+    void setFrequenciesSet(const ProteinFrequenciesSet& freqSet)
+    {
+      delete freqSet_;
+      freqSet_ = dynamic_cast<ProteinFrequenciesSet*>(freqSet.clone());
+      resetParameters_();
+      addParameters_(freqSet_->getParameters());
+    }
+
+    const FrequenciesSet* getFrequenciesSet() const { return freqSet_; }
+
+    void setFreqFromData(const SequenceContainer& data);
+
+  protected:
+    void readFromFile();
+
+  };
+
+} //end of namespace bpp.
+
+#endif //_USERPROTEINSUBSTITUTIONMODEL_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/WAG01.cpp b/src/Bpp/Phyl/Model/Protein/WAG01.cpp
new file mode 100644
index 0000000..ef148d7
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/WAG01.cpp
@@ -0,0 +1,92 @@
+//
+// File: WAG01.cpp
+// Created by: Laurent Gueguen
+// Created on: mardi 28 septembre 2010, à 14h 43
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "WAG01.h"
+
+//From SeqLib:
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+WAG01::WAG01(const ProteicAlphabet* alpha) :
+  AbstractParameterAliasable("WAG01."),
+  AbstractSubstitutionModel(alpha, "WAG01."),
+  AbstractReversibleSubstitutionModel(alpha, "WAG01."),
+  freqSet_(0)
+{
+  #include "__WAG01ExchangeabilityCode"
+  #include "__WAG01FrequenciesCode"
+  freqSet_ = new FixedProteinFrequenciesSet(alpha, freq_);
+  updateMatrices();  
+}
+
+WAG01::WAG01(const ProteicAlphabet* alpha, ProteinFrequenciesSet* freqSet, bool initFreqs) :
+  AbstractParameterAliasable("WAG01+F."),
+  AbstractSubstitutionModel(alpha, "WAG01+F."),
+  AbstractReversibleSubstitutionModel(alpha, "WAG01+F."),
+  freqSet_(freqSet)
+{
+  #include "__WAG01ExchangeabilityCode"
+  #include "__WAG01FrequenciesCode"
+  if (initFreqs) freqSet_->setFrequencies(freq_);
+  else freq_ = freqSet_->getFrequencies();
+  freqSet_->setNamespace("WAG01+F."+freqSet_->getNamespace());
+  addParameters_(freqSet_->getParameters());
+  updateMatrices();  
+}
+
+/******************************************************************************/
+
+void WAG01::setFreqFromData(const SequenceContainer& data)
+{
+  std::map<int, double> freqs;
+  SequenceContainerTools::getFrequencies(data, freqs);
+  double t = 0;
+  for (size_t i = 0; i < size_; i++) t += freqs[static_cast<int>(i)];
+  for (size_t i = 0; i < size_; i++) freq_[i] = freqs[static_cast<int>(i)] / t;
+  freqSet_->setFrequencies(freq_);
+  //Update parameters and re-compute generator and eigen values:
+  matchParametersValues(freqSet_->getParameters());
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/Protein/WAG01.h b/src/Bpp/Phyl/Model/Protein/WAG01.h
new file mode 100644
index 0000000..2f6ba6d
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/WAG01.h
@@ -0,0 +1,155 @@
+//
+// File: WAG01.h
+// Created by: Laurent Gueguen
+// Created on: mardi 28 septembre 2010, à 14h 43
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _WAG01_H_
+#define _WAG01_H_
+
+#include "ProteinSubstitutionModel.h"
+#include "../AbstractSubstitutionModel.h"
+#include "../FrequenciesSet/ProteinFrequenciesSet.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/ProteicAlphabet.h>
+
+namespace bpp
+{
+
+  /**
+   * @brief The Whelan and Goldman substitution model for proteins.
+   *
+   * The exchangability matrix is normalized so that \f$Q = S . \pi\f$ and
+   * \f$\sum_i Q_{i,i}\pi_i = -1\f$.
+   *
+   * The original frequencies can be used, or alternatively a
+   * parametrized version, corresponding to the so-called WAG01+F
+   * model. Eigen values and vectors are obtained numerically.
+   * 
+   * Reference:
+   *
+   * Whelan, S. and N. Goldman. 2001. A general empirical model of
+   * protein evolution derived from multiple protein families using a
+   * maximum likelihood approach. Molecular Biology and Evolution 18:691-699.
+   *
+   */
+
+  class WAG01 :
+    public virtual ProteinSubstitutionModel,
+    public AbstractReversibleSubstitutionModel
+  {
+  private:
+    ProteinFrequenciesSet* freqSet_;
+
+  public:
+    /**
+     * @brief Build a simple WAG01 model, with original equilibrium frequencies.
+     *
+     * @param alpha A proteic alphabet.
+     */
+    WAG01(const ProteicAlphabet* alpha);
+
+    /**
+     * @brief Build a WAG01 model with special equilibrium frequencies.
+     *
+     * @param alpha A proteic alphabet.
+     * @param freqSet A pointer toward a protein frequencies set, which will be owned by this instance.
+     * @param initFreqs Tell if the frequency set should be initialized with the original WAG01 values.
+     * Otherwise, the values of the set will be used.
+     */
+    WAG01(const ProteicAlphabet* alpha, ProteinFrequenciesSet* freqSet, bool initFreqs=false);
+
+    WAG01(const WAG01& model) :
+      AbstractParameterAliasable(model),
+      AbstractSubstitutionModel(model),
+      AbstractReversibleSubstitutionModel(model),
+      freqSet_(dynamic_cast<ProteinFrequenciesSet *>(model.freqSet_->clone()))
+    {}
+
+    WAG01& operator=(const WAG01& model)
+    {
+      AbstractParameterAliasable::operator=(model);
+      AbstractSubstitutionModel::operator=(model);
+      AbstractReversibleSubstitutionModel::operator=(model);
+      if (freqSet_) delete freqSet_;
+      freqSet_ = dynamic_cast<ProteinFrequenciesSet *>(model.freqSet_->clone());
+      return *this;
+    }
+
+    virtual ~WAG01() { delete freqSet_; }
+
+#ifndef NO_VIRTUAL_COV
+    WAG01*
+#else
+    Clonable*
+#endif
+    clone() const { return new WAG01(*this); }
+
+  public:
+    std::string getName() const 
+    { 
+      if (freqSet_->getNamespace().find("WAG01+F.")!=std::string::npos)
+        return "WAG01+F"; 
+      else 
+        return "WAG01"; 
+    }
+
+    void fireParameterChanged(const ParameterList& parameters)
+    {
+      freqSet_->matchParametersValues(parameters);
+      freq_ = freqSet_->getFrequencies();
+      AbstractReversibleSubstitutionModel::fireParameterChanged(parameters);
+    }
+
+    void setFrequenciesSet(const ProteinFrequenciesSet& freqSet)
+    {
+      delete freqSet_;
+      freqSet_ = dynamic_cast<ProteinFrequenciesSet*>(freqSet.clone());
+      resetParameters_();
+      addParameters_(freqSet_->getParameters());
+    }
+
+    const FrequenciesSet* getFrequenciesSet() const { return freqSet_; }
+
+    void setFreqFromData(const SequenceContainer& data);
+
+  };
+
+} //end of namespace bpp.
+
+#endif	//_WAG01_H_
+
diff --git a/src/Bpp/Phyl/Model/Protein/__CATC10FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__CATC10FrequenciesCode
new file mode 100644
index 0000000..95e51df
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__CATC10FrequenciesCode
@@ -0,0 +1,230 @@
+if (getName()=="C1"){
+	freq_[0] = 0.4082573125;
+	freq_[1] = 0.0081783015;
+	freq_[2] = 0.0096285438;
+	freq_[3] = 0.0069870889;
+	freq_[4] = 0.0349388179;
+	freq_[5] = 0.0075279735;
+	freq_[6] = 0.0097846653;
+	freq_[7] = 0.1221613215;
+	freq_[8] = 0.003915183;
+	freq_[9] = 0.0125784287;
+	freq_[10] = 0.0158338663;
+	freq_[11] = 0.005967015;
+	freq_[12] = 0.0081313216;
+	freq_[13] = 0.0061604332;
+	freq_[14] = 0.0394155867;
+	freq_[15] = 0.1682450664;
+	freq_[16] = 0.0658132542;
+	freq_[17] = 0.0018751587;
+	freq_[18] = 0.0041579747;
+	freq_[19] = 0.0604426865;
+}
+
+if (getName()=="C2"){
+	freq_[0] = 0.1027763487;
+	freq_[1] = 0.0418664491;
+	freq_[2] = 0.0213272051;
+	freq_[3] = 0.0155943616;
+	freq_[4] = 0.0149663448;
+	freq_[5] = 0.0440685478;
+	freq_[6] = 0.0419667447;
+	freq_[7] = 0.0138805792;
+	freq_[8] = 0.0158864807;
+	freq_[9] = 0.1066076641;
+	freq_[10] = 0.1131944125;
+	freq_[11] = 0.0436343681;
+	freq_[12] = 0.0437800327;
+	freq_[13] = 0.0180729309;
+	freq_[14] = 0.0223250701;
+	freq_[15] = 0.0529608087;
+	freq_[16] = 0.1081741005;
+	freq_[17] = 0.0045147205;
+	freq_[18] = 0.0137373857;
+	freq_[19] = 0.1606654446;
+}
+
+if (getName()=="C3"){
+	freq_[0] = 0.0351766018;
+	freq_[1] = 0.0019678632;
+	freq_[2] = 0.0016591476;
+	freq_[3] = 0.0006768741;
+	freq_[4] = 0.0078706538;
+	freq_[5] = 0.0016559557;
+	freq_[6] = 0.0019686768;
+	freq_[7] = 0.0022420602;
+	freq_[8] = 0.0012878339;
+	freq_[9] = 0.3515819591;
+	freq_[10] = 0.1278183107;
+	freq_[11] = 0.001885655;
+	freq_[12] = 0.0242631753;
+	freq_[13] = 0.0126221329;
+	freq_[14] = 0.0029771559;
+	freq_[15] = 0.0049998099;
+	freq_[16] = 0.0255378034;
+	freq_[17] = 0.0011907778;
+	freq_[18] = 0.0037539283;
+	freq_[19] = 0.3888636245;
+}
+
+if (getName()=="C4"){
+	freq_[0] = 0.0408513927;
+	freq_[1] = 0.0269887074;
+	freq_[2] = 0.2185648186;
+	freq_[3] = 0.233381479;
+	freq_[4] = 0.0037602852;
+	freq_[5] = 0.0380451418;
+	freq_[6] = 0.0901238869;
+	freq_[7] = 0.1158332065;
+	freq_[8] = 0.0373197176;
+	freq_[9] = 0.0025523644;
+	freq_[10] = 0.0052164616;
+	freq_[11] = 0.0485017266;
+	freq_[12] = 0.0022571778;
+	freq_[13] = 0.0025108218;
+	freq_[14] = 0.010833361;
+	freq_[15] = 0.0804527209;
+	freq_[16] = 0.0302879995;
+	freq_[17] = 0.001081526;
+	freq_[18] = 0.0069890931;
+	freq_[19] = 0.0044481118;
+}
+
+if (getName()=="C5"){
+	freq_[0] = 0.0185492661;
+	freq_[1] = 0.0062362395;
+	freq_[2] = 0.0024895723;
+	freq_[3] = 0.0009775062;
+	freq_[4] = 0.0070416514;
+	freq_[5] = 0.0083539447;
+	freq_[6] = 0.0024891617;
+	freq_[7] = 0.0028952913;
+	freq_[8] = 0.0040103982;
+	freq_[9] = 0.1632422345;
+	freq_[10] = 0.4443079409;
+	freq_[11] = 0.0043570878;
+	freq_[12] = 0.1202815687;
+	freq_[13] = 0.0733329781;
+	freq_[14] = 0.0048827648;
+	freq_[15] = 0.0051642443;
+	freq_[16] = 0.0131806647;
+	freq_[17] = 0.0068759784;
+	freq_[18] = 0.014473442;
+	freq_[19] = 0.0968580644;
+}
+
+if (getName()=="C6"){
+	freq_[0] = 0.1106750119;
+	freq_[1] = 0.0352190043;
+	freq_[2] = 0.040518621;
+	freq_[3] = 0.1636437899;
+	freq_[4] = 0.0014834855;
+	freq_[5] = 0.0877962201;
+	freq_[6] = 0.2638456592;
+	freq_[7] = 0.0325228293;
+	freq_[8] = 0.01638036;
+	freq_[9] = 0.0068334902;
+	freq_[10] = 0.0140679579;
+	freq_[11] = 0.0677158208;
+	freq_[12] = 0.0048988133;
+	freq_[13] = 0.0023256777;
+	freq_[14] = 0.0298982139;
+	freq_[15] = 0.0562887953;
+	freq_[16] = 0.0426922497;
+	freq_[17] = 0.0010338979;
+	freq_[18] = 0.0040522304;
+	freq_[19] = 0.0181078719;
+}
+
+if (getName()=="C7"){
+	freq_[0] = 0.0522657662;
+	freq_[1] = 0.0668294648;
+	freq_[2] = 0.0714836849;
+	freq_[3] = 0.0297745257;
+	freq_[4] = 0.0143324928;
+	freq_[5] = 0.0736540298;
+	freq_[6] = 0.0388386669;
+	freq_[7] = 0.0228101108;
+	freq_[8] = 0.1551638111;
+	freq_[9] = 0.0187406149;
+	freq_[10] = 0.0653779932;
+	freq_[11] = 0.0439469345;
+	freq_[12] = 0.0207189121;
+	freq_[13] = 0.0624033021;
+	freq_[14] = 0.0145475497;
+	freq_[15] = 0.0549017631;
+	freq_[16] = 0.0370140058;
+	freq_[17] = 0.01937569;
+	freq_[18] = 0.1110694548;
+	freq_[19] = 0.0267512268;
+}
+
+if (getName()=="C8"){
+	freq_[0] = 0.0116587342;
+	freq_[1] = 0.0050990142;
+	freq_[2] = 0.0064011054;
+	freq_[3] = 0.0021742457;
+	freq_[4] = 0.0105340743;
+	freq_[5] = 0.0040203734;
+	freq_[6] = 0.0024251112;
+	freq_[7] = 0.0034709143;
+	freq_[8] = 0.0366787049;
+	freq_[9] = 0.018718533;
+	freq_[10] = 0.0676489746;
+	freq_[11] = 0.0026694717;
+	freq_[12] = 0.0143534813;
+	freq_[13] = 0.3650985596;
+	freq_[14] = 0.0031159927;
+	freq_[15] = 0.0094848536;
+	freq_[16] = 0.007371392;
+	freq_[17] = 0.0509564551;
+	freq_[18] = 0.3574858593;
+	freq_[19] = 0.0206341497;
+}
+
+if (getName()=="C9"){
+	freq_[0] = 0.0627195947;
+	freq_[1] = 0.2038782162;
+	freq_[2] = 0.0428629162;
+	freq_[3] = 0.0236193294;
+	freq_[4] = 0.0052662886;
+	freq_[5] = 0.1098111767;
+	freq_[6] = 0.0686284994;
+	freq_[7] = 0.0256174957;
+	freq_[8] = 0.0332612124;
+	freq_[9] = 0.0128968249;
+	freq_[10] = 0.030562774;
+	freq_[11] = 0.2270839355;
+	freq_[12] = 0.0124036991;
+	freq_[13] = 0.0039181841;
+	freq_[14] = 0.0140440613;
+	freq_[15] = 0.0483152469;
+	freq_[16] = 0.0463378087;
+	freq_[17] = 0.0025143473;
+	freq_[18] = 0.0065521118;
+	freq_[19] = 0.019706277;
+}
+
+if (getName()=="C10"){
+	freq_[0] = 0.1145518598;
+	freq_[1] = 0.0324008908;
+	freq_[2] = 0.0750614981;
+	freq_[3] = 0.0416192189;
+	freq_[4] = 0.0098549497;
+	freq_[5] = 0.0339624663;
+	freq_[6] = 0.036490791;
+	freq_[7] = 0.0503817581;
+	freq_[8] = 0.0165233329;
+	freq_[9] = 0.009294946;
+	freq_[10] = 0.0139153707;
+	freq_[11] = 0.0423026886;
+	freq_[12] = 0.0082240805;
+	freq_[13] = 0.0046605982;
+	freq_[14] = 0.0379221548;
+	freq_[15] = 0.2610647896;
+	freq_[16] = 0.1845829279;
+	freq_[17] = 0.0017548981;
+	freq_[18] = 0.0058538316;
+	freq_[19] = 0.0195769483;
+}
+
diff --git a/src/Bpp/Phyl/Model/Protein/__CATC10RatesProps b/src/Bpp/Phyl/Model/Protein/__CATC10RatesProps
new file mode 100644
index 0000000..239c004
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__CATC10RatesProps
@@ -0,0 +1,50 @@
+if (getName()=="C1"){
+	rate_ = 1.;
+	proportion_ = 0.1191344178;
+}
+
+if (getName()=="C2"){
+	rate_ = 1.;
+	proportion_ = 0.0874372456;
+}
+
+if (getName()=="C3"){
+	rate_ = 1.;
+	proportion_ = 0.103710507;
+}
+
+if (getName()=="C4"){
+	rate_ = 1.;
+	proportion_ = 0.0922584809;
+}
+
+if (getName()=="C5"){
+	rate_ = 1.;
+	proportion_ = 0.1070492801;
+}
+
+if (getName()=="C6"){
+	rate_ = 1.;
+	proportion_ = 0.1329945166;
+}
+
+if (getName()=="C7"){
+	rate_ = 1.;
+	proportion_ = 0.0538028458;
+}
+
+if (getName()=="C8"){
+	rate_ = 1.;
+	proportion_ = 0.0691986212;
+}
+
+if (getName()=="C9"){
+	rate_ = 1.;
+	proportion_ = 0.1319937434;
+}
+
+if (getName()=="C10"){
+	rate_ = 1.;
+	proportion_ = 0.1024203429;
+}
+
diff --git a/src/Bpp/Phyl/Model/Protein/__CATC20FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__CATC20FrequenciesCode
new file mode 100644
index 0000000..d375b92
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__CATC20FrequenciesCode
@@ -0,0 +1,460 @@
+if (getName()=="C1"){
+	freq_[0] = 0.0862412505;
+	freq_[1] = 0.0171943793;
+	freq_[2] = 0.0791293376;
+	freq_[3] = 0.0329908619;
+	freq_[4] = 0.0130504558;
+	freq_[5] = 0.0169046938;
+	freq_[6] = 0.0184526503;
+	freq_[7] = 0.0366905299;
+	freq_[8] = 0.010801334;
+	freq_[9] = 0.0097907148;
+	freq_[10] = 0.0112826424;
+	freq_[11] = 0.0220195221;
+	freq_[12] = 0.0087821483;
+	freq_[13] = 0.0044155335;
+	freq_[14] = 0.0189273201;
+	freq_[15] = 0.3178152357;
+	freq_[16] = 0.2711700523;
+	freq_[17] = 0.0015317305;
+	freq_[18] = 0.0048342853;
+	freq_[19] = 0.017975322;
+}
+
+if (getName()=="C2"){
+	freq_[0] = 0.2035582865;
+	freq_[1] = 0.005098081;
+	freq_[2] = 0.0077052407;
+	freq_[3] = 0.0031656079;
+	freq_[4] = 0.0348667285;
+	freq_[5] = 0.0064044073;
+	freq_[6] = 0.00708594;
+	freq_[7] = 0.0195235515;
+	freq_[8] = 0.0024392035;
+	freq_[9] = 0.1152573291;
+	freq_[10] = 0.0789777393;
+	freq_[11] = 0.004238085;
+	freq_[12] = 0.0309187017;
+	freq_[13] = 0.0112429356;
+	freq_[14] = 0.0164189221;
+	freq_[15] = 0.0496777139;
+	freq_[16] = 0.1118946615;
+	freq_[17] = 0.0017762569;
+	freq_[18] = 0.0048448213;
+	freq_[19] = 0.2849057867;
+}
+
+if (getName()=="C3"){
+	freq_[0] = 0.0211547413;
+	freq_[1] = 0.0014946177;
+	freq_[2] = 0.001275503;
+	freq_[3] = 0.0005492865;
+	freq_[4] = 0.0048188557;
+	freq_[5] = 0.0012328812;
+	freq_[6] = 0.0014539632;
+	freq_[7] = 0.0011430874;
+	freq_[8] = 0.0011346394;
+	freq_[9] = 0.3928460626;
+	freq_[10] = 0.125064421;
+	freq_[11] = 0.0013579946;
+	freq_[12] = 0.0209788805;
+	freq_[13] = 0.0128251737;
+	freq_[14] = 0.0020247248;
+	freq_[15] = 0.0026240726;
+	freq_[16] = 0.0171914121;
+	freq_[17] = 0.0011591071;
+	freq_[18] = 0.0036027969;
+	freq_[19] = 0.3860677787;
+}
+
+if (getName()=="C4"){
+	freq_[0] = 0.0376903543;
+	freq_[1] = 0.2885196153;
+	freq_[2] = 0.0365411474;
+	freq_[3] = 0.01094694;
+	freq_[4] = 0.0064073829;
+	freq_[5] = 0.0893564381;
+	freq_[6] = 0.0358365464;
+	freq_[7] = 0.0191106776;
+	freq_[8] = 0.0329513951;
+	freq_[9] = 0.0101711878;
+	freq_[10] = 0.0237495504;
+	freq_[11] = 0.2897626974;
+	freq_[12] = 0.009652887;
+	freq_[13] = 0.0036349802;
+	freq_[14] = 0.010533737;
+	freq_[15] = 0.0356313768;
+	freq_[16] = 0.03559265;
+	freq_[17] = 0.0027925238;
+	freq_[18] = 0.0066557222;
+	freq_[19] = 0.0144621902;
+}
+
+if (getName()=="C5"){
+	freq_[0] = 0.0084597802;
+	freq_[1] = 0.0053589922;
+	freq_[2] = 0.0072525884;
+	freq_[3] = 0.0024487852;
+	freq_[4] = 0.0084909;
+	freq_[5] = 0.0042781483;
+	freq_[6] = 0.0025055486;
+	freq_[7] = 0.0024277107;
+	freq_[8] = 0.0433214027;
+	freq_[9] = 0.0097713028;
+	freq_[10] = 0.0380507037;
+	freq_[11] = 0.0026741007;
+	freq_[12] = 0.0080724771;
+	freq_[13] = 0.3420463838;
+	freq_[14] = 0.0021418673;
+	freq_[15] = 0.0080418935;
+	freq_[16] = 0.0055322116;
+	freq_[17] = 0.0494840193;
+	freq_[18] = 0.4375001561;
+	freq_[19] = 0.0121410277;
+}
+
+if (getName()=="C6"){
+	freq_[0] = 0.1759898886;
+	freq_[1] = 0.0290429175;
+	freq_[2] = 0.0332845569;
+	freq_[3] = 0.1301263816;
+	freq_[4] = 0.0017558693;
+	freq_[5] = 0.0707183953;
+	freq_[6] = 0.2182166681;
+	freq_[7] = 0.0409535143;
+	freq_[8] = 0.0130708195;
+	freq_[9] = 0.0085622087;
+	freq_[10] = 0.0159530702;
+	freq_[11] = 0.0542946169;
+	freq_[12] = 0.0054045759;
+	freq_[13] = 0.002527698;
+	freq_[14] = 0.0371020404;
+	freq_[15] = 0.07934805;
+	freq_[16] = 0.0540083424;
+	freq_[17] = 0.0010592104;
+	freq_[18] = 0.0036259116;
+	freq_[19] = 0.0249552645;
+}
+
+if (getName()=="C7"){
+	freq_[0] = 0.1634397322;
+	freq_[1] = 0.0195541184;
+	freq_[2] = 0.0438701833;
+	freq_[3] = 0.0374272612;
+	freq_[4] = 0.0088659891;
+	freq_[5] = 0.0137554758;
+	freq_[6] = 0.0220611924;
+	freq_[7] = 0.5296717726;
+	freq_[8] = 0.0090006141;
+	freq_[9] = 0.0017569353;
+	freq_[10] = 0.0061156267;
+	freq_[11] = 0.0167117975;
+	freq_[12] = 0.0029390787;
+	freq_[13] = 0.0030641349;
+	freq_[14] = 0.0126457766;
+	freq_[15] = 0.0829342776;
+	freq_[16] = 0.0142835614;
+	freq_[17] = 0.0028640685;
+	freq_[18] = 0.0032398299;
+	freq_[19] = 0.0057985736;
+}
+
+if (getName()=="C8"){
+	freq_[0] = 0.0917468761;
+	freq_[1] = 0.0265853306;
+	freq_[2] = 0.0290699087;
+	freq_[3] = 0.0133818895;
+	freq_[4] = 0.0284015012;
+	freq_[5] = 0.0255084506;
+	freq_[6] = 0.0196875685;
+	freq_[7] = 0.0249898794;
+	freq_[8] = 0.0449766405;
+	freq_[9] = 0.0583555688;
+	freq_[10] = 0.1155009222;
+	freq_[11] = 0.0164915955;
+	freq_[12] = 0.0395994595;
+	freq_[13] = 0.0998479096;
+	freq_[14] = 0.0209916159;
+	freq_[15] = 0.0736482742;
+	freq_[16] = 0.0661518462;
+	freq_[17] = 0.0246463919;
+	freq_[18] = 0.0972327226;
+	freq_[19] = 0.0831856483;
+}
+
+if (getName()=="C9"){
+	freq_[0] = 0.0646700714;
+	freq_[1] = 0.0988015996;
+	freq_[2] = 0.0228907308;
+	freq_[3] = 0.0168733856;
+	freq_[4] = 0.0077117603;
+	freq_[5] = 0.0996414875;
+	freq_[6] = 0.0544977962;
+	freq_[7] = 0.0148893975;
+	freq_[8] = 0.0313851988;
+	freq_[9] = 0.0505983315;
+	freq_[10] = 0.1844282999;
+	freq_[11] = 0.090793129;
+	freq_[12] = 0.077483996;
+	freq_[13] = 0.0219148172;
+	freq_[14] = 0.0105004469;
+	freq_[15] = 0.032119617;
+	freq_[16] = 0.0411766062;
+	freq_[17] = 0.008430303;
+	freq_[18] = 0.0206106035;
+	freq_[19] = 0.0505824221;
+}
+
+if (getName()=="C10"){
+	freq_[0] = 0.0135993865;
+	freq_[1] = 0.0043408375;
+	freq_[2] = 0.0018469375;
+	freq_[3] = 0.0007951703;
+	freq_[4] = 0.010009024;
+	freq_[5] = 0.0046420778;
+	freq_[6] = 0.0018011758;
+	freq_[7] = 0.0026794645;
+	freq_[8] = 0.0072401918;
+	freq_[9] = 0.0814026713;
+	freq_[10] = 0.3661422246;
+	freq_[11] = 0.0025158135;
+	freq_[12] = 0.0734965132;
+	freq_[13] = 0.2640965246;
+	freq_[14] = 0.0038994134;
+	freq_[15] = 0.004366876;
+	freq_[16] = 0.0075248451;
+	freq_[17] = 0.0261564898;
+	freq_[18] = 0.0660970801;
+	freq_[19] = 0.0573472826;
+}
+
+if (getName()=="C11"){
+	freq_[0] = 0.1478036236;
+	freq_[1] = 0.0842845089;
+	freq_[2] = 0.0726630217;
+	freq_[3] = 0.0534743238;
+	freq_[4] = 0.0048825808;
+	freq_[5] = 0.0757166156;
+	freq_[6] = 0.072724646;
+	freq_[7] = 0.0907725939;
+	freq_[8] = 0.0262288856;
+	freq_[9] = 0.0035781075;
+	freq_[10] = 0.0126777221;
+	freq_[11] = 0.1051660098;
+	freq_[12] = 0.0059621792;
+	freq_[13] = 0.0029903868;
+	freq_[14] = 0.0156558198;
+	freq_[15] = 0.1459903343;
+	freq_[16] = 0.0634877444;
+	freq_[17] = 0.0015928454;
+	freq_[18] = 0.0050760739;
+	freq_[19] = 0.0092719768;
+}
+
+if (getName()=="C12"){
+	freq_[0] = 0.0186377412;
+	freq_[1] = 0.0042055165;
+	freq_[2] = 0.0019865236;
+	freq_[3] = 0.0008329696;
+	freq_[4] = 0.0054968852;
+	freq_[5] = 0.0065890091;
+	freq_[6] = 0.0020248504;
+	freq_[7] = 0.0021713483;
+	freq_[8] = 0.0023665991;
+	freq_[9] = 0.2020809776;
+	freq_[10] = 0.437038192;
+	freq_[11] = 0.0029120653;
+	freq_[12] = 0.1241860384;
+	freq_[13] = 0.0385383157;
+	freq_[14] = 0.0040672279;
+	freq_[15] = 0.0046177381;
+	freq_[16] = 0.0149904396;
+	freq_[17] = 0.0026871667;
+	freq_[18] = 0.0056324117;
+	freq_[19] = 0.118937984;
+}
+
+if (getName()=="C13"){
+	freq_[0] = 0.0477624336;
+	freq_[1] = 0.0505742667;
+	freq_[2] = 0.0209574273;
+	freq_[3] = 0.0141349161;
+	freq_[4] = 0.0075791708;
+	freq_[5] = 0.0429296799;
+	freq_[6] = 0.0462688073;
+	freq_[7] = 0.0052327914;
+	freq_[8] = 0.0165351815;
+	freq_[9] = 0.1741496627;
+	freq_[10] = 0.112125357;
+	freq_[11] = 0.057757502;
+	freq_[12] = 0.0330288046;
+	freq_[13] = 0.0130691347;
+	freq_[14] = 0.0124374733;
+	freq_[15] = 0.0264988925;
+	freq_[16] = 0.0951754678;
+	freq_[17] = 0.0031660482;
+	freq_[18] = 0.0112465746;
+	freq_[19] = 0.2093704079;
+}
+
+if (getName()=="C14"){
+	freq_[0] = 0.4164189845;
+	freq_[1] = 0.0056100821;
+	freq_[2] = 0.0091701381;
+	freq_[3] = 0.0045131748;
+	freq_[4] = 0.0406937949;
+	freq_[5] = 0.0061320495;
+	freq_[6] = 0.0063229801;
+	freq_[7] = 0.0946185184;
+	freq_[8] = 0.0031057404;
+	freq_[9] = 0.0076443223;
+	freq_[10] = 0.0099885414;
+	freq_[11] = 0.0038941773;
+	freq_[12] = 0.0069323155;
+	freq_[13] = 0.0048438356;
+	freq_[14] = 0.0187840756;
+	freq_[15] = 0.2360774301;
+	freq_[16] = 0.0746274607;
+	freq_[17] = 0.0012172579;
+	freq_[18] = 0.0034825786;
+	freq_[19] = 0.0459225422;
+}
+
+if (getName()=="C15"){
+	freq_[0] = 0.0402295888;
+	freq_[1] = 0.0735203003;
+	freq_[2] = 0.1036647193;
+	freq_[3] = 0.0365523994;
+	freq_[4] = 0.0124782975;
+	freq_[5] = 0.0826558132;
+	freq_[6] = 0.0372197283;
+	freq_[7] = 0.0233618081;
+	freq_[8] = 0.2108307125;
+	freq_[9] = 0.0093478727;
+	freq_[10] = 0.0360561493;
+	freq_[11] = 0.0482410586;
+	freq_[12] = 0.0100289536;
+	freq_[13] = 0.0459094917;
+	freq_[14] = 0.0098503973;
+	freq_[15] = 0.0533383445;
+	freq_[16] = 0.0310209005;
+	freq_[17] = 0.0140076639;
+	freq_[18] = 0.1064377821;
+	freq_[19] = 0.0152480184;
+}
+
+if (getName()=="C16"){
+	freq_[0] = 0.0323453034;
+	freq_[1] = 0.0236282995;
+	freq_[2] = 0.2520448083;
+	freq_[3] = 0.2431495959;
+	freq_[4] = 0.0035976296;
+	freq_[5] = 0.0330831153;
+	freq_[6] = 0.0710274499;
+	freq_[7] = 0.1016074562;
+	freq_[8] = 0.0366225082;
+	freq_[9] = 0.0031410809;
+	freq_[10] = 0.0051980542;
+	freq_[11] = 0.0470129351;
+	freq_[12] = 0.0024028744;
+	freq_[13] = 0.0024429276;
+	freq_[14] = 0.0094837826;
+	freq_[15] = 0.0848355278;
+	freq_[16] = 0.0359083275;
+	freq_[17] = 0.0008730928;
+	freq_[18] = 0.0067247672;
+	freq_[19] = 0.0048704638;
+}
+
+if (getName()=="C17"){
+	freq_[0] = 0.1476256642;
+	freq_[1] = 0.0334506604;
+	freq_[2] = 0.0211972524;
+	freq_[3] = 0.040305155;
+	freq_[4] = 0.0032327194;
+	freq_[5] = 0.037155448;
+	freq_[6] = 0.0576893391;
+	freq_[7] = 0.0330850942;
+	freq_[8] = 0.0146392559;
+	freq_[9] = 0.0108267008;
+	freq_[10] = 0.0256200793;
+	freq_[11] = 0.0451350877;
+	freq_[12] = 0.00586514;
+	freq_[13] = 0.0047177179;
+	freq_[14] = 0.3473710507;
+	freq_[15] = 0.0892065279;
+	freq_[16] = 0.0485899446;
+	freq_[17] = 0.0016358749;
+	freq_[18] = 0.0044177191;
+	freq_[19] = 0.0282335685;
+}
+
+if (getName()=="C18"){
+	freq_[0] = 0.1031448143;
+	freq_[1] = 0.0717747663;
+	freq_[2] = 0.0435172139;
+	freq_[3] = 0.0386401502;
+	freq_[4] = 0.0061762467;
+	freq_[5] = 0.0786603123;
+	freq_[6] = 0.092336914;
+	freq_[7] = 0.0202338419;
+	freq_[8] = 0.0246761899;
+	freq_[9] = 0.0376904275;
+	freq_[10] = 0.0376283678;
+	freq_[11] = 0.092169892;
+	freq_[12] = 0.0161883318;
+	freq_[13] = 0.0067666433;
+	freq_[14] = 0.012830212;
+	freq_[15] = 0.0951450188;
+	freq_[16] = 0.1378566702;
+	freq_[17] = 0.0022144738;
+	freq_[18] = 0.0083041573;
+	freq_[19] = 0.074045356;
+}
+
+if (getName()=="C19"){
+	freq_[0] = 0.0837542823;
+	freq_[1] = 0.0899383244;
+	freq_[2] = 0.0518811417;
+	freq_[3] = 0.0804870571;
+	freq_[4] = 0.0020735078;
+	freq_[5] = 0.145649747;
+	freq_[6] = 0.1947759184;
+	freq_[7] = 0.0229030361;
+	freq_[8] = 0.0268458796;
+	freq_[9] = 0.0074079756;
+	freq_[10] = 0.0190249576;
+	freq_[11] = 0.1459287407;
+	freq_[12] = 0.0067395241;
+	freq_[13] = 0.0023063393;
+	freq_[14] = 0.0085616014;
+	freq_[15] = 0.0455739585;
+	freq_[16] = 0.0451080843;
+	freq_[17] = 0.0010771349;
+	freq_[18] = 0.0049325333;
+	freq_[19] = 0.0150302559;
+}
+
+if (getName()=="C20"){
+	freq_[0] = 0.057873557;
+	freq_[1] = 0.0138313604;
+	freq_[2] = 0.0491421636;
+	freq_[3] = 0.2946738942;
+	freq_[4] = 0.0011130839;
+	freq_[5] = 0.0598250358;
+	freq_[6] = 0.3402102668;
+	freq_[7] = 0.0293911435;
+	freq_[8] = 0.0139817004;
+	freq_[9] = 0.0030525663;
+	freq_[10] = 0.0062611922;
+	freq_[11] = 0.0363365043;
+	freq_[12] = 0.0027295976;
+	freq_[13] = 0.0017034884;
+	freq_[14] = 0.015610639;
+	freq_[15] = 0.0358044639;
+	freq_[16] = 0.0249941878;
+	freq_[17] = 0.0008664342;
+	freq_[18] = 0.0038312977;
+	freq_[19] = 0.0087674229;
+}
+
diff --git a/src/Bpp/Phyl/Model/Protein/__CATC20RatesProps b/src/Bpp/Phyl/Model/Protein/__CATC20RatesProps
new file mode 100644
index 0000000..85a9815
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__CATC20RatesProps
@@ -0,0 +1,100 @@
+if (getName()=="C1"){
+	rate_ = 1.;
+	proportion_ = 0.05599106;
+}
+
+if (getName()=="C2"){
+	rate_ = 1.;
+	proportion_ = 0.051482487;
+}
+
+if (getName()=="C3"){
+	rate_ = 1.;
+	proportion_ = 0.0812922124;
+}
+
+if (getName()=="C4"){
+	rate_ = 1.;
+	proportion_ = 0.0721976867;
+}
+
+if (getName()=="C5"){
+	rate_ = 1.;
+	proportion_ = 0.0556718858;
+}
+
+if (getName()=="C6"){
+	rate_ = 1.;
+	proportion_ = 0.033100308;
+}
+
+if (getName()=="C7"){
+	rate_ = 1.;
+	proportion_ = 0.0589501763;
+}
+
+if (getName()=="C8"){
+	rate_ = 1.;
+	proportion_ = 0.0263756889;
+}
+
+if (getName()=="C9"){
+	rate_ = 1.;
+	proportion_ = 0.030758422;
+}
+
+if (getName()=="C10"){
+	rate_ = 1.;
+	proportion_ = 0.0376701125;
+}
+
+if (getName()=="C11"){
+	rate_ = 1.;
+	proportion_ = 0.030305829;
+}
+
+if (getName()=="C12"){
+	rate_ = 1.;
+	proportion_ = 0.0808775576;
+}
+
+if (getName()=="C13"){
+	rate_ = 1.;
+	proportion_ = 0.0263349134;
+}
+
+if (getName()=="C14"){
+	rate_ = 1.;
+	proportion_ = 0.0579101455;
+}
+
+if (getName()=="C15"){
+	rate_ = 1.;
+	proportion_ = 0.0371248064;
+}
+
+if (getName()=="C16"){
+	rate_ = 1.;
+	proportion_ = 0.0586867766;
+}
+
+if (getName()=="C17"){
+	rate_ = 1.;
+	proportion_ = 0.0561479138;
+}
+
+if (getName()=="C18"){
+	rate_ = 1.;
+	proportion_ = 0.0349810886;
+}
+
+if (getName()=="C19"){
+	rate_ = 1.;
+	proportion_ = 0.0544937394;
+}
+
+if (getName()=="C20"){
+	rate_ = 1.;
+	proportion_ = 0.0596471901;
+}
+
diff --git a/src/Bpp/Phyl/Model/Protein/__CATC30FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__CATC30FrequenciesCode
new file mode 100644
index 0000000..b978d47
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__CATC30FrequenciesCode
@@ -0,0 +1,690 @@
+if (getName()=="C1"){
+	freq_[0] = 0.1100453954;
+	freq_[1] = 0.0171294861;
+	freq_[2] = 0.0640338464;
+	freq_[3] = 0.1595411459;
+	freq_[4] = 0.0019047235;
+	freq_[5] = 0.0310187088;
+	freq_[6] = 0.1098958823;
+	freq_[7] = 0.068430154;
+	freq_[8] = 0.0137950707;
+	freq_[9] = 0.0026283074;
+	freq_[10] = 0.0073396531;
+	freq_[11] = 0.0358553674;
+	freq_[12] = 0.0024706414;
+	freq_[13] = 0.0016629473;
+	freq_[14] = 0.166935682;
+	freq_[15] = 0.1381790473;
+	freq_[16] = 0.0568342547;
+	freq_[17] = 0.000466112;
+	freq_[18] = 0.0035970152;
+	freq_[19] = 0.0082365591;
+}
+
+if (getName()=="C2"){
+	freq_[0] = 0.0874125465;
+	freq_[1] = 0.0806320385;
+	freq_[2] = 0.0382152368;
+	freq_[3] = 0.0326119879;
+	freq_[4] = 0.0049826376;
+	freq_[5] = 0.0798168854;
+	freq_[6] = 0.0951700809;
+	freq_[7] = 0.0144042708;
+	freq_[8] = 0.0210626652;
+	freq_[9] = 0.039988445;
+	freq_[10] = 0.0301585074;
+	freq_[11] = 0.1147200015;
+	freq_[12] = 0.0126488911;
+	freq_[13] = 0.0048996596;
+	freq_[14] = 0.0137397028;
+	freq_[15] = 0.0873769666;
+	freq_[16] = 0.1558616621;
+	freq_[17] = 0.0015122843;
+	freq_[18] = 0.0053974463;
+	freq_[19] = 0.0793880836;
+}
+
+if (getName()=="C3"){
+	freq_[0] = 0.0225477414;
+	freq_[1] = 0.0014900535;
+	freq_[2] = 0.0013034594;
+	freq_[3] = 0.0005959279;
+	freq_[4] = 0.0050018158;
+	freq_[5] = 0.0011436556;
+	freq_[6] = 0.0015030529;
+	freq_[7] = 0.0011570953;
+	freq_[8] = 0.0009374322;
+	freq_[9] = 0.3944689167;
+	freq_[10] = 0.0889573138;
+	freq_[11] = 0.0013600872;
+	freq_[12] = 0.0189102669;
+	freq_[13] = 0.0089216031;
+	freq_[14] = 0.0018312028;
+	freq_[15] = 0.0028336408;
+	freq_[16] = 0.0189813395;
+	freq_[17] = 0.0006693746;
+	freq_[18] = 0.0023303726;
+	freq_[19] = 0.425055648;
+}
+
+if (getName()=="C4"){
+	freq_[0] = 0.0602158209;
+	freq_[1] = 0.0136833299;
+	freq_[2] = 0.0414987935;
+	freq_[3] = 0.2900084105;
+	freq_[4] = 0.0009525462;
+	freq_[5] = 0.0621611083;
+	freq_[6] = 0.3610869026;
+	freq_[7] = 0.0281925621;
+	freq_[8] = 0.0130500799;
+	freq_[9] = 0.0030516237;
+	freq_[10] = 0.0060401889;
+	freq_[11] = 0.0352704692;
+	freq_[12] = 0.0027460635;
+	freq_[13] = 0.0014625624;
+	freq_[14] = 0.0127175499;
+	freq_[15] = 0.0318109377;
+	freq_[16] = 0.0225279521;
+	freq_[17] = 0.0007948027;
+	freq_[18] = 0.0034024563;
+	freq_[19] = 0.0093258397;
+}
+
+if (getName()=="C5"){
+	freq_[0] = 0.0101223637;
+	freq_[1] = 0.002834492;
+	freq_[2] = 0.001292891;
+	freq_[3] = 0.0006379191;
+	freq_[4] = 0.0085989355;
+	freq_[5] = 0.0035028551;
+	freq_[6] = 0.0011249625;
+	freq_[7] = 0.0024085229;
+	freq_[8] = 0.0047753376;
+	freq_[9] = 0.0701153131;
+	freq_[10] = 0.4135913903;
+	freq_[11] = 0.0016748492;
+	freq_[12] = 0.0744862631;
+	freq_[13] = 0.2785384406;
+	freq_[14] = 0.0040466582;
+	freq_[15] = 0.0037087155;
+	freq_[16] = 0.0052379329;
+	freq_[17] = 0.0200222636;
+	freq_[18] = 0.0523938808;
+	freq_[19] = 0.0408860135;
+}
+
+if (getName()=="C6"){
+	freq_[0] = 0.1335831781;
+	freq_[1] = 0.028478959;
+	freq_[2] = 0.0213891629;
+	freq_[3] = 0.1125775537;
+	freq_[4] = 0.0010514541;
+	freq_[5] = 0.0565844323;
+	freq_[6] = 0.2099572968;
+	freq_[7] = 0.020755187;
+	freq_[8] = 0.0121330488;
+	freq_[9] = 0.0073526522;
+	freq_[10] = 0.013327824;
+	freq_[11] = 0.0771772013;
+	freq_[12] = 0.0030571689;
+	freq_[13] = 0.0016793592;
+	freq_[14] = 0.1890195131;
+	freq_[15] = 0.0484054108;
+	freq_[16] = 0.037331818;
+	freq_[17] = 0.0009266995;
+	freq_[18] = 0.0026946425;
+	freq_[19] = 0.0225174379;
+}
+
+if (getName()=="C7"){
+	freq_[0] = 0.0408277374;
+	freq_[1] = 0.0124491768;
+	freq_[2] = 0.0080464869;
+	freq_[3] = 0.0030634898;
+	freq_[4] = 0.015391841;
+	freq_[5] = 0.0102922098;
+	freq_[6] = 0.006601088;
+	freq_[7] = 0.0058113137;
+	freq_[8] = 0.0245211764;
+	freq_[9] = 0.1487514547;
+	freq_[10] = 0.163780216;
+	freq_[11] = 0.0075923232;
+	freq_[12] = 0.0385527359;
+	freq_[13] = 0.1575049888;
+	freq_[14] = 0.0058352224;
+	freq_[15] = 0.0151578617;
+	freq_[16] = 0.0332220362;
+	freq_[17] = 0.0264937109;
+	freq_[18] = 0.1213342989;
+	freq_[19] = 0.1547706314;
+}
+
+if (getName()=="C8"){
+	freq_[0] = 0.2469059247;
+	freq_[1] = 0.0106278945;
+	freq_[2] = 0.0168929681;
+	freq_[3] = 0.0027418266;
+	freq_[4] = 0.1039406309;
+	freq_[5] = 0.0103988197;
+	freq_[6] = 0.0054944756;
+	freq_[7] = 0.0373263209;
+	freq_[8] = 0.0085752319;
+	freq_[9] = 0.0292403793;
+	freq_[10] = 0.053509118;
+	freq_[11] = 0.0056123053;
+	freq_[12] = 0.0302246485;
+	freq_[13] = 0.025177564;
+	freq_[14] = 0.0078098946;
+	freq_[15] = 0.1642352274;
+	freq_[16] = 0.1239889705;
+	freq_[17] = 0.0053155877;
+	freq_[18] = 0.0163953993;
+	freq_[19] = 0.0955868125;
+}
+
+if (getName()=="C9"){
+	freq_[0] = 0.0549428629;
+	freq_[1] = 0.1305426495;
+	freq_[2] = 0.0202957532;
+	freq_[3] = 0.0092915274;
+	freq_[4] = 0.0099280995;
+	freq_[5] = 0.0906036344;
+	freq_[6] = 0.0417085054;
+	freq_[7] = 0.0105563869;
+	freq_[8] = 0.036351247;
+	freq_[9] = 0.0569584863;
+	freq_[10] = 0.1681833183;
+	freq_[11] = 0.1152521806;
+	freq_[12] = 0.0592328363;
+	freq_[13] = 0.0243860149;
+	freq_[14] = 0.0083055411;
+	freq_[15] = 0.0283778833;
+	freq_[16] = 0.0412594019;
+	freq_[17] = 0.0096355359;
+	freq_[18] = 0.0249780472;
+	freq_[19] = 0.0592100878;
+}
+
+if (getName()=="C10"){
+	freq_[0] = 0.0462773303;
+	freq_[1] = 0.0362984274;
+	freq_[2] = 0.0412365193;
+	freq_[3] = 0.0182504174;
+	freq_[4] = 0.0172727117;
+	freq_[5] = 0.0348990852;
+	freq_[6] = 0.0224266258;
+	freq_[7] = 0.0160971397;
+	freq_[8] = 0.1357852215;
+	freq_[9] = 0.0164966886;
+	freq_[10] = 0.0598936127;
+	freq_[11] = 0.0239396241;
+	freq_[12] = 0.0164507129;
+	freq_[13] = 0.1336320854;
+	freq_[14] = 0.0117413009;
+	freq_[15] = 0.0454156401;
+	freq_[16] = 0.0304387749;
+	freq_[17] = 0.033033841;
+	freq_[18] = 0.2350163763;
+	freq_[19] = 0.0253978649;
+}
+
+if (getName()=="C11"){
+	freq_[0] = 0.0474379955;
+	freq_[1] = 0.0410179935;
+	freq_[2] = 0.0222453982;
+	freq_[3] = 0.0112116958;
+	freq_[4] = 0.0082332447;
+	freq_[5] = 0.0374051414;
+	freq_[6] = 0.0388100853;
+	freq_[7] = 0.0055998598;
+	freq_[8] = 0.014915657;
+	freq_[9] = 0.183217384;
+	freq_[10] = 0.1100691114;
+	freq_[11] = 0.0467850545;
+	freq_[12] = 0.0356443791;
+	freq_[13] = 0.0116643783;
+	freq_[14] = 0.0100244663;
+	freq_[15] = 0.03171711;
+	freq_[16] = 0.1114352326;
+	freq_[17] = 0.0026685586;
+	freq_[18] = 0.0099660086;
+	freq_[19] = 0.2199312452;
+}
+
+if (getName()=="C12"){
+	freq_[0] = 0.0213607696;
+	freq_[1] = 0.0069976154;
+	freq_[2] = 0.0039878996;
+	freq_[3] = 0.0012941246;
+	freq_[4] = 0.0061024858;
+	freq_[5] = 0.0139566033;
+	freq_[6] = 0.0036297282;
+	freq_[7] = 0.0030017014;
+	freq_[8] = 0.0038425894;
+	freq_[9] = 0.1309465785;
+	freq_[10] = 0.4566988203;
+	freq_[11] = 0.005456776;
+	freq_[12] = 0.1947837355;
+	freq_[13] = 0.0371808169;
+	freq_[14] = 0.0040747282;
+	freq_[15] = 0.0076991487;
+	freq_[16] = 0.0198018718;
+	freq_[17] = 0.0034086391;
+	freq_[18] = 0.0064545692;
+	freq_[19] = 0.0693207986;
+}
+
+if (getName()=="C13"){
+	freq_[0] = 0.0919632044;
+	freq_[1] = 0.0160004872;
+	freq_[2] = 0.0764682386;
+	freq_[3] = 0.030671736;
+	freq_[4] = 0.0117031014;
+	freq_[5] = 0.0160060006;
+	freq_[6] = 0.0171907654;
+	freq_[7] = 0.0370684649;
+	freq_[8] = 0.0100792697;
+	freq_[9] = 0.0093123713;
+	freq_[10] = 0.009724097;
+	freq_[11] = 0.0205385908;
+	freq_[12] = 0.0075767282;
+	freq_[13] = 0.004158944;
+	freq_[14] = 0.0179686194;
+	freq_[15] = 0.3254471625;
+	freq_[16] = 0.2744377258;
+	freq_[17] = 0.0013887442;
+	freq_[18] = 0.0044739725;
+	freq_[19] = 0.0178217761;
+}
+
+if (getName()=="C14"){
+	freq_[0] = 0.4649246103;
+	freq_[1] = 0.0043013249;
+	freq_[2] = 0.0075304815;
+	freq_[3] = 0.0050731691;
+	freq_[4] = 0.0233328752;
+	freq_[5] = 0.0043571322;
+	freq_[6] = 0.0057994247;
+	freq_[7] = 0.1495242047;
+	freq_[8] = 0.0023298425;
+	freq_[9] = 0.004336119;
+	freq_[10] = 0.005599553;
+	freq_[11] = 0.0028525398;
+	freq_[12] = 0.003931317;
+	freq_[13] = 0.0025588185;
+	freq_[14] = 0.0186467246;
+	freq_[15] = 0.2150194771;
+	freq_[16] = 0.0477030158;
+	freq_[17] = 0.0009038096;
+	freq_[18] = 0.0020087184;
+	freq_[19] = 0.0292668421;
+}
+
+if (getName()=="C15"){
+	freq_[0] = 0.2051329382;
+	freq_[1] = 0.0439661329;
+	freq_[2] = 0.0339418395;
+	freq_[3] = 0.1070980865;
+	freq_[4] = 0.002091594;
+	freq_[5] = 0.0822742346;
+	freq_[6] = 0.1989733497;
+	freq_[7] = 0.0487574293;
+	freq_[8] = 0.0127143076;
+	freq_[9] = 0.0058124693;
+	freq_[10] = 0.0133471767;
+	freq_[11] = 0.0667787412;
+	freq_[12] = 0.0043783406;
+	freq_[13] = 0.0018235059;
+	freq_[14] = 0.0110997761;
+	freq_[15] = 0.0873961609;
+	freq_[16] = 0.0519781961;
+	freq_[17] = 0.0007361603;
+	freq_[18] = 0.0023821404;
+	freq_[19] = 0.0193174204;
+}
+
+if (getName()=="C16"){
+	freq_[0] = 0.026368989;
+	freq_[1] = 0.0133613622;
+	freq_[2] = 0.2727158135;
+	freq_[3] = 0.3117715371;
+	freq_[4] = 0.0039462429;
+	freq_[5] = 0.0218978778;
+	freq_[6] = 0.0694354212;
+	freq_[7] = 0.0799842408;
+	freq_[8] = 0.030961513;
+	freq_[9] = 0.0027521242;
+	freq_[10] = 0.0038579661;
+	freq_[11] = 0.0288630708;
+	freq_[12] = 0.0018363656;
+	freq_[13] = 0.0023351927;
+	freq_[14] = 0.006245756;
+	freq_[15] = 0.0798729385;
+	freq_[16] = 0.0324143174;
+	freq_[17] = 0.0007229656;
+	freq_[18] = 0.0063857732;
+	freq_[19] = 0.0042705326;
+}
+
+if (getName()=="C17"){
+	freq_[0] = 0.1526502637;
+	freq_[1] = 0.0332784464;
+	freq_[2] = 0.0168229991;
+	freq_[3] = 0.023739218;
+	freq_[4] = 0.0040215287;
+	freq_[5] = 0.0341733672;
+	freq_[6] = 0.0377949108;
+	freq_[7] = 0.0306214335;
+	freq_[8] = 0.0141929803;
+	freq_[9] = 0.0123317972;
+	freq_[10] = 0.0290062362;
+	freq_[11] = 0.0375543022;
+	freq_[12] = 0.0064473224;
+	freq_[13] = 0.0058584416;
+	freq_[14] = 0.38645048;
+	freq_[15] = 0.088033641;
+	freq_[16] = 0.0489543188;
+	freq_[17] = 0.0018252558;
+	freq_[18] = 0.0048877798;
+	freq_[19] = 0.0313552773;
+}
+
+if (getName()=="C18"){
+	freq_[0] = 0.0080247558;
+	freq_[1] = 0.0017408595;
+	freq_[2] = 0.0006327403;
+	freq_[3] = 0.0003385965;
+	freq_[4] = 0.0023412143;
+	freq_[5] = 0.0015507896;
+	freq_[6] = 0.0007818945;
+	freq_[7] = 0.0005403825;
+	freq_[8] = 0.0010026402;
+	freq_[9] = 0.3177056649;
+	freq_[10] = 0.3737894172;
+	freq_[11] = 0.0012598254;
+	freq_[12] = 0.0488212345;
+	freq_[13] = 0.0311968471;
+	freq_[14] = 0.0020687549;
+	freq_[15] = 0.0012095129;
+	freq_[16] = 0.0065696791;
+	freq_[17] = 0.0016309208;
+	freq_[18] = 0.0043343553;
+	freq_[19] = 0.1944599147;
+}
+
+if (getName()=="C19"){
+	freq_[0] = 0.0599950319;
+	freq_[1] = 0.1000540567;
+	freq_[2] = 0.1334918892;
+	freq_[3] = 0.0889730776;
+	freq_[4] = 0.0016884984;
+	freq_[5] = 0.0864856169;
+	freq_[6] = 0.0962700957;
+	freq_[7] = 0.0588796388;
+	freq_[8] = 0.0327277145;
+	freq_[9] = 0.0021467269;
+	freq_[10] = 0.0070876372;
+	freq_[11] = 0.1825860579;
+	freq_[12] = 0.0033979446;
+	freq_[13] = 0.0011800742;
+	freq_[14] = 0.0141408084;
+	freq_[15] = 0.0779002375;
+	freq_[16] = 0.0448817374;
+	freq_[17] = 0.0006249028;
+	freq_[18] = 0.003264112;
+	freq_[19] = 0.0042241415;
+}
+
+if (getName()=="C20"){
+	freq_[0] = 0.0393520657;
+	freq_[1] = 0.0838170642;
+	freq_[2] = 0.14254816;
+	freq_[3] = 0.0431197671;
+	freq_[4] = 0.0099071945;
+	freq_[5] = 0.101978661;
+	freq_[6] = 0.039463951;
+	freq_[7] = 0.0282866471;
+	freq_[8] = 0.2095718357;
+	freq_[9] = 0.0076101442;
+	freq_[10] = 0.0258339558;
+	freq_[11] = 0.0596434088;
+	freq_[12] = 0.0084586675;
+	freq_[13] = 0.0188680789;
+	freq_[14] = 0.0096840517;
+	freq_[15] = 0.0624998643;
+	freq_[16] = 0.0347087967;
+	freq_[17] = 0.0054645779;
+	freq_[18] = 0.0564145251;
+	freq_[19] = 0.0127685828;
+}
+
+if (getName()=="C21"){
+	freq_[0] = 0.0072715487;
+	freq_[1] = 0.0140998918;
+	freq_[2] = 0.0019756795;
+	freq_[3] = 0.002760383;
+	freq_[4] = 0.0067852535;
+	freq_[5] = 0.004333929;
+	freq_[6] = 0.0025069369;
+	freq_[7] = 0.0080834718;
+	freq_[8] = 0.0113217919;
+	freq_[9] = 0.005660964;
+	freq_[10] = 0.0394199644;
+	freq_[11] = 0.0017735096;
+	freq_[12] = 0.007986608;
+	freq_[13] = 0.1271475634;
+	freq_[14] = 0.0041098092;
+	freq_[15] = 0.0052244365;
+	freq_[16] = 0.0043022271;
+	freq_[17] = 0.6273570153;
+	freq_[18] = 0.1084563767;
+	freq_[19] = 0.0094226397;
+}
+
+if (getName()=="C22"){
+	freq_[0] = 0.0907070068;
+	freq_[1] = 0.0290062335;
+	freq_[2] = 0.0860677696;
+	freq_[3] = 0.0745872716;
+	freq_[4] = 0.0063699858;
+	freq_[5] = 0.0259377035;
+	freq_[6] = 0.0386802115;
+	freq_[7] = 0.4750046194;
+	freq_[8] = 0.0168090013;
+	freq_[9] = 0.0014721054;
+	freq_[10] = 0.0055149849;
+	freq_[11] = 0.0343855535;
+	freq_[12] = 0.0024692074;
+	freq_[13] = 0.0028859215;
+	freq_[14] = 0.0112150781;
+	freq_[15] = 0.0731110371;
+	freq_[16] = 0.0153705714;
+	freq_[17] = 0.0022914775;
+	freq_[18] = 0.004186066;
+	freq_[19] = 0.0039281943;
+}
+
+if (getName()=="C23"){
+	freq_[0] = 0.0055291882;
+	freq_[1] = 0.0024626303;
+	freq_[2] = 0.0046086594;
+	freq_[3] = 0.0011413426;
+	freq_[4] = 0.0072105915;
+	freq_[5] = 0.0022692184;
+	freq_[6] = 0.0009683043;
+	freq_[7] = 0.001607095;
+	freq_[8] = 0.0325831191;
+	freq_[9] = 0.00829184;
+	freq_[10] = 0.0353677882;
+	freq_[11] = 0.0013849437;
+	freq_[12] = 0.0074486804;
+	freq_[13] = 0.3744093753;
+	freq_[14] = 0.0013374573;
+	freq_[15] = 0.0057402692;
+	freq_[16] = 0.0037279636;
+	freq_[17] = 0.0330334445;
+	freq_[18] = 0.4609978298;
+	freq_[19] = 0.0098802591;
+}
+
+if (getName()=="C24"){
+	freq_[0] = 0.2443263138;
+	freq_[1] = 0.0045386562;
+	freq_[2] = 0.0062422652;
+	freq_[3] = 0.0031590902;
+	freq_[4] = 0.0273880205;
+	freq_[5] = 0.005359395;
+	freq_[6] = 0.0076715636;
+	freq_[7] = 0.0196089609;
+	freq_[8] = 0.0020189401;
+	freq_[9] = 0.1017435067;
+	freq_[10] = 0.0468424225;
+	freq_[11] = 0.0045492259;
+	freq_[12] = 0.0201286022;
+	freq_[13] = 0.006061945;
+	freq_[14] = 0.0185219126;
+	freq_[15] = 0.0497753825;
+	freq_[16] = 0.1170795523;
+	freq_[17] = 0.0009577255;
+	freq_[18] = 0.0035333687;
+	freq_[19] = 0.3104931504;
+}
+
+if (getName()=="C25"){
+	freq_[0] = 0.0863111274;
+	freq_[1] = 0.0984811895;
+	freq_[2] = 0.0313963115;
+	freq_[3] = 0.0600902926;
+	freq_[4] = 0.0024419845;
+	freq_[5] = 0.1672351286;
+	freq_[6] = 0.203609615;
+	freq_[7] = 0.0175221435;
+	freq_[8] = 0.0245245046;
+	freq_[9] = 0.010599422;
+	freq_[10] = 0.0271209781;
+	freq_[11] = 0.148578959;
+	freq_[12] = 0.0095824358;
+	freq_[13] = 0.0029393105;
+	freq_[14] = 0.0068276769;
+	freq_[15] = 0.0347800318;
+	freq_[16] = 0.0408210979;
+	freq_[17] = 0.0014001253;
+	freq_[18] = 0.0055105388;
+	freq_[19] = 0.0202271268;
+}
+
+if (getName()=="C26"){
+	freq_[0] = 0.0643926114;
+	freq_[1] = 0.0369048739;
+	freq_[2] = 0.1031213278;
+	freq_[3] = 0.1628208462;
+	freq_[4] = 0.0023165895;
+	freq_[5] = 0.0752534859;
+	freq_[6] = 0.1762701353;
+	freq_[7] = 0.0297139006;
+	freq_[8] = 0.0303503732;
+	freq_[9] = 0.0088163033;
+	freq_[10] = 0.0148016812;
+	freq_[11] = 0.0727140107;
+	freq_[12] = 0.0056748403;
+	freq_[13] = 0.0043066715;
+	freq_[14] = 0.0099270322;
+	freq_[15] = 0.0926433867;
+	freq_[16] = 0.0833129915;
+	freq_[17] = 0.0011237109;
+	freq_[18] = 0.0093801464;
+	freq_[19] = 0.0161550816;
+}
+
+if (getName()=="C27"){
+	freq_[0] = 0.1736682858;
+	freq_[1] = 0.0943628709;
+	freq_[2] = 0.052040498;
+	freq_[3] = 0.0285984935;
+	freq_[4] = 0.0083596568;
+	freq_[5] = 0.0722446698;
+	freq_[6] = 0.048389406;
+	freq_[7] = 0.0781901497;
+	freq_[8] = 0.0266134684;
+	freq_[9] = 0.0068641911;
+	freq_[10] = 0.0219499324;
+	freq_[11] = 0.0964011794;
+	freq_[12] = 0.0112303313;
+	freq_[13] = 0.0058273974;
+	freq_[14] = 0.0169661076;
+	freq_[15] = 0.154780246;
+	freq_[16] = 0.075170193;
+	freq_[17] = 0.0028774511;
+	freq_[18] = 0.0082130397;
+	freq_[19] = 0.017252432;
+}
+
+if (getName()=="C28"){
+	freq_[0] = 0.0347856579;
+	freq_[1] = 0.3075984538;
+	freq_[2] = 0.0314157384;
+	freq_[3] = 0.0092355245;
+	freq_[4] = 0.0062754891;
+	freq_[5] = 0.0861073155;
+	freq_[6] = 0.0323568406;
+	freq_[7] = 0.0170288127;
+	freq_[8] = 0.0306438905;
+	freq_[9] = 0.0091932292;
+	freq_[10] = 0.0224428556;
+	freq_[11] = 0.3020845818;
+	freq_[12] = 0.0093720833;
+	freq_[13] = 0.0034303536;
+	freq_[14] = 0.0104447169;
+	freq_[15] = 0.0326882932;
+	freq_[16] = 0.0328713449;
+	freq_[17] = 0.0025244855;
+	freq_[18] = 0.0064171317;
+	freq_[19] = 0.0130832013;
+}
+
+if (getName()=="C29"){
+	freq_[0] = 0.1087737102;
+	freq_[1] = 0.005178102;
+	freq_[2] = 0.0032679768;
+	freq_[3] = 0.0015823203;
+	freq_[4] = 0.024787748;
+	freq_[5] = 0.0057932006;
+	freq_[6] = 0.0041769888;
+	freq_[7] = 0.0134703172;
+	freq_[8] = 0.0024765788;
+	freq_[9] = 0.1643462917;
+	freq_[10] = 0.2337152707;
+	freq_[11] = 0.0027000391;
+	freq_[12] = 0.0539213396;
+	freq_[13] = 0.031652342;
+	freq_[14] = 0.0154886946;
+	freq_[15] = 0.0188187787;
+	freq_[16] = 0.0474912345;
+	freq_[17] = 0.0037656478;
+	freq_[18] = 0.0073106362;
+	freq_[19] = 0.2512827825;
+}
+
+if (getName()=="C30"){
+	freq_[0] = 0.1101008748;
+	freq_[1] = 0.0324324597;
+	freq_[2] = 0.0435098681;
+	freq_[3] = 0.057926852;
+	freq_[4] = 0.0072699765;
+	freq_[5] = 0.061519663;
+	freq_[6] = 0.0828181488;
+	freq_[7] = 0.0314463068;
+	freq_[8] = 0.0308557019;
+	freq_[9] = 0.0530865813;
+	freq_[10] = 0.1096787834;
+	freq_[11] = 0.0293860426;
+	freq_[12] = 0.0458728977;
+	freq_[13] = 0.0269153699;
+	freq_[14] = 0.0296430687;
+	freq_[15] = 0.0715887866;
+	freq_[16] = 0.0685882454;
+	freq_[17] = 0.006232412;
+	freq_[18] = 0.0257237601;
+	freq_[19] = 0.0754042006;
+}
+
diff --git a/src/Bpp/Phyl/Model/Protein/__CATC30RatesProps b/src/Bpp/Phyl/Model/Protein/__CATC30RatesProps
new file mode 100644
index 0000000..345c461
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__CATC30RatesProps
@@ -0,0 +1,150 @@
+if (getName()=="C1"){
+	rate_ = 1.;
+	proportion_ = 0.0095783264;
+}
+
+if (getName()=="C2"){
+	rate_ = 1.;
+	proportion_ = 0.0248476365;
+}
+
+if (getName()=="C3"){
+	rate_ = 1.;
+	proportion_ = 0.0636309366;
+}
+
+if (getName()=="C4"){
+	rate_ = 1.;
+	proportion_ = 0.0537939225;
+}
+
+if (getName()=="C5"){
+	rate_ = 1.;
+	proportion_ = 0.0295885587;
+}
+
+if (getName()=="C6"){
+	rate_ = 1.;
+	proportion_ = 0.0117587936;
+}
+
+if (getName()=="C7"){
+	rate_ = 1.;
+	proportion_ = 0.0132013428;
+}
+
+if (getName()=="C8"){
+	rate_ = 1.;
+	proportion_ = 0.0236868805;
+}
+
+if (getName()=="C9"){
+	rate_ = 1.;
+	proportion_ = 0.0261687659;
+}
+
+if (getName()=="C10"){
+	rate_ = 1.;
+	proportion_ = 0.0239821974;
+}
+
+if (getName()=="C11"){
+	rate_ = 1.;
+	proportion_ = 0.0257100906;
+}
+
+if (getName()=="C12"){
+	rate_ = 1.;
+	proportion_ = 0.0465072425;
+}
+
+if (getName()=="C13"){
+	rate_ = 1.;
+	proportion_ = 0.0546794546;
+}
+
+if (getName()=="C14"){
+	rate_ = 1.;
+	proportion_ = 0.0536085131;
+}
+
+if (getName()=="C15"){
+	rate_ = 1.;
+	proportion_ = 0.027062267;
+}
+
+if (getName()=="C16"){
+	rate_ = 1.;
+	proportion_ = 0.0403913593;
+}
+
+if (getName()=="C17"){
+	rate_ = 1.;
+	proportion_ = 0.04742127;
+}
+
+if (getName()=="C18"){
+	rate_ = 1.;
+	proportion_ = 0.0458816478;
+}
+
+if (getName()=="C19"){
+	rate_ = 1.;
+	proportion_ = 0.021403651;
+}
+
+if (getName()=="C20"){
+	rate_ = 1.;
+	proportion_ = 0.0290385981;
+}
+
+if (getName()=="C21"){
+	rate_ = 1.;
+	proportion_ = 0.0123391793;
+}
+
+if (getName()=="C22"){
+	rate_ = 1.;
+	proportion_ = 0.0569350229;
+}
+
+if (getName()=="C23"){
+	rate_ = 1.;
+	proportion_ = 0.0419687568;
+}
+
+if (getName()=="C24"){
+	rate_ = 1.;
+	proportion_ = 0.0339027062;
+}
+
+if (getName()=="C25"){
+	rate_ = 1.;
+	proportion_ = 0.0388777376;
+}
+
+if (getName()=="C26"){
+	rate_ = 1.;
+	proportion_ = 0.0196343766;
+}
+
+if (getName()=="C27"){
+	rate_ = 1.;
+	proportion_ = 0.0233086174;
+}
+
+if (getName()=="C28"){
+	rate_ = 1.;
+	proportion_ = 0.0622722654;
+}
+
+if (getName()=="C29"){
+	rate_ = 1.;
+	proportion_ = 0.0184803385;
+}
+
+if (getName()=="C30"){
+	rate_ = 1.;
+	proportion_ = 0.0203395454;
+}
+
diff --git a/src/Bpp/Phyl/Model/Protein/__CATC40FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__CATC40FrequenciesCode
new file mode 100644
index 0000000..5d7ff1a
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__CATC40FrequenciesCode
@@ -0,0 +1,920 @@
+if (getName()=="C1"){
+	freq_[0] = 0.0660259814;
+	freq_[1] = 0.0231861755;
+	freq_[2] = 0.1599815873;
+	freq_[3] = 0.1054473175;
+	freq_[4] = 0.0056586745;
+	freq_[5] = 0.0273928499;
+	freq_[6] = 0.0440360794;
+	freq_[7] = 0.0711238664;
+	freq_[8] = 0.0168194755;
+	freq_[9] = 0.0039088727;
+	freq_[10] = 0.0055316013;
+	freq_[11] = 0.0366689617;
+	freq_[12] = 0.0037412416;
+	freq_[13] = 0.0013104807;
+	freq_[14] = 0.0176359169;
+	freq_[15] = 0.2497687201;
+	freq_[16] = 0.1507079582;
+	freq_[17] = 0.0006723214;
+	freq_[18] = 0.0038290224;
+	freq_[19] = 0.0065528958;
+}
+
+if (getName()=="C2"){
+	freq_[0] = 0.0232377444;
+	freq_[1] = 0.0122683027;
+	freq_[2] = 0.2759650991;
+	freq_[3] = 0.3532087982;
+	freq_[4] = 0.0037987468;
+	freq_[5] = 0.0197339134;
+	freq_[6] = 0.0739378219;
+	freq_[7] = 0.057666803;
+	freq_[8] = 0.0315866952;
+	freq_[9] = 0.0031092806;
+	freq_[10] = 0.0038711609;
+	freq_[11] = 0.0259363304;
+	freq_[12] = 0.0017355634;
+	freq_[13] = 0.0024032103;
+	freq_[14] = 0.0063116881;
+	freq_[15] = 0.0657067704;
+	freq_[16] = 0.0270483653;
+	freq_[17] = 0.0007602894;
+	freq_[18] = 0.0069602476;
+	freq_[19] = 0.0047531689;
+}
+
+if (getName()=="C3"){
+	freq_[0] = 0.0166486809;
+	freq_[1] = 0.0012594763;
+	freq_[2] = 0.0012622242;
+	freq_[3] = 0.0005651446;
+	freq_[4] = 0.0036665719;
+	freq_[5] = 0.0010669784;
+	freq_[6] = 0.0013356251;
+	freq_[7] = 0.0008894749;
+	freq_[8] = 0.0008231853;
+	freq_[9] = 0.4129367561;
+	freq_[10] = 0.0884689295;
+	freq_[11] = 0.0011904105;
+	freq_[12] = 0.0186054583;
+	freq_[13] = 0.0082775676;
+	freq_[14] = 0.0014029981;
+	freq_[15] = 0.0021339439;
+	freq_[16] = 0.016216738;
+	freq_[17] = 0.0006082049;
+	freq_[18] = 0.00195532;
+	freq_[19] = 0.4206863114;
+}
+
+if (getName()=="C4"){
+	freq_[0] = 0.2394741986;
+	freq_[1] = 0.0072901253;
+	freq_[2] = 0.0120536943;
+	freq_[3] = 0.0044741726;
+	freq_[4] = 0.0283811727;
+	freq_[5] = 0.008655885;
+	freq_[6] = 0.0105529632;
+	freq_[7] = 0.0135109628;
+	freq_[8] = 0.0038929844;
+	freq_[9] = 0.0765957115;
+	freq_[10] = 0.0358494908;
+	freq_[11] = 0.0071093014;
+	freq_[12] = 0.0199496319;
+	freq_[13] = 0.0055991131;
+	freq_[14] = 0.0114265585;
+	freq_[15] = 0.0847798773;
+	freq_[16] = 0.1797284519;
+	freq_[17] = 0.0009838;
+	freq_[18] = 0.0042240671;
+	freq_[19] = 0.2454678377;
+}
+
+if (getName()=="C5"){
+	freq_[0] = 0.1194613086;
+	freq_[1] = 0.0233255669;
+	freq_[2] = 0.029455214;
+	freq_[3] = 0.0134272792;
+	freq_[4] = 0.0150526644;
+	freq_[5] = 0.0301537796;
+	freq_[6] = 0.0192173037;
+	freq_[7] = 0.0337675998;
+	freq_[8] = 0.0214746045;
+	freq_[9] = 0.0579001821;
+	freq_[10] = 0.1446308373;
+	freq_[11] = 0.0147261337;
+	freq_[12] = 0.056124294;
+	freq_[13] = 0.0550467421;
+	freq_[14] = 0.0631355418;
+	freq_[15] = 0.0925266727;
+	freq_[16] = 0.0831230185;
+	freq_[17] = 0.0131636136;
+	freq_[18] = 0.0331118002;
+	freq_[19] = 0.0811758434;
+}
+
+if (getName()=="C6"){
+	freq_[0] = 0.056704371;
+	freq_[1] = 0.011735933;
+	freq_[2] = 0.0364734454;
+	freq_[3] = 0.2955500969;
+	freq_[4] = 0.0008924801;
+	freq_[5] = 0.0609516515;
+	freq_[6] = 0.3795154126;
+	freq_[7] = 0.0230469606;
+	freq_[8] = 0.0118360971;
+	freq_[9] = 0.0031182036;
+	freq_[10] = 0.0060137466;
+	freq_[11] = 0.0314205689;
+	freq_[12] = 0.0028584065;
+	freq_[13] = 0.0012972333;
+	freq_[14] = 0.0124745819;
+	freq_[15] = 0.0300334889;
+	freq_[16] = 0.0227051137;
+	freq_[17] = 0.0007738758;
+	freq_[18] = 0.0031343761;
+	freq_[19] = 0.0094639563;
+}
+
+if (getName()=="C7"){
+	freq_[0] = 0.0179027412;
+	freq_[1] = 0.0040967133;
+	freq_[2] = 0.0035697688;
+	freq_[3] = 0.0008870412;
+	freq_[4] = 0.016076034;
+	freq_[5] = 0.0045395474;
+	freq_[6] = 0.0023182113;
+	freq_[7] = 0.0039829808;
+	freq_[8] = 0.012729268;
+	freq_[9] = 0.0404650518;
+	freq_[10] = 0.1676143477;
+	freq_[11] = 0.0027994718;
+	freq_[12] = 0.0424172255;
+	freq_[13] = 0.334486259;
+	freq_[14] = 0.0020115128;
+	freq_[15] = 0.0075841581;
+	freq_[16] = 0.0068227293;
+	freq_[17] = 0.0518381385;
+	freq_[18] = 0.2452542553;
+	freq_[19] = 0.0326045442;
+}
+
+if (getName()=="C8"){
+	freq_[0] = 0.2712170094;
+	freq_[1] = 0.0056480837;
+	freq_[2] = 0.014104526;
+	freq_[3] = 0.0021017036;
+	freq_[4] = 0.2003830179;
+	freq_[5] = 0.0048264059;
+	freq_[6] = 0.0023229984;
+	freq_[7] = 0.0502501222;
+	freq_[8] = 0.005372796;
+	freq_[9] = 0.0150684657;
+	freq_[10] = 0.0330003443;
+	freq_[11] = 0.0020646283;
+	freq_[12] = 0.0154811217;
+	freq_[13] = 0.0202990358;
+	freq_[14] = 0.0045351023;
+	freq_[15] = 0.1764198412;
+	freq_[16] = 0.0839578061;
+	freq_[17] = 0.0046265242;
+	freq_[18] = 0.0141271048;
+	freq_[19] = 0.0741933626;
+}
+
+if (getName()=="C9"){
+	freq_[0] = 0.0894736584;
+	freq_[1] = 0.1040026384;
+	freq_[2] = 0.0190192153;
+	freq_[3] = 0.0272183085;
+	freq_[4] = 0.0045538316;
+	freq_[5] = 0.1168091917;
+	freq_[6] = 0.1275076663;
+	freq_[7] = 0.0115685734;
+	freq_[8] = 0.0215746293;
+	freq_[9] = 0.0469424171;
+	freq_[10] = 0.05120351;
+	freq_[11] = 0.1382047308;
+	freq_[12] = 0.0147656854;
+	freq_[13] = 0.0056590176;
+	freq_[14] = 0.0095546504;
+	freq_[15] = 0.0383953611;
+	freq_[16] = 0.0836652641;
+	freq_[17] = 0.0017079427;
+	freq_[18] = 0.0062181292;
+	freq_[19] = 0.0819555787;
+}
+
+if (getName()=="C10"){
+	freq_[0] = 0.0495441385;
+	freq_[1] = 0.0375345822;
+	freq_[2] = 0.031586353;
+	freq_[3] = 0.0143641284;
+	freq_[4] = 0.0182505609;
+	freq_[5] = 0.03165041;
+	freq_[6] = 0.0215379122;
+	freq_[7] = 0.0140199913;
+	freq_[8] = 0.1108543799;
+	freq_[9] = 0.0247065801;
+	freq_[10] = 0.0700287927;
+	freq_[11] = 0.0258142032;
+	freq_[12] = 0.018827176;
+	freq_[13] = 0.1418048822;
+	freq_[14] = 0.0112101202;
+	freq_[15] = 0.0456094427;
+	freq_[16] = 0.0361427973;
+	freq_[17] = 0.0371985427;
+	freq_[18] = 0.2223972375;
+	freq_[19] = 0.0369177689;
+}
+
+if (getName()=="C11"){
+	freq_[0] = 0.1704314254;
+	freq_[1] = 0.0415784004;
+	freq_[2] = 0.0271109259;
+	freq_[3] = 0.10985566;
+	freq_[4] = 0.0009747331;
+	freq_[5] = 0.0917299929;
+	freq_[6] = 0.2536458944;
+	freq_[7] = 0.0249846466;
+	freq_[8] = 0.0101389736;
+	freq_[9] = 0.0058749399;
+	freq_[10] = 0.011652635;
+	freq_[11] = 0.0903324267;
+	freq_[12] = 0.0036512738;
+	freq_[13] = 0.0013321301;
+	freq_[14] = 0.0293613681;
+	freq_[15] = 0.0561765645;
+	freq_[16] = 0.0479045729;
+	freq_[17] = 0.0006696817;
+	freq_[18] = 0.0022637316;
+	freq_[19] = 0.0203300232;
+}
+
+if (getName()=="C12"){
+	freq_[0] = 0.0162725399;
+	freq_[1] = 0.0054826071;
+	freq_[2] = 0.0021876158;
+	freq_[3] = 0.0010182101;
+	freq_[4] = 0.0050614097;
+	freq_[5] = 0.0104414465;
+	freq_[6] = 0.0025141347;
+	freq_[7] = 0.0021935389;
+	freq_[8] = 0.0029914328;
+	freq_[9] = 0.1328173512;
+	freq_[10] = 0.4904441779;
+	freq_[11] = 0.0040120394;
+	freq_[12] = 0.192993128;
+	freq_[13] = 0.037624558;
+	freq_[14] = 0.0034333187;
+	freq_[15] = 0.0040122105;
+	freq_[16] = 0.0127074428;
+	freq_[17] = 0.0032107554;
+	freq_[18] = 0.0058100621;
+	freq_[19] = 0.0647720205;
+}
+
+if (getName()=="C13"){
+	freq_[0] = 0.0823765743;
+	freq_[1] = 0.0734226431;
+	freq_[2] = 0.0598389731;
+	freq_[3] = 0.0311745159;
+	freq_[4] = 0.0065694304;
+	freq_[5] = 0.0686451074;
+	freq_[6] = 0.0675530778;
+	freq_[7] = 0.0178961594;
+	freq_[8] = 0.0251143622;
+	freq_[9] = 0.0291161743;
+	freq_[10] = 0.0287904106;
+	freq_[11] = 0.0982301674;
+	freq_[12] = 0.0168022878;
+	freq_[13] = 0.0064717899;
+	freq_[14] = 0.0114044922;
+	freq_[15] = 0.1302995288;
+	freq_[16] = 0.1820374273;
+	freq_[17] = 0.0022724618;
+	freq_[18] = 0.0079573279;
+	freq_[19] = 0.0540270885;
+}
+
+if (getName()=="C14"){
+	freq_[0] = 0.359496594;
+	freq_[1] = 0.0072407229;
+	freq_[2] = 0.0033421456;
+	freq_[3] = 0.0031484357;
+	freq_[4] = 0.0251417178;
+	freq_[5] = 0.0049014279;
+	freq_[6] = 0.00649627;
+	freq_[7] = 0.1194682267;
+	freq_[8] = 0.0022970448;
+	freq_[9] = 0.0458766662;
+	freq_[10] = 0.0468053893;
+	freq_[11] = 0.0050168849;
+	freq_[12] = 0.0215568816;
+	freq_[13] = 0.0092020461;
+	freq_[14] = 0.0443915884;
+	freq_[15] = 0.0465270945;
+	freq_[16] = 0.0477755293;
+	freq_[17] = 0.0024540215;
+	freq_[18] = 0.0046450361;
+	freq_[19] = 0.1942162766;
+}
+
+if (getName()=="C15"){
+	freq_[0] = 0.2015583874;
+	freq_[1] = 0.043016161;
+	freq_[2] = 0.0425386444;
+	freq_[3] = 0.0954149893;
+	freq_[4] = 0.0032365302;
+	freq_[5] = 0.0772010857;
+	freq_[6] = 0.1534908791;
+	freq_[7] = 0.0667291678;
+	freq_[8] = 0.0155218808;
+	freq_[9] = 0.0067740832;
+	freq_[10] = 0.0165114429;
+	freq_[11] = 0.0547322644;
+	freq_[12] = 0.0060162992;
+	freq_[13] = 0.00256433;
+	freq_[14] = 0.009197056;
+	freq_[15] = 0.1185981804;
+	freq_[16] = 0.0625472744;
+	freq_[17] = 0.0009565508;
+	freq_[18] = 0.0031150007;
+	freq_[19] = 0.0202797924;
+}
+
+if (getName()=="C16"){
+	freq_[0] = 0.1042731047;
+	freq_[1] = 0.0147062345;
+	freq_[2] = 0.06216458;
+	freq_[3] = 0.2424069523;
+	freq_[4] = 0.0022450116;
+	freq_[5] = 0.0356498946;
+	freq_[6] = 0.1774821588;
+	freq_[7] = 0.1697819523;
+	freq_[8] = 0.0132648834;
+	freq_[9] = 0.0018929517;
+	freq_[10] = 0.004254262;
+	freq_[11] = 0.0220651981;
+	freq_[12] = 0.0016441234;
+	freq_[13] = 0.0012570256;
+	freq_[14] = 0.0317041583;
+	freq_[15] = 0.077863623;
+	freq_[16] = 0.0288515782;
+	freq_[17] = 0.0006930898;
+	freq_[18] = 0.0017741945;
+	freq_[19] = 0.0060250231;
+}
+
+if (getName()=="C17"){
+	freq_[0] = 0.0781183281;
+	freq_[1] = 0.0111498472;
+	freq_[2] = 0.0159270309;
+	freq_[3] = 0.0041541669;
+	freq_[4] = 0.0194448667;
+	freq_[5] = 0.024015162;
+	freq_[6] = 0.0116633921;
+	freq_[7] = 0.0111524105;
+	freq_[8] = 0.0063589385;
+	freq_[9] = 0.1354530457;
+	freq_[10] = 0.2457574952;
+	freq_[11] = 0.0093729846;
+	freq_[12] = 0.1087781166;
+	freq_[13] = 0.0262793949;
+	freq_[14] = 0.0055294038;
+	freq_[15] = 0.0408518858;
+	freq_[16] = 0.0860514305;
+	freq_[17] = 0.0031547586;
+	freq_[18] = 0.0085108496;
+	freq_[19] = 0.1482764918;
+}
+
+if (getName()=="C18"){
+	freq_[0] = 0.0856592432;
+	freq_[1] = 0.0101233167;
+	freq_[2] = 0.0441923073;
+	freq_[3] = 0.0135061568;
+	freq_[4] = 0.0136072878;
+	freq_[5] = 0.0092590642;
+	freq_[6] = 0.0078602552;
+	freq_[7] = 0.024540088;
+	freq_[8] = 0.0055379075;
+	freq_[9] = 0.0100591561;
+	freq_[10] = 0.0103343559;
+	freq_[11] = 0.0127318506;
+	freq_[12] = 0.0080675803;
+	freq_[13] = 0.0047153035;
+	freq_[14] = 0.0175273997;
+	freq_[15] = 0.3406479487;
+	freq_[16] = 0.357329465;
+	freq_[17] = 0.0014243098;
+	freq_[18] = 0.003509981;
+	freq_[19] = 0.0193670227;
+}
+
+if (getName()=="C19"){
+	freq_[0] = 0.0674594695;
+	freq_[1] = 0.1161734658;
+	freq_[2] = 0.1163107783;
+	freq_[3] = 0.0662588409;
+	freq_[4] = 0.0021634231;
+	freq_[5] = 0.0939360452;
+	freq_[6] = 0.086550128;
+	freq_[7] = 0.0368556575;
+	freq_[8] = 0.0381149118;
+	freq_[9] = 0.0033238825;
+	freq_[10] = 0.0093839985;
+	freq_[11] = 0.1899736999;
+	freq_[12] = 0.0039487389;
+	freq_[13] = 0.001821273;
+	freq_[14] = 0.015120783;
+	freq_[15] = 0.0842204423;
+	freq_[16] = 0.056595368;
+	freq_[17] = 0.0007187305;
+	freq_[18] = 0.0046189437;
+	freq_[19] = 0.0064514195;
+}
+
+if (getName()=="C20"){
+	freq_[0] = 0.0572262322;
+	freq_[1] = 0.0494723554;
+	freq_[2] = 0.1083882793;
+	freq_[3] = 0.1793932771;
+	freq_[4] = 0.0015301521;
+	freq_[5] = 0.0903668522;
+	freq_[6] = 0.1992261265;
+	freq_[7] = 0.0316472274;
+	freq_[8] = 0.0291392067;
+	freq_[9] = 0.0045804559;
+	freq_[10] = 0.0100739563;
+	freq_[11] = 0.1015624916;
+	freq_[12] = 0.0040204606;
+	freq_[13] = 0.0013701849;
+	freq_[14] = 0.006367413;
+	freq_[15] = 0.0621142922;
+	freq_[16] = 0.0496102162;
+	freq_[17] = 0.0006669285;
+	freq_[18] = 0.0046497641;
+	freq_[19] = 0.0085941279;
+}
+
+if (getName()=="C21"){
+	freq_[0] = 0.0036020163;
+	freq_[1] = 0.0102712927;
+	freq_[2] = 0.0013455508;
+	freq_[3] = 0.0020871647;
+	freq_[4] = 0.0045484804;
+	freq_[5] = 0.0032718114;
+	freq_[6] = 0.001785773;
+	freq_[7] = 0.0056391633;
+	freq_[8] = 0.006496879;
+	freq_[9] = 0.0029292916;
+	freq_[10] = 0.0232635081;
+	freq_[11] = 0.0010419846;
+	freq_[12] = 0.0044592278;
+	freq_[13] = 0.0855714596;
+	freq_[14] = 0.0024991984;
+	freq_[15] = 0.0030671803;
+	freq_[16] = 0.002590025;
+	freq_[17] = 0.7617821954;
+	freq_[18] = 0.0678809532;
+	freq_[19] = 0.0058668443;
+}
+
+if (getName()=="C22"){
+	freq_[0] = 0.2032018418;
+	freq_[1] = 0.0083895722;
+	freq_[2] = 0.0143743754;
+	freq_[3] = 0.0135011707;
+	freq_[4] = 0.0098131618;
+	freq_[5] = 0.004451458;
+	freq_[6] = 0.0083818173;
+	freq_[7] = 0.6184886075;
+	freq_[8] = 0.0027747899;
+	freq_[9] = 0.0011828492;
+	freq_[10] = 0.0039826789;
+	freq_[11] = 0.0044598895;
+	freq_[12] = 0.0020631785;
+	freq_[13] = 0.0019619615;
+	freq_[14] = 0.0085870399;
+	freq_[15] = 0.0739919851;
+	freq_[16] = 0.0108922273;
+	freq_[17] = 0.0018606145;
+	freq_[18] = 0.0015638674;
+	freq_[19] = 0.0060769136;
+}
+
+if (getName()=="C23"){
+	freq_[0] = 0.0050898779;
+	freq_[1] = 0.0028740788;
+	freq_[2] = 0.0057092962;
+	freq_[3] = 0.0016126151;
+	freq_[4] = 0.006177645;
+	freq_[5] = 0.0024693148;
+	freq_[6] = 0.0012040415;
+	freq_[7] = 0.0016334183;
+	freq_[8] = 0.039346078;
+	freq_[9] = 0.0059088776;
+	freq_[10] = 0.0249343597;
+	freq_[11] = 0.0013713662;
+	freq_[12] = 0.0049795162;
+	freq_[13] = 0.3563126947;
+	freq_[14] = 0.0014136424;
+	freq_[15] = 0.0059527667;
+	freq_[16] = 0.003653677;
+	freq_[17] = 0.035798738;
+	freq_[18] = 0.4853645852;
+	freq_[19] = 0.0081934106;
+}
+
+if (getName()=="C24"){
+	freq_[0] = 0.0403335679;
+	freq_[1] = 0.0540186397;
+	freq_[2] = 0.0216052457;
+	freq_[3] = 0.0098218598;
+	freq_[4] = 0.0081549541;
+	freq_[5] = 0.0383639077;
+	freq_[6] = 0.0375406578;
+	freq_[7] = 0.0047934404;
+	freq_[8] = 0.0176735565;
+	freq_[9] = 0.1893424159;
+	freq_[10] = 0.1051859862;
+	freq_[11] = 0.0607377395;
+	freq_[12] = 0.0305599836;
+	freq_[13] = 0.0119140782;
+	freq_[14] = 0.0077550551;
+	freq_[15] = 0.0257110173;
+	freq_[16] = 0.1009913165;
+	freq_[17] = 0.002878002;
+	freq_[18] = 0.0115276935;
+	freq_[19] = 0.2210908828;
+}
+
+if (getName()=="C25"){
+	freq_[0] = 0.0790086293;
+	freq_[1] = 0.1065441152;
+	freq_[2] = 0.0309384274;
+	freq_[3] = 0.0546012394;
+	freq_[4] = 0.0024947877;
+	freq_[5] = 0.1843375981;
+	freq_[6] = 0.1997882784;
+	freq_[7] = 0.0192655847;
+	freq_[8] = 0.0270700474;
+	freq_[9] = 0.0075667489;
+	freq_[10] = 0.0254542392;
+	freq_[11] = 0.1553108816;
+	freq_[12] = 0.0098024439;
+	freq_[13] = 0.0023773444;
+	freq_[14] = 0.0056640684;
+	freq_[15] = 0.0332370813;
+	freq_[16] = 0.0359574739;
+	freq_[17] = 0.0011682801;
+	freq_[18] = 0.0048820809;
+	freq_[19] = 0.0145306498;
+}
+
+if (getName()=="C26"){
+	freq_[0] = 0.0722240672;
+	freq_[1] = 0.0489728405;
+	freq_[2] = 0.0678929607;
+	freq_[3] = 0.1194883992;
+	freq_[4] = 0.0064755348;
+	freq_[5] = 0.0708969573;
+	freq_[6] = 0.1345886574;
+	freq_[7] = 0.0287815397;
+	freq_[8] = 0.0699011334;
+	freq_[9] = 0.0173588702;
+	freq_[10] = 0.0519870084;
+	freq_[11] = 0.049034179;
+	freq_[12] = 0.0154411043;
+	freq_[13] = 0.0348233029;
+	freq_[14] = 0.0145597486;
+	freq_[15] = 0.0589579876;
+	freq_[16] = 0.042597278;
+	freq_[17] = 0.008791377;
+	freq_[18] = 0.0554386705;
+	freq_[19] = 0.0317883834;
+}
+
+if (getName()=="C27"){
+	freq_[0] = 0.1085842431;
+	freq_[1] = 0.0206450023;
+	freq_[2] = 0.0441956285;
+	freq_[3] = 0.1529666596;
+	freq_[4] = 0.001250257;
+	freq_[5] = 0.0405398136;
+	freq_[6] = 0.1664851192;
+	freq_[7] = 0.0336098469;
+	freq_[8] = 0.0134902179;
+	freq_[9] = 0.0038821795;
+	freq_[10] = 0.008986144;
+	freq_[11] = 0.0576227094;
+	freq_[12] = 0.0024339036;
+	freq_[13] = 0.0014553522;
+	freq_[14] = 0.1990095021;
+	freq_[15] = 0.0846749753;
+	freq_[16] = 0.0454715217;
+	freq_[17] = 0.0005902831;
+	freq_[18] = 0.0027650162;
+	freq_[19] = 0.0113416246;
+}
+
+if (getName()=="C28"){
+	freq_[0] = 0.0309526387;
+	freq_[1] = 0.3195887318;
+	freq_[2] = 0.0301336637;
+	freq_[3] = 0.0082352132;
+	freq_[4] = 0.0065593963;
+	freq_[5] = 0.0832608108;
+	freq_[6] = 0.0291974083;
+	freq_[7] = 0.0154206187;
+	freq_[8] = 0.0310385092;
+	freq_[9] = 0.0098251607;
+	freq_[10] = 0.0237900204;
+	freq_[11] = 0.3062634996;
+	freq_[12] = 0.0097071728;
+	freq_[13] = 0.0036891639;
+	freq_[14] = 0.0095029109;
+	freq_[15] = 0.0295285439;
+	freq_[16] = 0.0303052301;
+	freq_[17] = 0.0028125285;
+	freq_[18] = 0.0068850639;
+	freq_[19] = 0.0133037148;
+}
+
+if (getName()=="C29"){
+	freq_[0] = 0.0098953741;
+	freq_[1] = 0.0019604525;
+	freq_[2] = 0.0007307935;
+	freq_[3] = 0.0003748228;
+	freq_[4] = 0.0028276741;
+	freq_[5] = 0.0017337004;
+	freq_[6] = 0.00091821;
+	freq_[7] = 0.0006997068;
+	freq_[8] = 0.0010419482;
+	freq_[9] = 0.3115040359;
+	freq_[10] = 0.3750387796;
+	freq_[11] = 0.0013960508;
+	freq_[12] = 0.047445107;
+	freq_[13] = 0.029860743;
+	freq_[14] = 0.0025296256;
+	freq_[15] = 0.0014628019;
+	freq_[16] = 0.0075738968;
+	freq_[17] = 0.0016799771;
+	freq_[18] = 0.004025993;
+	freq_[19] = 0.1973003069;
+}
+
+if (getName()=="C30"){
+	freq_[0] = 0.1163213921;
+	freq_[1] = 0.0273321006;
+	freq_[2] = 0.0250163656;
+	freq_[3] = 0.0731917718;
+	freq_[4] = 0.0034792282;
+	freq_[5] = 0.0586677248;
+	freq_[6] = 0.1380880502;
+	freq_[7] = 0.0193193469;
+	freq_[8] = 0.016024074;
+	freq_[9] = 0.0712243431;
+	freq_[10] = 0.0771473538;
+	freq_[11] = 0.0355120487;
+	freq_[12] = 0.0242841072;
+	freq_[13] = 0.0094117688;
+	freq_[14] = 0.0508926833;
+	freq_[15] = 0.047556028;
+	freq_[16] = 0.0726552233;
+	freq_[17] = 0.0026892716;
+	freq_[18] = 0.007616602;
+	freq_[19] = 0.1235705162;
+}
+
+if (getName()=="C31"){
+	freq_[0] = 0.1285218235;
+	freq_[1] = 0.0373073487;
+	freq_[2] = 0.1179844215;
+	freq_[3] = 0.0402749992;
+	freq_[4] = 0.0172928883;
+	freq_[5] = 0.043970611;
+	freq_[6] = 0.0250692272;
+	freq_[7] = 0.1127033137;
+	freq_[8] = 0.0606981059;
+	freq_[9] = 0.0109350265;
+	freq_[10] = 0.0258415767;
+	freq_[11] = 0.0288749652;
+	freq_[12] = 0.0167592956;
+	freq_[13] = 0.0199118302;
+	freq_[14] = 0.0180674983;
+	freq_[15] = 0.1741489481;
+	freq_[16] = 0.0648967655;
+	freq_[17] = 0.0063574951;
+	freq_[18] = 0.032177165;
+	freq_[19] = 0.0182066946;
+}
+
+if (getName()=="C32"){
+	freq_[0] = 0.0372286941;
+	freq_[1] = 0.0094528028;
+	freq_[2] = 0.0053377315;
+	freq_[3] = 0.0023703173;
+	freq_[4] = 0.0144940088;
+	freq_[5] = 0.0079097138;
+	freq_[6] = 0.0048585146;
+	freq_[7] = 0.0046433943;
+	freq_[8] = 0.0186795102;
+	freq_[9] = 0.1820459527;
+	freq_[10] = 0.1780099317;
+	freq_[11] = 0.0058198481;
+	freq_[12] = 0.0371334296;
+	freq_[13] = 0.1463772419;
+	freq_[14] = 0.0048538601;
+	freq_[15] = 0.0103570678;
+	freq_[16] = 0.0284161577;
+	freq_[17] = 0.0211293603;
+	freq_[18] = 0.0958905187;
+	freq_[19] = 0.1849919442;
+}
+
+if (getName()=="C33"){
+	freq_[0] = 0.0535643726;
+	freq_[1] = 0.1159797757;
+	freq_[2] = 0.0239172676;
+	freq_[3] = 0.0113537364;
+	freq_[4] = 0.0096256227;
+	freq_[5] = 0.092858507;
+	freq_[6] = 0.039169908;
+	freq_[7] = 0.0120279334;
+	freq_[8] = 0.038488795;
+	freq_[9] = 0.052274827;
+	freq_[10] = 0.1892392595;
+	freq_[11] = 0.0996037748;
+	freq_[12] = 0.0712219098;
+	freq_[13] = 0.0264213736;
+	freq_[14] = 0.0083720574;
+	freq_[15] = 0.0299114019;
+	freq_[16] = 0.0389484845;
+	freq_[17] = 0.0104232046;
+	freq_[18] = 0.026503005;
+	freq_[19] = 0.0500947835;
+}
+
+if (getName()=="C34"){
+	freq_[0] = 0.1332424803;
+	freq_[1] = 0.0033147683;
+	freq_[2] = 0.0022704992;
+	freq_[3] = 0.0012739239;
+	freq_[4] = 0.0246514263;
+	freq_[5] = 0.0030843469;
+	freq_[6] = 0.0040461524;
+	freq_[7] = 0.0089139209;
+	freq_[8] = 0.001586468;
+	freq_[9] = 0.1971284995;
+	freq_[10] = 0.1251288442;
+	freq_[11] = 0.0023713225;
+	freq_[12] = 0.02869472;
+	freq_[13] = 0.0156995251;
+	freq_[14] = 0.0118845743;
+	freq_[15] = 0.0171461828;
+	freq_[16] = 0.0563298009;
+	freq_[17] = 0.001734182;
+	freq_[18] = 0.004877841;
+	freq_[19] = 0.3566205216;
+}
+
+if (getName()=="C35"){
+	freq_[0] = 0.1498658185;
+	freq_[1] = 0.0326607222;
+	freq_[2] = 0.017645282;
+	freq_[3] = 0.0280354786;
+	freq_[4] = 0.0035437399;
+	freq_[5] = 0.0348151308;
+	freq_[6] = 0.0435380704;
+	freq_[7] = 0.0311112643;
+	freq_[8] = 0.0140625707;
+	freq_[9] = 0.0101953314;
+	freq_[10] = 0.0251433928;
+	freq_[11] = 0.039312498;
+	freq_[12] = 0.0051548319;
+	freq_[13] = 0.0047533945;
+	freq_[14] = 0.3923800449;
+	freq_[15] = 0.0874496981;
+	freq_[16] = 0.0473306717;
+	freq_[17] = 0.0015215239;
+	freq_[18] = 0.0043208299;
+	freq_[19] = 0.0271597054;
+}
+
+if (getName()=="C36"){
+	freq_[0] = 0.4214366359;
+	freq_[1] = 0.0061425967;
+	freq_[2] = 0.0121590498;
+	freq_[3] = 0.0073305074;
+	freq_[4] = 0.0187609694;
+	freq_[5] = 0.0072748556;
+	freq_[6] = 0.0086837775;
+	freq_[7] = 0.0902333103;
+	freq_[8] = 0.0030262044;
+	freq_[9] = 0.0039362777;
+	freq_[10] = 0.004719332;
+	freq_[11] = 0.0051508681;
+	freq_[12] = 0.0038306586;
+	freq_[13] = 0.0027156136;
+	freq_[14] = 0.0208940236;
+	freq_[15] = 0.2901188793;
+	freq_[16] = 0.0651922314;
+	freq_[17] = 0.0008108235;
+	freq_[18] = 0.0023622848;
+	freq_[19] = 0.0252211004;
+}
+
+if (getName()=="C37"){
+	freq_[0] = 0.177071389;
+	freq_[1] = 0.133278205;
+	freq_[2] = 0.0311656783;
+	freq_[3] = 0.0226500225;
+	freq_[4] = 0.0078348946;
+	freq_[5] = 0.0752471493;
+	freq_[6] = 0.0509767242;
+	freq_[7] = 0.0897389513;
+	freq_[8] = 0.0220667143;
+	freq_[9] = 0.005951985;
+	freq_[10] = 0.0205369728;
+	freq_[11] = 0.1257689326;
+	freq_[12] = 0.0092982479;
+	freq_[13] = 0.0040514178;
+	freq_[14] = 0.0264087912;
+	freq_[15] = 0.1169591448;
+	freq_[16] = 0.0565566955;
+	freq_[17] = 0.0029947127;
+	freq_[18] = 0.0049346701;
+	freq_[19] = 0.016508701;
+}
+
+if (getName()=="C38"){
+	freq_[0] = 0.0293984032;
+	freq_[1] = 0.037090172;
+	freq_[2] = 0.1483622633;
+	freq_[3] = 0.10997099;
+	freq_[4] = 0.0031729093;
+	freq_[5] = 0.038868845;
+	freq_[6] = 0.0464270335;
+	freq_[7] = 0.4222420155;
+	freq_[8] = 0.0272494642;
+	freq_[9] = 0.0007997326;
+	freq_[10] = 0.0037634298;
+	freq_[11] = 0.0622314461;
+	freq_[12] = 0.0016657052;
+	freq_[13] = 0.0015039626;
+	freq_[14] = 0.0056481827;
+	freq_[15] = 0.0472252404;
+	freq_[16] = 0.0086568982;
+	freq_[17] = 0.0009176022;
+	freq_[18] = 0.0027693124;
+	freq_[19] = 0.002036392;
+}
+
+if (getName()=="C39"){
+	freq_[0] = 0.0265779317;
+	freq_[1] = 0.0791104753;
+	freq_[2] = 0.1318603134;
+	freq_[3] = 0.028031414;
+	freq_[4] = 0.0101369144;
+	freq_[5] = 0.098971081;
+	freq_[6] = 0.0269057233;
+	freq_[7] = 0.0173376629;
+	freq_[8] = 0.2815133703;
+	freq_[9] = 0.0064646977;
+	freq_[10] = 0.0268210053;
+	freq_[11] = 0.0474749135;
+	freq_[12] = 0.0072375268;
+	freq_[13] = 0.0276960902;
+	freq_[14] = 0.0083014995;
+	freq_[15] = 0.0426276702;
+	freq_[16] = 0.0259042511;
+	freq_[17] = 0.0078528946;
+	freq_[18] = 0.0891598394;
+	freq_[19] = 0.0100147256;
+}
+
+if (getName()=="C40"){
+	freq_[0] = 0.0096096503;
+	freq_[1] = 0.002713618;
+	freq_[2] = 0.0013104432;
+	freq_[3] = 0.0006331856;
+	freq_[4] = 0.0077301682;
+	freq_[5] = 0.003389942;
+	freq_[6] = 0.0010471898;
+	freq_[7] = 0.0020227436;
+	freq_[8] = 0.0039001415;
+	freq_[9] = 0.0733098005;
+	freq_[10] = 0.4451691588;
+	freq_[11] = 0.0014931484;
+	freq_[12] = 0.0732575295;
+	freq_[13] = 0.263017169;
+	freq_[14] = 0.0042768091;
+	freq_[15] = 0.0036117358;
+	freq_[16] = 0.0057928403;
+	freq_[17] = 0.0181275729;
+	freq_[18] = 0.0370698053;
+	freq_[19] = 0.042517348;
+}
+
diff --git a/src/Bpp/Phyl/Model/Protein/__CATC40RatesProps b/src/Bpp/Phyl/Model/Protein/__CATC40RatesProps
new file mode 100644
index 0000000..8195733
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__CATC40RatesProps
@@ -0,0 +1,200 @@
+if (getName()=="C1"){
+	rate_ = 1.;
+	proportion_ = 0.0223853788;
+}
+
+if (getName()=="C2"){
+	rate_ = 1.;
+	proportion_ = 0.033889182;
+}
+
+if (getName()=="C3"){
+	rate_ = 1.;
+	proportion_ = 0.0577169375;
+}
+
+if (getName()=="C4"){
+	rate_ = 1.;
+	proportion_ = 0.0252416233;
+}
+
+if (getName()=="C5"){
+	rate_ = 1.;
+	proportion_ = 0.0108607921;
+}
+
+if (getName()=="C6"){
+	rate_ = 1.;
+	proportion_ = 0.0462373793;
+}
+
+if (getName()=="C7"){
+	rate_ = 1.;
+	proportion_ = 0.0102293175;
+}
+
+if (getName()=="C8"){
+	rate_ = 1.;
+	proportion_ = 0.0147523625;
+}
+
+if (getName()=="C9"){
+	rate_ = 1.;
+	proportion_ = 0.0143161352;
+}
+
+if (getName()=="C10"){
+	rate_ = 1.;
+	proportion_ = 0.0182302541;
+}
+
+if (getName()=="C11"){
+	rate_ = 1.;
+	proportion_ = 0.0204025079;
+}
+
+if (getName()=="C12"){
+	rate_ = 1.;
+	proportion_ = 0.0425505156;
+}
+
+if (getName()=="C13"){
+	rate_ = 1.;
+	proportion_ = 0.0248627269;
+}
+
+if (getName()=="C14"){
+	rate_ = 1.;
+	proportion_ = 0.0105892988;
+}
+
+if (getName()=="C15"){
+	rate_ = 1.;
+	proportion_ = 0.0188238725;
+}
+
+if (getName()=="C16"){
+	rate_ = 1.;
+	proportion_ = 0.0086663445;
+}
+
+if (getName()=="C17"){
+	rate_ = 1.;
+	proportion_ = 0.0148496147;
+}
+
+if (getName()=="C18"){
+	rate_ = 1.;
+	proportion_ = 0.0343037402;
+}
+
+if (getName()=="C19"){
+	rate_ = 1.;
+	proportion_ = 0.0225335203;
+}
+
+if (getName()=="C20"){
+	rate_ = 1.;
+	proportion_ = 0.0174068578;
+}
+
+if (getName()=="C21"){
+	rate_ = 1.;
+	proportion_ = 0.0112207827;
+}
+
+if (getName()=="C22"){
+	rate_ = 1.;
+	proportion_ = 0.0443532245;
+}
+
+if (getName()=="C23"){
+	rate_ = 1.;
+	proportion_ = 0.039257337;
+}
+
+if (getName()=="C24"){
+	rate_ = 1.;
+	proportion_ = 0.0196756555;
+}
+
+if (getName()=="C25"){
+	rate_ = 1.;
+	proportion_ = 0.0287690328;
+}
+
+if (getName()=="C26"){
+	rate_ = 1.;
+	proportion_ = 0.0114441177;
+}
+
+if (getName()=="C27"){
+	rate_ = 1.;
+	proportion_ = 0.011233874;
+}
+
+if (getName()=="C28"){
+	rate_ = 1.;
+	proportion_ = 0.0582694099;
+}
+
+if (getName()=="C29"){
+	rate_ = 1.;
+	proportion_ = 0.0444272279;
+}
+
+if (getName()=="C30"){
+	rate_ = 1.;
+	proportion_ = 0.0112010942;
+}
+
+if (getName()=="C31"){
+	rate_ = 1.;
+	proportion_ = 0.0145176111;
+}
+
+if (getName()=="C32"){
+	rate_ = 1.;
+	proportion_ = 0.0114629026;
+}
+
+if (getName()=="C33"){
+	rate_ = 1.;
+	proportion_ = 0.0239628061;
+}
+
+if (getName()=="C34"){
+	rate_ = 1.;
+	proportion_ = 0.0266266492;
+}
+
+if (getName()=="C35"){
+	rate_ = 1.;
+	proportion_ = 0.0481201159;
+}
+
+if (getName()=="C36"){
+	rate_ = 1.;
+	proportion_ = 0.0371147423;
+}
+
+if (getName()=="C37"){
+	rate_ = 1.;
+	proportion_ = 0.0160476688;
+}
+
+if (getName()=="C38"){
+	rate_ = 1.;
+	proportion_ = 0.0237249267;
+}
+
+if (getName()=="C39"){
+	rate_ = 1.;
+	proportion_ = 0.0235226203;
+}
+
+if (getName()=="C40"){
+	rate_ = 1.;
+	proportion_ = 0.0261998398;
+}
+
diff --git a/src/Bpp/Phyl/Model/Protein/__CATC50FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__CATC50FrequenciesCode
new file mode 100644
index 0000000..1531512
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__CATC50FrequenciesCode
@@ -0,0 +1,1150 @@
+if (getName()=="C1"){
+	freq_[0] = 0.1357566757;
+	freq_[1] = 0.0328511938;
+	freq_[2] = 0.0937692919;
+	freq_[3] = 0.0757182069;
+	freq_[4] = 0.0041887049;
+	freq_[5] = 0.044801047;
+	freq_[6] = 0.0572805366;
+	freq_[7] = 0.1210866186;
+	freq_[8] = 0.0167465028;
+	freq_[9] = 0.0049719235;
+	freq_[10] = 0.0113823284;
+	freq_[11] = 0.0458096069;
+	freq_[12] = 0.0064563157;
+	freq_[13] = 0.002929281;
+	freq_[14] = 0.0228705187;
+	freq_[15] = 0.206011578;
+	freq_[16] = 0.1011347978;
+	freq_[17] = 0.0012443033;
+	freq_[18] = 0.0056104605;
+	freq_[19] = 0.0093801079;
+}
+
+if (getName()=="C2"){
+	freq_[0] = 0.0530862751;
+	freq_[1] = 0.190593601;
+	freq_[2] = 0.0595772279;
+	freq_[3] = 0.0320970468;
+	freq_[4] = 0.0026608079;
+	freq_[5] = 0.1152605895;
+	freq_[6] = 0.0840617877;
+	freq_[7] = 0.0196495178;
+	freq_[8] = 0.0274729775;
+	freq_[9] = 0.00649192;
+	freq_[10] = 0.015870912;
+	freq_[11] = 0.2635539775;
+	freq_[12] = 0.0078171228;
+	freq_[13] = 0.0017231166;
+	freq_[14] = 0.01216393;
+	freq_[15] = 0.0449347664;
+	freq_[16] = 0.0472425608;
+	freq_[17] = 0.0008407188;
+	freq_[18] = 0.0037608716;
+	freq_[19] = 0.0111402722;
+}
+
+if (getName()=="C3"){
+	freq_[0] = 0.0083279799;
+	freq_[1] = 0.0007172026;
+	freq_[2] = 0.0006359642;
+	freq_[3] = 0.0003134388;
+	freq_[4] = 0.0020547407;
+	freq_[5] = 0.0007351595;
+	freq_[6] = 0.000537371;
+	freq_[7] = 0.0005576905;
+	freq_[8] = 0.0004858721;
+	freq_[9] = 0.4370910601;
+	freq_[10] = 0.120872222;
+	freq_[11] = 0.0006394909;
+	freq_[12] = 0.0195499664;
+	freq_[13] = 0.0090175268;
+	freq_[14] = 0.0007265254;
+	freq_[15] = 0.0007876194;
+	freq_[16] = 0.0057076665;
+	freq_[17] = 0.0006453449;
+	freq_[18] = 0.0016797264;
+	freq_[19] = 0.3889174318;
+}
+
+if (getName()=="C4"){
+	freq_[0] = 0.207286835;
+	freq_[1] = 0.0166858699;
+	freq_[2] = 0.0129177658;
+	freq_[3] = 0.0020625574;
+	freq_[4] = 0.0849982226;
+	freq_[5] = 0.0151757635;
+	freq_[6] = 0.0065903656;
+	freq_[7] = 0.0472047575;
+	freq_[8] = 0.0130289256;
+	freq_[9] = 0.0345690755;
+	freq_[10] = 0.1042722764;
+	freq_[11] = 0.0075861385;
+	freq_[12] = 0.0498042308;
+	freq_[13] = 0.0572909747;
+	freq_[14] = 0.0064928361;
+	freq_[15] = 0.1183618036;
+	freq_[16] = 0.0780339514;
+	freq_[17] = 0.0128352368;
+	freq_[18] = 0.0323576924;
+	freq_[19] = 0.0924447209;
+}
+
+if (getName()=="C5"){
+	freq_[0] = 0.0364181183;
+	freq_[1] = 0.0076427099;
+	freq_[2] = 0.0052725527;
+	freq_[3] = 0.002038995;
+	freq_[4] = 0.0171009943;
+	freq_[5] = 0.0064088232;
+	freq_[6] = 0.0042399368;
+	freq_[7] = 0.0053824238;
+	freq_[8] = 0.0198596156;
+	freq_[9] = 0.1361523026;
+	freq_[10] = 0.1651892915;
+	freq_[11] = 0.0045481616;
+	freq_[12] = 0.0387479055;
+	freq_[13] = 0.2025922657;
+	freq_[14] = 0.0055053348;
+	freq_[15] = 0.012111195;
+	freq_[16] = 0.0254621828;
+	freq_[17] = 0.0327580458;
+	freq_[18] = 0.1368025306;
+	freq_[19] = 0.1357666147;
+}
+
+if (getName()=="C6"){
+	freq_[0] = 0.0535489196;
+	freq_[1] = 0.0099543365;
+	freq_[2] = 0.0269073208;
+	freq_[3] = 0.3076150732;
+	freq_[4] = 0.0007101021;
+	freq_[5] = 0.0574988641;
+	freq_[6] = 0.4066173371;
+	freq_[7] = 0.0204537673;
+	freq_[8] = 0.0096286483;
+	freq_[9] = 0.0025879708;
+	freq_[10] = 0.0049721459;
+	freq_[11] = 0.0280989086;
+	freq_[12] = 0.0025143457;
+	freq_[13] = 0.0010618006;
+	freq_[14] = 0.0124317994;
+	freq_[15] = 0.0247246015;
+	freq_[16] = 0.0191107367;
+	freq_[17] = 0.0006385967;
+	freq_[18] = 0.0024132214;
+	freq_[19] = 0.0085115039;
+}
+
+if (getName()=="C7"){
+	freq_[0] = 0.0074733729;
+	freq_[1] = 0.0025226602;
+	freq_[2] = 0.0033967505;
+	freq_[3] = 0.0005574007;
+	freq_[4] = 0.0081158286;
+	freq_[5] = 0.0037658904;
+	freq_[6] = 0.0013610444;
+	freq_[7] = 0.0022017759;
+	freq_[8] = 0.0115142679;
+	freq_[9] = 0.0195730439;
+	freq_[10] = 0.1268878488;
+	freq_[11] = 0.0018497296;
+	freq_[12] = 0.026914168;
+	freq_[13] = 0.3821985941;
+	freq_[14] = 0.0019970421;
+	freq_[15] = 0.0057127939;
+	freq_[16] = 0.0039692337;
+	freq_[17] = 0.0553575998;
+	freq_[18] = 0.3184099394;
+	freq_[19] = 0.0162210153;
+}
+
+if (getName()=="C8"){
+	freq_[0] = 0.2615592974;
+	freq_[1] = 0.0027098854;
+	freq_[2] = 0.0124908261;
+	freq_[3] = 0.0020153852;
+	freq_[4] = 0.2740228527;
+	freq_[5] = 0.0017043893;
+	freq_[6] = 0.0007667803;
+	freq_[7] = 0.046349803;
+	freq_[8] = 0.0019474361;
+	freq_[9] = 0.0082858275;
+	freq_[10] = 0.0147048711;
+	freq_[11] = 0.0010787235;
+	freq_[12] = 0.0063051368;
+	freq_[13] = 0.0062080862;
+	freq_[14] = 0.0039442437;
+	freq_[15] = 0.1940042648;
+	freq_[16] = 0.0963699489;
+	freq_[17] = 0.0016185483;
+	freq_[18] = 0.0048431386;
+	freq_[19] = 0.059070555;
+}
+
+if (getName()=="C9"){
+	freq_[0] = 0.1190557043;
+	freq_[1] = 0.0956320251;
+	freq_[2] = 0.0215995297;
+	freq_[3] = 0.0378323341;
+	freq_[4] = 0.0041536088;
+	freq_[5] = 0.1151348174;
+	freq_[6] = 0.1337084452;
+	freq_[7] = 0.017937522;
+	freq_[8] = 0.0216767047;
+	freq_[9] = 0.033622877;
+	freq_[10] = 0.0557402194;
+	freq_[11] = 0.1132452331;
+	freq_[12] = 0.0178407325;
+	freq_[13] = 0.0063405927;
+	freq_[14] = 0.0147606946;
+	freq_[15] = 0.0478666925;
+	freq_[16] = 0.0712091035;
+	freq_[17] = 0.0022867238;
+	freq_[18] = 0.007572863;
+	freq_[19] = 0.0627835766;
+}
+
+if (getName()=="C10"){
+	freq_[0] = 0.0505010344;
+	freq_[1] = 0.0281381134;
+	freq_[2] = 0.0341872191;
+	freq_[3] = 0.0178157543;
+	freq_[4] = 0.0183140005;
+	freq_[5] = 0.0271729546;
+	freq_[6] = 0.0212018661;
+	freq_[7] = 0.0176052654;
+	freq_[8] = 0.1190104107;
+	freq_[9] = 0.0161645217;
+	freq_[10] = 0.0561232531;
+	freq_[11] = 0.0203908848;
+	freq_[12] = 0.0146521042;
+	freq_[13] = 0.1553484132;
+	freq_[14] = 0.01352516;
+	freq_[15] = 0.0478959652;
+	freq_[16] = 0.0292963208;
+	freq_[17] = 0.0376058633;
+	freq_[18] = 0.24772838;
+	freq_[19] = 0.0273225153;
+}
+
+if (getName()=="C11"){
+	freq_[0] = 0.123944691;
+	freq_[1] = 0.035552587;
+	freq_[2] = 0.0409769096;
+	freq_[3] = 0.1479953346;
+	freq_[4] = 0.0011563976;
+	freq_[5] = 0.0908869312;
+	freq_[6] = 0.2700270273;
+	freq_[7] = 0.0283589709;
+	freq_[8] = 0.0126760201;
+	freq_[9] = 0.0064825033;
+	freq_[10] = 0.0122101302;
+	freq_[11] = 0.0787433823;
+	freq_[12] = 0.004246744;
+	freq_[13] = 0.0016540857;
+	freq_[14] = 0.02057175;
+	freq_[15] = 0.0552940245;
+	freq_[16] = 0.0474239965;
+	freq_[17] = 0.0008596621;
+	freq_[18] = 0.0027823209;
+	freq_[19] = 0.0181565313;
+}
+
+if (getName()=="C12"){
+	freq_[0] = 0.0160542063;
+	freq_[1] = 0.0027359185;
+	freq_[2] = 0.0014708079;
+	freq_[3] = 0.00070049;
+	freq_[4] = 0.0034820152;
+	freq_[5] = 0.0061470051;
+	freq_[6] = 0.0016359686;
+	freq_[7] = 0.0022137927;
+	freq_[8] = 0.0013207229;
+	freq_[9] = 0.1640035117;
+	freq_[10] = 0.4616043506;
+	freq_[11] = 0.0021342205;
+	freq_[12] = 0.2174099502;
+	freq_[13] = 0.0143751693;
+	freq_[14] = 0.0013694259;
+	freq_[15] = 0.0037614383;
+	freq_[16] = 0.0172651408;
+	freq_[17] = 0.0011454338;
+	freq_[18] = 0.0019438536;
+	freq_[19] = 0.0792265779;
+}
+
+if (getName()=="C13"){
+	freq_[0] = 0.1548192401;
+	freq_[1] = 0.0131324559;
+	freq_[2] = 0.0280584102;
+	freq_[3] = 0.009530162;
+	freq_[4] = 0.0166267416;
+	freq_[5] = 0.017522895;
+	freq_[6] = 0.0170969133;
+	freq_[7] = 0.0179616718;
+	freq_[8] = 0.0078385586;
+	freq_[9] = 0.0865181208;
+	freq_[10] = 0.052336991;
+	freq_[11] = 0.0132802182;
+	freq_[12] = 0.032634821;
+	freq_[13] = 0.0083511229;
+	freq_[14] = 0.0145594414;
+	freq_[15] = 0.1096327081;
+	freq_[16] = 0.2218108602;
+	freq_[17] = 0.0015829972;
+	freq_[18] = 0.006217336;
+	freq_[19] = 0.1704883347;
+}
+
+if (getName()=="C14"){
+	freq_[0] = 0.2950313592;
+	freq_[1] = 0.0027580697;
+	freq_[2] = 0.0021616268;
+	freq_[3] = 0.001536419;
+	freq_[4] = 0.0375439186;
+	freq_[5] = 0.0028808733;
+	freq_[6] = 0.0042976283;
+	freq_[7] = 0.0261726702;
+	freq_[8] = 0.0008294969;
+	freq_[9] = 0.0834938143;
+	freq_[10] = 0.0553606311;
+	freq_[11] = 0.0022642314;
+	freq_[12] = 0.0181259911;
+	freq_[13] = 0.0074433078;
+	freq_[14] = 0.0126794048;
+	freq_[15] = 0.0382913338;
+	freq_[16] = 0.0783205173;
+	freq_[17] = 0.0010015148;
+	freq_[18] = 0.0034016419;
+	freq_[19] = 0.3264055498;
+}
+
+if (getName()=="C15"){
+	freq_[0] = 0.1683177099;
+	freq_[1] = 0.0820396152;
+	freq_[2] = 0.0526048706;
+	freq_[3] = 0.082251715;
+	freq_[4] = 0.0023029997;
+	freq_[5] = 0.0969341246;
+	freq_[6] = 0.1488943001;
+	freq_[7] = 0.0535291188;
+	freq_[8] = 0.0179803231;
+	freq_[9] = 0.0032503636;
+	freq_[10] = 0.0114941086;
+	freq_[11] = 0.1156402642;
+	freq_[12] = 0.0039439899;
+	freq_[13] = 0.0015002945;
+	freq_[14] = 0.0066854154;
+	freq_[15] = 0.0924511658;
+	freq_[16] = 0.0480769504;
+	freq_[17] = 0.0006152103;
+	freq_[18] = 0.0025022919;
+	freq_[19] = 0.0089851683;
+}
+
+if (getName()=="C16"){
+	freq_[0] = 0.0334088176;
+	freq_[1] = 0.0134485791;
+	freq_[2] = 0.159091815;
+	freq_[3] = 0.3657542471;
+	freq_[4] = 0.0025127086;
+	freq_[5] = 0.0327665151;
+	freq_[6] = 0.1820739351;
+	freq_[7] = 0.0740807194;
+	freq_[8] = 0.0202010901;
+	freq_[9] = 0.0016650025;
+	freq_[10] = 0.0036700956;
+	freq_[11] = 0.0295517886;
+	freq_[12] = 0.001708781;
+	freq_[13] = 0.0011422805;
+	freq_[14] = 0.0073155123;
+	freq_[15] = 0.0426788071;
+	freq_[16] = 0.0211162106;
+	freq_[17] = 0.0005931485;
+	freq_[18] = 0.003472458;
+	freq_[19] = 0.0037474882;
+}
+
+if (getName()=="C17"){
+	freq_[0] = 0.0777586977;
+	freq_[1] = 0.0174438357;
+	freq_[2] = 0.0053423343;
+	freq_[3] = 0.0043431532;
+	freq_[4] = 0.0062523949;
+	freq_[5] = 0.0220851281;
+	freq_[6] = 0.0161769285;
+	freq_[7] = 0.0053903202;
+	freq_[8] = 0.0080675581;
+	freq_[9] = 0.1052945216;
+	freq_[10] = 0.1617365895;
+	freq_[11] = 0.0148319919;
+	freq_[12] = 0.0288253912;
+	freq_[13] = 0.0168985297;
+	freq_[14] = 0.2565426868;
+	freq_[15] = 0.0202089662;
+	freq_[16] = 0.0542929694;
+	freq_[17] = 0.0060146095;
+	freq_[18] = 0.0078109966;
+	freq_[19] = 0.1646823969;
+}
+
+if (getName()=="C18"){
+	freq_[0] = 0.0727013979;
+	freq_[1] = 0.0048977192;
+	freq_[2] = 0.0026095383;
+	freq_[3] = 0.001142012;
+	freq_[4] = 0.0198747408;
+	freq_[5] = 0.0066949336;
+	freq_[6] = 0.0030401434;
+	freq_[7] = 0.0079074845;
+	freq_[8] = 0.00264929;
+	freq_[9] = 0.1685788878;
+	freq_[10] = 0.3185489163;
+	freq_[11] = 0.0026024909;
+	freq_[12] = 0.0735597038;
+	freq_[13] = 0.0490419983;
+	freq_[14] = 0.0051699104;
+	freq_[15] = 0.012863083;
+	freq_[16] = 0.0305356924;
+	freq_[17] = 0.005085784;
+	freq_[18] = 0.0095279173;
+	freq_[19] = 0.2029683559;
+}
+
+if (getName()=="C19"){
+	freq_[0] = 0.0658153836;
+	freq_[1] = 0.0833432992;
+	freq_[2] = 0.0224582275;
+	freq_[3] = 0.0107735824;
+	freq_[4] = 0.0092974677;
+	freq_[5] = 0.0745951987;
+	freq_[6] = 0.0299754097;
+	freq_[7] = 0.0146336557;
+	freq_[8] = 0.0148026634;
+	freq_[9] = 0.0671888719;
+	freq_[10] = 0.219867599;
+	freq_[11] = 0.0868172087;
+	freq_[12] = 0.1084156835;
+	freq_[13] = 0.0155812696;
+	freq_[14] = 0.0071132147;
+	freq_[15] = 0.0381451947;
+	freq_[16] = 0.0562948237;
+	freq_[17] = 0.0056421684;
+	freq_[18] = 0.0102813038;
+	freq_[19] = 0.058957774;
+}
+
+if (getName()=="C20"){
+	freq_[0] = 0.0525278351;
+	freq_[1] = 0.036489739;
+	freq_[2] = 0.0903013988;
+	freq_[3] = 0.1854660991;
+	freq_[4] = 0.00377954;
+	freq_[5] = 0.0776857292;
+	freq_[6] = 0.178928729;
+	freq_[7] = 0.0232011648;
+	freq_[8] = 0.0687702011;
+	freq_[9] = 0.0135825419;
+	freq_[10] = 0.0337350646;
+	freq_[11] = 0.045814377;
+	freq_[12] = 0.0108457797;
+	freq_[13] = 0.0191020037;
+	freq_[14] = 0.0088729983;
+	freq_[15] = 0.0495289201;
+	freq_[16] = 0.0389358438;
+	freq_[17] = 0.0046292762;
+	freq_[18] = 0.0354195947;
+	freq_[19] = 0.0223831639;
+}
+
+if (getName()=="C21"){
+	freq_[0] = 0.002651597;
+	freq_[1] = 0.0080885204;
+	freq_[2] = 0.0010572021;
+	freq_[3] = 0.0016052142;
+	freq_[4] = 0.0036540307;
+	freq_[5] = 0.0022979498;
+	freq_[6] = 0.0014681767;
+	freq_[7] = 0.0046230912;
+	freq_[8] = 0.0043887616;
+	freq_[9] = 0.0020669456;
+	freq_[10] = 0.0172444871;
+	freq_[11] = 0.0006593575;
+	freq_[12] = 0.0034691503;
+	freq_[13] = 0.0658351447;
+	freq_[14] = 0.0019185467;
+	freq_[15] = 0.002249842;
+	freq_[16] = 0.0021278866;
+	freq_[17] = 0.8183345006;
+	freq_[18] = 0.0515918357;
+	freq_[19] = 0.0046677595;
+}
+
+if (getName()=="C22"){
+	freq_[0] = 0.0548133174;
+	freq_[1] = 0.0692044159;
+	freq_[2] = 0.021126571;
+	freq_[3] = 0.0207779125;
+	freq_[4] = 0.0072646572;
+	freq_[5] = 0.0567865657;
+	freq_[6] = 0.0738456579;
+	freq_[7] = 0.0051797705;
+	freq_[8] = 0.0168408457;
+	freq_[9] = 0.1386104888;
+	freq_[10] = 0.0713795154;
+	freq_[11] = 0.089639334;
+	freq_[12] = 0.0201205491;
+	freq_[13] = 0.0082150393;
+	freq_[14] = 0.0104049016;
+	freq_[15] = 0.0282344422;
+	freq_[16] = 0.099559711;
+	freq_[17] = 0.0019722093;
+	freq_[18] = 0.0074054035;
+	freq_[19] = 0.1986186919;
+}
+
+if (getName()=="C23"){
+	freq_[0] = 0.0047955268;
+	freq_[1] = 0.0028033787;
+	freq_[2] = 0.0050506238;
+	freq_[3] = 0.0014080516;
+	freq_[4] = 0.0061671241;
+	freq_[5] = 0.0019350126;
+	freq_[6] = 0.0009861551;
+	freq_[7] = 0.0014396818;
+	freq_[8] = 0.0389623239;
+	freq_[9] = 0.0048950388;
+	freq_[10] = 0.015174815;
+	freq_[11] = 0.0012306644;
+	freq_[12] = 0.0032520404;
+	freq_[13] = 0.360199306;
+	freq_[14] = 0.0011266316;
+	freq_[15] = 0.0054509935;
+	freq_[16] = 0.0034763921;
+	freq_[17] = 0.0362899931;
+	freq_[18] = 0.4980200998;
+	freq_[19] = 0.0073361467;
+}
+
+if (getName()=="C24"){
+	freq_[0] = 0.0365462996;
+	freq_[1] = 0.028007063;
+	freq_[2] = 0.0183606115;
+	freq_[3] = 0.0070525803;
+	freq_[4] = 0.0093251684;
+	freq_[5] = 0.0300239431;
+	freq_[6] = 0.0221812842;
+	freq_[7] = 0.0047778642;
+	freq_[8] = 0.0178840316;
+	freq_[9] = 0.2025947306;
+	freq_[10] = 0.197301213;
+	freq_[11] = 0.025020975;
+	freq_[12] = 0.055786264;
+	freq_[13] = 0.0258067541;
+	freq_[14] = 0.004277221;
+	freq_[15] = 0.0209374223;
+	freq_[16] = 0.0731398943;
+	freq_[17] = 0.0049738166;
+	freq_[18] = 0.0200601168;
+	freq_[19] = 0.1959427463;
+}
+
+if (getName()=="C25"){
+	freq_[0] = 0.0684197684;
+	freq_[1] = 0.011161975;
+	freq_[2] = 0.0544764241;
+	freq_[3] = 0.0224313301;
+	freq_[4] = 0.0106958312;
+	freq_[5] = 0.0091799953;
+	freq_[6] = 0.0097436799;
+	freq_[7] = 0.0255871619;
+	freq_[8] = 0.0055558006;
+	freq_[9] = 0.0059416697;
+	freq_[10] = 0.0076746853;
+	freq_[11] = 0.0144198991;
+	freq_[12] = 0.0056892166;
+	freq_[13] = 0.0037356845;
+	freq_[14] = 0.0172554137;
+	freq_[15] = 0.3527301149;
+	freq_[16] = 0.3586913194;
+	freq_[17] = 0.0012501907;
+	freq_[18] = 0.002863671;
+	freq_[19] = 0.0124961682;
+}
+
+if (getName()=="C26"){
+	freq_[0] = 0.0495330775;
+	freq_[1] = 0.1060064564;
+	freq_[2] = 0.1511923969;
+	freq_[3] = 0.0483471288;
+	freq_[4] = 0.0080946362;
+	freq_[5] = 0.0886108407;
+	freq_[6] = 0.0449556763;
+	freq_[7] = 0.0331436148;
+	freq_[8] = 0.1447288287;
+	freq_[9] = 0.006185077;
+	freq_[10] = 0.0190407203;
+	freq_[11] = 0.0948075276;
+	freq_[12] = 0.0063418871;
+	freq_[13] = 0.0126162987;
+	freq_[14] = 0.0100869563;
+	freq_[15] = 0.0799801169;
+	freq_[16] = 0.0445418973;
+	freq_[17] = 0.0044765096;
+	freq_[18] = 0.0363930724;
+	freq_[19] = 0.0109172804;
+}
+
+if (getName()=="C27"){
+	freq_[0] = 0.0702411901;
+	freq_[1] = 0.0642050323;
+	freq_[2] = 0.0779553908;
+	freq_[3] = 0.0510328304;
+	freq_[4] = 0.0042438849;
+	freq_[5] = 0.0723300485;
+	freq_[6] = 0.088374771;
+	freq_[7] = 0.0177347101;
+	freq_[8] = 0.0233800891;
+	freq_[9] = 0.019877932;
+	freq_[10] = 0.0183537117;
+	freq_[11] = 0.1051267065;
+	freq_[12] = 0.0107865869;
+	freq_[13] = 0.0037987118;
+	freq_[14] = 0.0112811107;
+	freq_[15] = 0.1345081583;
+	freq_[16] = 0.1805543234;
+	freq_[17] = 0.0014252764;
+	freq_[18] = 0.0055089381;
+	freq_[19] = 0.0392805971;
+}
+
+if (getName()=="C28"){
+	freq_[0] = 0.1207399152;
+	freq_[1] = 0.1741788075;
+	freq_[2] = 0.038552812;
+	freq_[3] = 0.0162689581;
+	freq_[4] = 0.0118494185;
+	freq_[5] = 0.0760068404;
+	freq_[6] = 0.0337935391;
+	freq_[7] = 0.0653431008;
+	freq_[8] = 0.0342783806;
+	freq_[9] = 0.0085426053;
+	freq_[10] = 0.0256788075;
+	freq_[11] = 0.1434443984;
+	freq_[12] = 0.0112347894;
+	freq_[13] = 0.0061270793;
+	freq_[14] = 0.0294493558;
+	freq_[15] = 0.1091415488;
+	freq_[16] = 0.0634181251;
+	freq_[17] = 0.0046156419;
+	freq_[18] = 0.0085374279;
+	freq_[19] = 0.0187984481;
+}
+
+if (getName()=="C29"){
+	freq_[0] = 0.0064521696;
+	freq_[1] = 0.0021817337;
+	freq_[2] = 0.0005939658;
+	freq_[3] = 0.0003904032;
+	freq_[4] = 0.0021538307;
+	freq_[5] = 0.0019099968;
+	freq_[6] = 0.0008007758;
+	freq_[7] = 0.0005208471;
+	freq_[8] = 0.0011374294;
+	freq_[9] = 0.2850758996;
+	freq_[10] = 0.427853674;
+	freq_[11] = 0.0013920239;
+	freq_[12] = 0.0561988528;
+	freq_[13] = 0.0449501501;
+	freq_[14] = 0.0026289702;
+	freq_[15] = 0.0011053664;
+	freq_[16] = 0.0055157148;
+	freq_[17] = 0.0022753671;
+	freq_[18] = 0.0059612583;
+	freq_[19] = 0.1509015707;
+}
+
+if (getName()=="C30"){
+	freq_[0] = 0.0969092741;
+	freq_[1] = 0.035972337;
+	freq_[2] = 0.0633194168;
+	freq_[3] = 0.0411020773;
+	freq_[4] = 0.0145578946;
+	freq_[5] = 0.0466661704;
+	freq_[6] = 0.0469223767;
+	freq_[7] = 0.0374614202;
+	freq_[8] = 0.053714958;
+	freq_[9] = 0.0394603009;
+	freq_[10] = 0.0856256544;
+	freq_[11] = 0.0283577862;
+	freq_[12] = 0.034643532;
+	freq_[13] = 0.0507298072;
+	freq_[14] = 0.0167177549;
+	freq_[15] = 0.0990945318;
+	freq_[16] = 0.0806503833;
+	freq_[17] = 0.0128373826;
+	freq_[18] = 0.0598972198;
+	freq_[19] = 0.0553597218;
+}
+
+if (getName()=="C31"){
+	freq_[0] = 0.084021201;
+	freq_[1] = 0.0214242172;
+	freq_[2] = 0.2240668646;
+	freq_[3] = 0.0354684798;
+	freq_[4] = 0.0265031681;
+	freq_[5] = 0.0235675678;
+	freq_[6] = 0.0076026464;
+	freq_[7] = 0.1173325117;
+	freq_[8] = 0.0516019781;
+	freq_[9] = 0.0048917455;
+	freq_[10] = 0.0067211727;
+	freq_[11] = 0.0173653354;
+	freq_[12] = 0.0079342101;
+	freq_[13] = 0.0087501486;
+	freq_[14] = 0.0093276105;
+	freq_[15] = 0.2637097946;
+	freq_[16] = 0.0630157977;
+	freq_[17] = 0.0022314593;
+	freq_[18] = 0.0170994247;
+	freq_[19] = 0.0073646661;
+}
+
+if (getName()=="C32"){
+	freq_[0] = 0.0055061507;
+	freq_[1] = 0.0012508737;
+	freq_[2] = 0.0004824961;
+	freq_[3] = 0.0004530173;
+	freq_[4] = 0.0054435931;
+	freq_[5] = 0.0011315076;
+	freq_[6] = 0.0004150379;
+	freq_[7] = 0.0012285001;
+	freq_[8] = 0.0019884532;
+	freq_[9] = 0.0617431901;
+	freq_[10] = 0.4342418135;
+	freq_[11] = 0.0008161868;
+	freq_[12] = 0.0554628445;
+	freq_[13] = 0.3289659386;
+	freq_[14] = 0.0025814794;
+	freq_[15] = 0.0021197505;
+	freq_[16] = 0.002951044;
+	freq_[17] = 0.0172981374;
+	freq_[18] = 0.0412097497;
+	freq_[19] = 0.0347102358;
+}
+
+if (getName()=="C33"){
+	freq_[0] = 0.0442014612;
+	freq_[1] = 0.1295816316;
+	freq_[2] = 0.0258622052;
+	freq_[3] = 0.0148900471;
+	freq_[4] = 0.0076165815;
+	freq_[5] = 0.1301765579;
+	freq_[6] = 0.0636708052;
+	freq_[7] = 0.0105339122;
+	freq_[8] = 0.0662542863;
+	freq_[9] = 0.042397724;
+	freq_[10] = 0.1434197528;
+	freq_[11] = 0.1040381429;
+	freq_[12] = 0.0403363621;
+	freq_[13] = 0.0260540342;
+	freq_[14] = 0.008933509;
+	freq_[15] = 0.0242573966;
+	freq_[16] = 0.0317938092;
+	freq_[17] = 0.0077831996;
+	freq_[18] = 0.0309973779;
+	freq_[19] = 0.0472012033;
+}
+
+if (getName()=="C34"){
+	freq_[0] = 0.0571984155;
+	freq_[1] = 0.0034929878;
+	freq_[2] = 0.0031324721;
+	freq_[3] = 0.0012472712;
+	freq_[4] = 0.0113230439;
+	freq_[5] = 0.0025279922;
+	freq_[6] = 0.0040737817;
+	freq_[7] = 0.0030647398;
+	freq_[8] = 0.0020494153;
+	freq_[9] = 0.3131200932;
+	freq_[10] = 0.0901750144;
+	freq_[11] = 0.0034699557;
+	freq_[12] = 0.0242565205;
+	freq_[13] = 0.0112345295;
+	freq_[14] = 0.004819702;
+	freq_[15] = 0.0095675953;
+	freq_[16] = 0.0529842025;
+	freq_[17] = 0.0010645104;
+	freq_[18] = 0.0041851135;
+	freq_[19] = 0.3970126433;
+}
+
+if (getName()=="C35"){
+	freq_[0] = 0.1141963934;
+	freq_[1] = 0.0102229903;
+	freq_[2] = 0.0178644126;
+	freq_[3] = 0.0172307307;
+	freq_[4] = 0.0056978908;
+	freq_[5] = 0.0039055039;
+	freq_[6] = 0.0085974326;
+	freq_[7] = 0.7425714921;
+	freq_[8] = 0.0026414175;
+	freq_[9] = 0.0005602022;
+	freq_[10] = 0.0019872568;
+	freq_[11] = 0.0055400059;
+	freq_[12] = 0.0004739977;
+	freq_[13] = 0.0010663175;
+	freq_[14] = 0.0054302447;
+	freq_[15] = 0.0508318204;
+	freq_[16] = 0.0055408544;
+	freq_[17] = 0.0018890811;
+	freq_[18] = 0.0012409205;
+	freq_[19] = 0.0025110348;
+}
+
+if (getName()=="C36"){
+	freq_[0] = 0.3531758625;
+	freq_[1] = 0.0043402857;
+	freq_[2] = 0.0031812423;
+	freq_[3] = 0.0030024877;
+	freq_[4] = 0.0165711581;
+	freq_[5] = 0.0029126214;
+	freq_[6] = 0.004207769;
+	freq_[7] = 0.45208961;
+	freq_[8] = 0.0021366362;
+	freq_[9] = 0.0063692579;
+	freq_[10] = 0.0120143269;
+	freq_[11] = 0.002258697;
+	freq_[12] = 0.008026013;
+	freq_[13] = 0.0043865828;
+	freq_[14] = 0.0111462027;
+	freq_[15] = 0.0658344033;
+	freq_[16] = 0.018295273;
+	freq_[17] = 0.0010872878;
+	freq_[18] = 0.0023330172;
+	freq_[19] = 0.0266312657;
+}
+
+if (getName()=="C37"){
+	freq_[0] = 0.0310798708;
+	freq_[1] = 0.0234519814;
+	freq_[2] = 0.1273669012;
+	freq_[3] = 0.11979251;
+	freq_[4] = 0.003121696;
+	freq_[5] = 0.0295858842;
+	freq_[6] = 0.0470763446;
+	freq_[7] = 0.4883046368;
+	freq_[8] = 0.0193412101;
+	freq_[9] = 0.0008855622;
+	freq_[10] = 0.003280822;
+	freq_[11] = 0.0408430573;
+	freq_[12] = 0.0014984226;
+	freq_[13] = 0.0016298596;
+	freq_[14] = 0.0063229464;
+	freq_[15] = 0.0423452622;
+	freq_[16] = 0.008279726;
+	freq_[17] = 0.0007718998;
+	freq_[18] = 0.0024996877;
+	freq_[19] = 0.0025217188;
+}
+
+if (getName()=="C38"){
+	freq_[0] = 0.0370340667;
+	freq_[1] = 0.0689410214;
+	freq_[2] = 0.1704407181;
+	freq_[3] = 0.1041817082;
+	freq_[4] = 0.0018108784;
+	freq_[5] = 0.0715495095;
+	freq_[6] = 0.0659866718;
+	freq_[7] = 0.2159298358;
+	freq_[8] = 0.0443591808;
+	freq_[9] = 0.0008668888;
+	freq_[10] = 0.0064679416;
+	freq_[11] = 0.1275300877;
+	freq_[12] = 0.0027248464;
+	freq_[13] = 0.0014178323;
+	freq_[14] = 0.0060253154;
+	freq_[15] = 0.0534574556;
+	freq_[16] = 0.0147073432;
+	freq_[17] = 0.000799941;
+	freq_[18] = 0.0037708147;
+	freq_[19] = 0.0019979426;
+}
+
+if (getName()=="C39"){
+	freq_[0] = 0.0160398536;
+	freq_[1] = 0.0526622999;
+	freq_[2] = 0.1051167149;
+	freq_[3] = 0.0187352256;
+	freq_[4] = 0.0085330116;
+	freq_[5] = 0.0922616498;
+	freq_[6] = 0.0154450839;
+	freq_[7] = 0.0076235155;
+	freq_[8] = 0.3848449137;
+	freq_[9] = 0.0057129406;
+	freq_[10] = 0.0277195224;
+	freq_[11] = 0.021934738;
+	freq_[12] = 0.0071078308;
+	freq_[13] = 0.0376358992;
+	freq_[14] = 0.0072201969;
+	freq_[15] = 0.0209969653;
+	freq_[16] = 0.0142198783;
+	freq_[17] = 0.0096946226;
+	freq_[18] = 0.1384243143;
+	freq_[19] = 0.0080708232;
+}
+
+if (getName()=="C40"){
+	freq_[0] = 0.0165549167;
+	freq_[1] = 0.0085856833;
+	freq_[2] = 0.0049441851;
+	freq_[3] = 0.001656738;
+	freq_[4] = 0.0086529073;
+	freq_[5] = 0.0184087838;
+	freq_[6] = 0.0033759867;
+	freq_[7] = 0.0033844413;
+	freq_[8] = 0.0084695063;
+	freq_[9] = 0.0483923758;
+	freq_[10] = 0.4963073963;
+	freq_[11] = 0.0056997331;
+	freq_[12] = 0.1949377866;
+	freq_[13] = 0.099952714;
+	freq_[14] = 0.0060271256;
+	freq_[15] = 0.0084289585;
+	freq_[16] = 0.0122619536;
+	freq_[17] = 0.0114013282;
+	freq_[18] = 0.0192314834;
+	freq_[19] = 0.0233259964;
+}
+
+if (getName()=="C41"){
+	freq_[0] = 0.0227379959;
+	freq_[1] = 0.0137060298;
+	freq_[2] = 0.3162561805;
+	freq_[3] = 0.2932103363;
+	freq_[4] = 0.0037073869;
+	freq_[5] = 0.0169119273;
+	freq_[6] = 0.038098422;
+	freq_[7] = 0.055022476;
+	freq_[8] = 0.0319886436;
+	freq_[9] = 0.003921919;
+	freq_[10] = 0.0041582288;
+	freq_[11] = 0.03125399;
+	freq_[12] = 0.0019467591;
+	freq_[13] = 0.0022276545;
+	freq_[14] = 0.0059660826;
+	freq_[15] = 0.0998736999;
+	freq_[16] = 0.0462336456;
+	freq_[17] = 0.0007310446;
+	freq_[18] = 0.0069012376;
+	freq_[19] = 0.00514634;
+}
+
+if (getName()=="C42"){
+	freq_[0] = 0.2406936002;
+	freq_[1] = 0.0197081082;
+	freq_[2] = 0.0462578641;
+	freq_[3] = 0.0206379264;
+	freq_[4] = 0.0186726798;
+	freq_[5] = 0.0189843646;
+	freq_[6] = 0.0129785315;
+	freq_[7] = 0.1749109142;
+	freq_[8] = 0.0118714342;
+	freq_[9] = 0.0049349532;
+	freq_[10] = 0.0126237761;
+	freq_[11] = 0.0127876711;
+	freq_[12] = 0.0095642661;
+	freq_[13] = 0.0083606873;
+	freq_[14] = 0.0326283314;
+	freq_[15] = 0.2101300187;
+	freq_[16] = 0.1130042042;
+	freq_[17] = 0.00419515;
+	freq_[18] = 0.0069210515;
+	freq_[19] = 0.0201344675;
+}
+
+if (getName()=="C43"){
+	freq_[0] = 0.0214325714;
+	freq_[1] = 0.3730744306;
+	freq_[2] = 0.0220674626;
+	freq_[3] = 0.003749529;
+	freq_[4] = 0.0069038342;
+	freq_[5] = 0.067039195;
+	freq_[6] = 0.0159298773;
+	freq_[7] = 0.0126211348;
+	freq_[8] = 0.0284477629;
+	freq_[9] = 0.0102051798;
+	freq_[10] = 0.0242954287;
+	freq_[11] = 0.3272456489;
+	freq_[12] = 0.0093147452;
+	freq_[13] = 0.0036403029;
+	freq_[14] = 0.0070138928;
+	freq_[15] = 0.0216860624;
+	freq_[16] = 0.0232259733;
+	freq_[17] = 0.0030422478;
+	freq_[18] = 0.006536859;
+	freq_[19] = 0.0125278613;
+}
+
+if (getName()=="C44"){
+	freq_[0] = 0.1567707052;
+	freq_[1] = 0.0258059606;
+	freq_[2] = 0.0161658338;
+	freq_[3] = 0.0223946414;
+	freq_[4] = 0.0074382689;
+	freq_[5] = 0.0274455582;
+	freq_[6] = 0.0410010574;
+	freq_[7] = 0.0360501033;
+	freq_[8] = 0.015997268;
+	freq_[9] = 0.0640941463;
+	freq_[10] = 0.0944756654;
+	freq_[11] = 0.0192586366;
+	freq_[12] = 0.0312789234;
+	freq_[13] = 0.0227728534;
+	freq_[14] = 0.1653169011;
+	freq_[15] = 0.0640177954;
+	freq_[16] = 0.0549103568;
+	freq_[17] = 0.0050980224;
+	freq_[18] = 0.0138248643;
+	freq_[19] = 0.1158824381;
+}
+
+if (getName()=="C45"){
+	freq_[0] = 0.4345912387;
+	freq_[1] = 0.0061142999;
+	freq_[2] = 0.0097660767;
+	freq_[3] = 0.0060102195;
+	freq_[4] = 0.0197377879;
+	freq_[5] = 0.0069062805;
+	freq_[6] = 0.0082800652;
+	freq_[7] = 0.0829075516;
+	freq_[8] = 0.0029125126;
+	freq_[9] = 0.0047747098;
+	freq_[10] = 0.0054182241;
+	freq_[11] = 0.0049974525;
+	freq_[12] = 0.0039676868;
+	freq_[13] = 0.0029052002;
+	freq_[14] = 0.0193588692;
+	freq_[15] = 0.2795854727;
+	freq_[16] = 0.0677816788;
+	freq_[17] = 0.0008196092;
+	freq_[18] = 0.0025196339;
+	freq_[19] = 0.0306454302;
+}
+
+if (getName()=="C46"){
+	freq_[0] = 0.0296734965;
+	freq_[1] = 0.1443250343;
+	freq_[2] = 0.012866816;
+	freq_[3] = 0.0059561454;
+	freq_[4] = 0.0129805897;
+	freq_[5] = 0.0492311054;
+	freq_[6] = 0.0262726056;
+	freq_[7] = 0.0069437743;
+	freq_[8] = 0.0676183913;
+	freq_[9] = 0.045236416;
+	freq_[10] = 0.1374511139;
+	freq_[11] = 0.0907089722;
+	freq_[12] = 0.0308070846;
+	freq_[13] = 0.0816441785;
+	freq_[14] = 0.0060701025;
+	freq_[15] = 0.0197130339;
+	freq_[16] = 0.0299715868;
+	freq_[17] = 0.0461468661;
+	freq_[18] = 0.1119414237;
+	freq_[19] = 0.0444412635;
+}
+
+if (getName()=="C47"){
+	freq_[0] = 0.1089911217;
+	freq_[1] = 0.0159187676;
+	freq_[2] = 0.0643054232;
+	freq_[3] = 0.2086425054;
+	freq_[4] = 0.0016540963;
+	freq_[5] = 0.0375565797;
+	freq_[6] = 0.1791004993;
+	freq_[7] = 0.0610564917;
+	freq_[8] = 0.0144660242;
+	freq_[9] = 0.0038322948;
+	freq_[10] = 0.0067778708;
+	freq_[11] = 0.0372270242;
+	freq_[12] = 0.0022817918;
+	freq_[13] = 0.0012634818;
+	freq_[14] = 0.0851792013;
+	freq_[15] = 0.1065821239;
+	freq_[16] = 0.0524401536;
+	freq_[17] = 0.0005901255;
+	freq_[18] = 0.002783606;
+	freq_[19] = 0.0093508169;
+}
+
+if (getName()=="C48"){
+	freq_[0] = 0.1429463629;
+	freq_[1] = 0.0304191716;
+	freq_[2] = 0.0191145368;
+	freq_[3] = 0.0351867799;
+	freq_[4] = 0.0031493079;
+	freq_[5] = 0.0341248336;
+	freq_[6] = 0.0508492526;
+	freq_[7] = 0.0305914291;
+	freq_[8] = 0.0134276644;
+	freq_[9] = 0.0070227247;
+	freq_[10] = 0.0197257013;
+	freq_[11] = 0.0421442438;
+	freq_[12] = 0.0038904796;
+	freq_[13] = 0.0040697467;
+	freq_[14] = 0.4052202085;
+	freq_[15] = 0.0874406009;
+	freq_[16] = 0.0445304918;
+	freq_[17] = 0.0012842531;
+	freq_[18] = 0.0039485525;
+	freq_[19] = 0.0209136585;
+}
+
+if (getName()=="C49"){
+	freq_[0] = 0.0580116857;
+	freq_[1] = 0.0903213669;
+	freq_[2] = 0.0369245281;
+	freq_[3] = 0.0613603988;
+	freq_[4] = 0.0022829951;
+	freq_[5] = 0.2073851382;
+	freq_[6] = 0.2225853236;
+	freq_[7] = 0.015947691;
+	freq_[8] = 0.0311816018;
+	freq_[9] = 0.0068543753;
+	freq_[10] = 0.0217092509;
+	freq_[11] = 0.1504781849;
+	freq_[12] = 0.0084841006;
+	freq_[13] = 0.0020581132;
+	freq_[14] = 0.0046206107;
+	freq_[15] = 0.0276754451;
+	freq_[16] = 0.0321477211;
+	freq_[17] = 0.0011651089;
+	freq_[18] = 0.0051889637;
+	freq_[19] = 0.0136173964;
+}
+
+if (getName()=="C50"){
+	freq_[0] = 0.215354094;
+	freq_[1] = 0.0359173007;
+	freq_[2] = 0.0219927944;
+	freq_[3] = 0.0735128474;
+	freq_[4] = 0.0037017294;
+	freq_[5] = 0.0566408566;
+	freq_[6] = 0.1350375818;
+	freq_[7] = 0.0662986417;
+	freq_[8] = 0.015712178;
+	freq_[9] = 0.0138456188;
+	freq_[10] = 0.0266922211;
+	freq_[11] = 0.0474338339;
+	freq_[12] = 0.00880426;
+	freq_[13] = 0.0035035311;
+	freq_[14] = 0.0739583083;
+	freq_[15] = 0.0921989198;
+	freq_[16] = 0.0575687235;
+	freq_[17] = 0.0019306896;
+	freq_[18] = 0.0044520833;
+	freq_[19] = 0.0454437865;
+}
+
diff --git a/src/Bpp/Phyl/Model/Protein/__CATC50RatesProps b/src/Bpp/Phyl/Model/Protein/__CATC50RatesProps
new file mode 100644
index 0000000..d1c2db5
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__CATC50RatesProps
@@ -0,0 +1,250 @@
+if (getName()=="C1"){
+	rate_ = 1.;
+	proportion_ = 0.0164297003;
+}
+
+if (getName()=="C2"){
+	rate_ = 1.;
+	proportion_ = 0.0273175755;
+}
+
+if (getName()=="C3"){
+	rate_ = 1.;
+	proportion_ = 0.046024761;
+}
+
+if (getName()=="C4"){
+	rate_ = 1.;
+	proportion_ = 0.0084864734;
+}
+
+if (getName()=="C5"){
+	rate_ = 1.;
+	proportion_ = 0.0125389252;
+}
+
+if (getName()=="C6"){
+	rate_ = 1.;
+	proportion_ = 0.0343549036;
+}
+
+if (getName()=="C7"){
+	rate_ = 1.;
+	proportion_ = 0.0130241102;
+}
+
+if (getName()=="C8"){
+	rate_ = 1.;
+	proportion_ = 0.0094755681;
+}
+
+if (getName()=="C9"){
+	rate_ = 1.;
+	proportion_ = 0.0190040551;
+}
+
+if (getName()=="C10"){
+	rate_ = 1.;
+	proportion_ = 0.0151902354;
+}
+
+if (getName()=="C11"){
+	rate_ = 1.;
+	proportion_ = 0.032053476;
+}
+
+if (getName()=="C12"){
+	rate_ = 1.;
+	proportion_ = 0.021005985;
+}
+
+if (getName()=="C13"){
+	rate_ = 1.;
+	proportion_ = 0.0237408547;
+}
+
+if (getName()=="C14"){
+	rate_ = 1.;
+	proportion_ = 0.0239841203;
+}
+
+if (getName()=="C15"){
+	rate_ = 1.;
+	proportion_ = 0.0213748021;
+}
+
+if (getName()=="C16"){
+	rate_ = 1.;
+	proportion_ = 0.0210717705;
+}
+
+if (getName()=="C17"){
+	rate_ = 1.;
+	proportion_ = 0.0050241805;
+}
+
+if (getName()=="C18"){
+	rate_ = 1.;
+	proportion_ = 0.0166262276;
+}
+
+if (getName()=="C19"){
+	rate_ = 1.;
+	proportion_ = 0.0143945956;
+}
+
+if (getName()=="C20"){
+	rate_ = 1.;
+	proportion_ = 0.010439113;
+}
+
+if (getName()=="C21"){
+	rate_ = 1.;
+	proportion_ = 0.0107628277;
+}
+
+if (getName()=="C22"){
+	rate_ = 1.;
+	proportion_ = 0.0148818171;
+}
+
+if (getName()=="C23"){
+	rate_ = 1.;
+	proportion_ = 0.0321480239;
+}
+
+if (getName()=="C24"){
+	rate_ = 1.;
+	proportion_ = 0.0145477978;
+}
+
+if (getName()=="C25"){
+	rate_ = 1.;
+	proportion_ = 0.0332355807;
+}
+
+if (getName()=="C26"){
+	rate_ = 1.;
+	proportion_ = 0.0143190281;
+}
+
+if (getName()=="C27"){
+	rate_ = 1.;
+	proportion_ = 0.0234478734;
+}
+
+if (getName()=="C28"){
+	rate_ = 1.;
+	proportion_ = 0.0183044983;
+}
+
+if (getName()=="C29"){
+	rate_ = 1.;
+	proportion_ = 0.0403269452;
+}
+
+if (getName()=="C30"){
+	rate_ = 1.;
+	proportion_ = 0.013562953;
+}
+
+if (getName()=="C31"){
+	rate_ = 1.;
+	proportion_ = 0.0091880799;
+}
+
+if (getName()=="C32"){
+	rate_ = 1.;
+	proportion_ = 0.0158270022;
+}
+
+if (getName()=="C33"){
+	rate_ = 1.;
+	proportion_ = 0.0121019379;
+}
+
+if (getName()=="C34"){
+	rate_ = 1.;
+	proportion_ = 0.0353560982;
+}
+
+if (getName()=="C35"){
+	rate_ = 1.;
+	proportion_ = 0.0404495617;
+}
+
+if (getName()=="C36"){
+	rate_ = 1.;
+	proportion_ = 0.0104569232;
+}
+
+if (getName()=="C37"){
+	rate_ = 1.;
+	proportion_ = 0.0146187792;
+}
+
+if (getName()=="C38"){
+	rate_ = 1.;
+	proportion_ = 0.0093984095;
+}
+
+if (getName()=="C39"){
+	rate_ = 1.;
+	proportion_ = 0.0146773809;
+}
+
+if (getName()=="C40"){
+	rate_ = 1.;
+	proportion_ = 0.0201635562;
+}
+
+if (getName()=="C41"){
+	rate_ = 1.;
+	proportion_ = 0.0255640273;
+}
+
+if (getName()=="C42"){
+	rate_ = 1.;
+	proportion_ = 0.0039486842;
+}
+
+if (getName()=="C43"){
+	rate_ = 1.;
+	proportion_ = 0.0393652608;
+}
+
+if (getName()=="C44"){
+	rate_ = 1.;
+	proportion_ = 0.0056415419;
+}
+
+if (getName()=="C45"){
+	rate_ = 1.;
+	proportion_ = 0.038283358;
+}
+
+if (getName()=="C46"){
+	rate_ = 1.;
+	proportion_ = 0.0039735086;
+}
+
+if (getName()=="C47"){
+	rate_ = 1.;
+	proportion_ = 0.0140269355;
+}
+
+if (getName()=="C48"){
+	rate_ = 1.;
+	proportion_ = 0.0476703673;
+}
+
+if (getName()=="C49"){
+	rate_ = 1.;
+	proportion_ = 0.0204062788;
+}
+
+if (getName()=="C50"){
+	rate_ = 1.;
+	proportion_ = 0.0117835304;
+}
+
diff --git a/src/Bpp/Phyl/Model/Protein/__CATC60FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__CATC60FrequenciesCode
new file mode 100644
index 0000000..beef058
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__CATC60FrequenciesCode
@@ -0,0 +1,1380 @@
+if (getName()=="C1"){
+	freq_[0] = 0.1534363248;
+	freq_[1] = 0.0444389067;
+	freq_[2] = 0.079672699;
+	freq_[3] = 0.0546757288;
+	freq_[4] = 0.0047306596;
+	freq_[5] = 0.0514333025;
+	freq_[6] = 0.0529324359;
+	freq_[7] = 0.1103775749;
+	freq_[8] = 0.0174480218;
+	freq_[9] = 0.0050343887;
+	freq_[10] = 0.013029416;
+	freq_[11] = 0.0603928711;
+	freq_[12] = 0.0075550589;
+	freq_[13] = 0.0035554315;
+	freq_[14] = 0.0249523704;
+	freq_[15] = 0.2029625968;
+	freq_[16] = 0.0957668473;
+	freq_[17] = 0.0014444483;
+	freq_[18] = 0.0059800307;
+	freq_[19] = 0.0101808864;
+}
+
+if (getName()=="C2"){
+	freq_[0] = 0.0281984692;
+	freq_[1] = 0.3031055487;
+	freq_[2] = 0.0312954609;
+	freq_[3] = 0.009154935;
+	freq_[4] = 0.0019503463;
+	freq_[5] = 0.0939884393;
+	freq_[6] = 0.038853014;
+	freq_[7] = 0.0084028325;
+	freq_[8] = 0.0155384715;
+	freq_[9] = 0.0107872879;
+	freq_[10] = 0.0217786594;
+	freq_[11] = 0.3476042929;
+	freq_[12] = 0.0109904917;
+	freq_[13] = 0.0015919288;
+	freq_[14] = 0.0071539896;
+	freq_[15] = 0.0197479052;
+	freq_[16] = 0.0328352333;
+	freq_[17] = 0.0009209994;
+	freq_[18] = 0.0025714024;
+	freq_[19] = 0.0135302919;
+}
+
+if (getName()=="C3"){
+	freq_[0] = 0.008368074;
+	freq_[1] = 0.0007319768;
+	freq_[2] = 0.0006123446;
+	freq_[3] = 0.0002228366;
+	freq_[4] = 0.002043387;
+	freq_[5] = 0.0009498685;
+	freq_[6] = 0.0004731544;
+	freq_[7] = 0.0004825748;
+	freq_[8] = 0.0005189995;
+	freq_[9] = 0.3768453098;
+	freq_[10] = 0.2608334606;
+	freq_[11] = 0.0006296168;
+	freq_[12] = 0.0315700586;
+	freq_[13] = 0.0123984358;
+	freq_[14] = 0.0009595916;
+	freq_[15] = 0.0009746383;
+	freq_[16] = 0.0049990761;
+	freq_[17] = 0.0008657759;
+	freq_[18] = 0.0017132332;
+	freq_[19] = 0.2938075872;
+}
+
+if (getName()=="C4"){
+	freq_[0] = 0.2227229348;
+	freq_[1] = 0.0064846074;
+	freq_[2] = 0.0061206496;
+	freq_[3] = 0.0007997588;
+	freq_[4] = 0.1640285908;
+	freq_[5] = 0.0051051888;
+	freq_[6] = 0.0027280806;
+	freq_[7] = 0.020270252;
+	freq_[8] = 0.0037183875;
+	freq_[9] = 0.0455406072;
+	freq_[10] = 0.0883350071;
+	freq_[11] = 0.0022832871;
+	freq_[12] = 0.0348094559;
+	freq_[13] = 0.0228667054;
+	freq_[14] = 0.0035471579;
+	freq_[15] = 0.0850040072;
+	freq_[16] = 0.1012848285;
+	freq_[17] = 0.0048424833;
+	freq_[18] = 0.0096500033;
+	freq_[19] = 0.1698580069;
+}
+
+if (getName()=="C5"){
+	freq_[0] = 0.0412139519;
+	freq_[1] = 0.0067627055;
+	freq_[2] = 0.005106769;
+	freq_[3] = 0.0017434391;
+	freq_[4] = 0.0204715649;
+	freq_[5] = 0.0057538477;
+	freq_[6] = 0.0037263409;
+	freq_[7] = 0.0069107492;
+	freq_[8] = 0.0180293946;
+	freq_[9] = 0.1154281623;
+	freq_[10] = 0.1693562458;
+	freq_[11] = 0.004290027;
+	freq_[12] = 0.0414066566;
+	freq_[13] = 0.2239001858;
+	freq_[14] = 0.005841641;
+	freq_[15] = 0.0149106129;
+	freq_[16] = 0.0239548406;
+	freq_[17] = 0.0332237129;
+	freq_[18] = 0.1379349474;
+	freq_[19] = 0.1200342049;
+}
+
+if (getName()=="C6"){
+	freq_[0] = 0.0480550249;
+	freq_[1] = 0.0308438053;
+	freq_[2] = 0.0940628721;
+	freq_[3] = 0.2084606133;
+	freq_[4] = 0.0037801787;
+	freq_[5] = 0.0747676701;
+	freq_[6] = 0.1855184661;
+	freq_[7] = 0.0191402239;
+	freq_[8] = 0.087216235;
+	freq_[9] = 0.0094685435;
+	freq_[10] = 0.0277340828;
+	freq_[11] = 0.0375741243;
+	freq_[12] = 0.0088308358;
+	freq_[13] = 0.0196000958;
+	freq_[14] = 0.0081267777;
+	freq_[15] = 0.0439680761;
+	freq_[16] = 0.0324588883;
+	freq_[17] = 0.003466572;
+	freq_[18] = 0.0387499964;
+	freq_[19] = 0.0181769181;
+}
+
+if (getName()=="C7"){
+	freq_[0] = 0.0062848745;
+	freq_[1] = 0.0026246919;
+	freq_[2] = 0.003034251;
+	freq_[3] = 0.0005324147;
+	freq_[4] = 0.0073027627;
+	freq_[5] = 0.0034409089;
+	freq_[6] = 0.0009741492;
+	freq_[7] = 0.0019578159;
+	freq_[8] = 0.0102225186;
+	freq_[9] = 0.0180592309;
+	freq_[10] = 0.1179064681;
+	freq_[11] = 0.0016205916;
+	freq_[12] = 0.0234721825;
+	freq_[13] = 0.3974552519;
+	freq_[14] = 0.0020165583;
+	freq_[15] = 0.0056903327;
+	freq_[16] = 0.0037091821;
+	freq_[17] = 0.0598639097;
+	freq_[18] = 0.3185565304;
+	freq_[19] = 0.0152753744;
+}
+
+if (getName()=="C8"){
+	freq_[0] = 0.181500556;
+	freq_[1] = 0.0026845411;
+	freq_[2] = 0.0148484537;
+	freq_[3] = 0.0025145485;
+	freq_[4] = 0.420563392;
+	freq_[5] = 0.0014097001;
+	freq_[6] = 0.0007088144;
+	freq_[7] = 0.0461854175;
+	freq_[8] = 0.0014374605;
+	freq_[9] = 0.0041745536;
+	freq_[10] = 0.0098310464;
+	freq_[11] = 0.0006474254;
+	freq_[12] = 0.0041611385;
+	freq_[13] = 0.0068976432;
+	freq_[14] = 0.0038767247;
+	freq_[15] = 0.186453705;
+	freq_[16] = 0.0687189855;
+	freq_[17] = 0.0027083549;
+	freq_[18] = 0.0061033012;
+	freq_[19] = 0.0345742379;
+}
+
+if (getName()=="C9"){
+	freq_[0] = 0.0600740822;
+	freq_[1] = 0.0367642654;
+	freq_[2] = 0.0134869242;
+	freq_[3] = 0.0170572285;
+	freq_[4] = 0.007071977;
+	freq_[5] = 0.0142469806;
+	freq_[6] = 0.0127486975;
+	freq_[7] = 0.0343564471;
+	freq_[8] = 0.0305859029;
+	freq_[9] = 0.0204571345;
+	freq_[10] = 0.0994551128;
+	freq_[11] = 0.0212367087;
+	freq_[12] = 0.0318165939;
+	freq_[13] = 0.1140907926;
+	freq_[14] = 0.0297628218;
+	freq_[15] = 0.0505792699;
+	freq_[16] = 0.0339368402;
+	freq_[17] = 0.2312808862;
+	freq_[18] = 0.1192491702;
+	freq_[19] = 0.0217421638;
+}
+
+if (getName()=="C10"){
+	freq_[0] = 0.0708394513;
+	freq_[1] = 0.0474098489;
+	freq_[2] = 0.0416822304;
+	freq_[3] = 0.0324482918;
+	freq_[4] = 0.0131641265;
+	freq_[5] = 0.0494874703;
+	freq_[6] = 0.0508264389;
+	freq_[7] = 0.0183309196;
+	freq_[8] = 0.0567272697;
+	freq_[9] = 0.0650369079;
+	freq_[10] = 0.1282255556;
+	freq_[11] = 0.0343618389;
+	freq_[12] = 0.039036293;
+	freq_[13] = 0.0594359563;
+	freq_[14] = 0.0135608209;
+	freq_[15] = 0.0551343199;
+	freq_[16] = 0.0642260358;
+	freq_[17] = 0.0137118382;
+	freq_[18] = 0.0673934289;
+	freq_[19] = 0.0789609573;
+}
+
+if (getName()=="C11"){
+	freq_[0] = 0.0617689371;
+	freq_[1] = 0.0076332888;
+	freq_[2] = 0.0303081645;
+	freq_[3] = 0.3430234188;
+	freq_[4] = 0.0007199837;
+	freq_[5] = 0.0307856241;
+	freq_[6] = 0.3792509407;
+	freq_[7] = 0.0284658686;
+	freq_[8] = 0.007959212;
+	freq_[9] = 0.0016999627;
+	freq_[10] = 0.0039945339;
+	freq_[11] = 0.0216076877;
+	freq_[12] = 0.0019734329;
+	freq_[13] = 0.0009814186;
+	freq_[14] = 0.0174791407;
+	freq_[15] = 0.033783194;
+	freq_[16] = 0.0203426591;
+	freq_[17] = 0.0006130268;
+	freq_[18] = 0.0017102752;
+	freq_[19] = 0.00589923;
+}
+
+if (getName()=="C12"){
+	freq_[0] = 0.0421559537;
+	freq_[1] = 0.1042068314;
+	freq_[2] = 0.0286980872;
+	freq_[3] = 0.016438524;
+	freq_[4] = 0.004445033;
+	freq_[5] = 0.1393690851;
+	freq_[6] = 0.0531949072;
+	freq_[7] = 0.0134711207;
+	freq_[8] = 0.0177764997;
+	freq_[9] = 0.0267727728;
+	freq_[10] = 0.1967237776;
+	freq_[11] = 0.1323735242;
+	freq_[12] = 0.1182827521;
+	freq_[13] = 0.0086728324;
+	freq_[14] = 0.005183788;
+	freq_[15] = 0.0255852718;
+	freq_[16] = 0.033329202;
+	freq_[17] = 0.0045852327;
+	freq_[18] = 0.0070281498;
+	freq_[19] = 0.0217066546;
+}
+
+if (getName()=="C13"){
+	freq_[0] = 0.2814809927;
+	freq_[1] = 0.0100367066;
+	freq_[2] = 0.0172867775;
+	freq_[3] = 0.0064385734;
+	freq_[4] = 0.0258337508;
+	freq_[5] = 0.0133101925;
+	freq_[6] = 0.011504641;
+	freq_[7] = 0.0270054934;
+	freq_[8] = 0.0054629657;
+	freq_[9] = 0.0188216093;
+	freq_[10] = 0.0190993462;
+	freq_[11] = 0.0098712843;
+	freq_[12] = 0.0158719589;
+	freq_[13] = 0.0050481705;
+	freq_[14] = 0.0129510033;
+	freq_[15] = 0.18868086;
+	freq_[16] = 0.2427104979;
+	freq_[17] = 0.0012274627;
+	freq_[18] = 0.0036052922;
+	freq_[19] = 0.0837524211;
+}
+
+if (getName()=="C14"){
+	freq_[0] = 0.276918832;
+	freq_[1] = 0.0017226995;
+	freq_[2] = 0.0021315271;
+	freq_[3] = 0.0011672545;
+	freq_[4] = 0.0318292645;
+	freq_[5] = 0.0018216251;
+	freq_[6] = 0.0024752467;
+	freq_[7] = 0.0199646887;
+	freq_[8] = 0.0005170863;
+	freq_[9] = 0.0983109006;
+	freq_[10] = 0.0489264326;
+	freq_[11] = 0.0016232163;
+	freq_[12] = 0.0173414948;
+	freq_[13] = 0.0070843906;
+	freq_[14] = 0.0070179705;
+	freq_[15] = 0.0336348952;
+	freq_[16] = 0.0814141404;
+	freq_[17] = 0.0007118144;
+	freq_[18] = 0.0032942319;
+	freq_[19] = 0.3620922883;
+}
+
+if (getName()=="C15"){
+	freq_[0] = 0.1577797792;
+	freq_[1] = 0.111214027;
+	freq_[2] = 0.0570403237;
+	freq_[3] = 0.0648290471;
+	freq_[4] = 0.0053318076;
+	freq_[5] = 0.1065373681;
+	freq_[6] = 0.0913586945;
+	freq_[7] = 0.0906209718;
+	freq_[8] = 0.0533809635;
+	freq_[9] = 0.0029171632;
+	freq_[10] = 0.0156225571;
+	freq_[11] = 0.0782148712;
+	freq_[12] = 0.0045758969;
+	freq_[13] = 0.0025047816;
+	freq_[14] = 0.0067077844;
+	freq_[15] = 0.0929310045;
+	freq_[16] = 0.0393122597;
+	freq_[17] = 0.0028575821;
+	freq_[18] = 0.0077590269;
+	freq_[19] = 0.0085040899;
+}
+
+if (getName()=="C16"){
+	freq_[0] = 0.0593735135;
+	freq_[1] = 0.0354740772;
+	freq_[2] = 0.1151175314;
+	freq_[3] = 0.2189482708;
+	freq_[4] = 0.0015332173;
+	freq_[5] = 0.0688752402;
+	freq_[6] = 0.1819422913;
+	freq_[7] = 0.0813707101;
+	freq_[8] = 0.0220478285;
+	freq_[9] = 0.0020993577;
+	freq_[10] = 0.0056191259;
+	freq_[11] = 0.0750172075;
+	freq_[12] = 0.0021871739;
+	freq_[13] = 0.0010838321;
+	freq_[14] = 0.0109737422;
+	freq_[15] = 0.0726449461;
+	freq_[16] = 0.0380238271;
+	freq_[17] = 0.000734646;
+	freq_[18] = 0.0026664883;
+	freq_[19] = 0.0042669729;
+}
+
+if (getName()=="C17"){
+	freq_[0] = 0.0978066326;
+	freq_[1] = 0.0265576438;
+	freq_[2] = 0.0101843505;
+	freq_[3] = 0.0120781428;
+	freq_[4] = 0.0064138404;
+	freq_[5] = 0.0307876446;
+	freq_[6] = 0.0291282947;
+	freq_[7] = 0.0128912798;
+	freq_[8] = 0.0128036716;
+	freq_[9] = 0.0723904209;
+	freq_[10] = 0.127943895;
+	freq_[11] = 0.0245630658;
+	freq_[12] = 0.0303267312;
+	freq_[13] = 0.0198963719;
+	freq_[14] = 0.2723524069;
+	freq_[15] = 0.0350549441;
+	freq_[16] = 0.048455734;
+	freq_[17] = 0.0046842467;
+	freq_[18] = 0.0104773833;
+	freq_[19] = 0.1152032995;
+}
+
+if (getName()=="C18"){
+	freq_[0] = 0.0124023388;
+	freq_[1] = 0.0030680354;
+	freq_[2] = 0.0009239105;
+	freq_[3] = 0.0006037316;
+	freq_[4] = 0.0041885695;
+	freq_[5] = 0.0032957441;
+	freq_[6] = 0.0012524;
+	freq_[7] = 0.0011306791;
+	freq_[8] = 0.0013542104;
+	freq_[9] = 0.2344167852;
+	freq_[10] = 0.4550557697;
+	freq_[11] = 0.0016718177;
+	freq_[12] = 0.0667307666;
+	freq_[13] = 0.0610615367;
+	freq_[14] = 0.0037076169;
+	freq_[15] = 0.0019420934;
+	freq_[16] = 0.0067612939;
+	freq_[17] = 0.0038937184;
+	freq_[18] = 0.0074911765;
+	freq_[19] = 0.1290478057;
+}
+
+if (getName()=="C19"){
+	freq_[0] = 0.0794230623;
+	freq_[1] = 0.1294739355;
+	freq_[2] = 0.0662792725;
+	freq_[3] = 0.0587236242;
+	freq_[4] = 0.0019919499;
+	freq_[5] = 0.1143880588;
+	freq_[6] = 0.1246900644;
+	freq_[7] = 0.0325432311;
+	freq_[8] = 0.0238605372;
+	freq_[9] = 0.003627715;
+	freq_[10] = 0.0097987961;
+	freq_[11] = 0.2147597316;
+	freq_[12] = 0.0041846209;
+	freq_[13] = 0.0012869951;
+	freq_[14] = 0.0142410239;
+	freq_[15] = 0.0615807386;
+	freq_[16] = 0.0477333594;
+	freq_[17] = 0.0006525371;
+	freq_[18] = 0.0029420233;
+	freq_[19] = 0.0078187231;
+}
+
+if (getName()=="C20"){
+	freq_[0] = 0.0248148778;
+	freq_[1] = 0.008355291;
+	freq_[2] = 0.1888915388;
+	freq_[3] = 0.4278832998;
+	freq_[4] = 0.0027839717;
+	freq_[5] = 0.0210777725;
+	freq_[6] = 0.1432386297;
+	freq_[7] = 0.0643968435;
+	freq_[8] = 0.018573687;
+	freq_[9] = 0.0022506941;
+	freq_[10] = 0.0034558626;
+	freq_[11] = 0.0179274104;
+	freq_[12] = 0.0015714503;
+	freq_[13] = 0.0014680353;
+	freq_[14] = 0.0073768035;
+	freq_[15] = 0.0377003132;
+	freq_[16] = 0.0187767966;
+	freq_[17] = 0.0005891859;
+	freq_[18] = 0.0042602708;
+	freq_[19] = 0.0046072655;
+}
+
+if (getName()=="C21"){
+	freq_[0] = 0.0017003427;
+	freq_[1] = 0.006067433;
+	freq_[2] = 0.00042229;
+	freq_[3] = 0.001071149;
+	freq_[4] = 0.002905942;
+	freq_[5] = 0.0016424179;
+	freq_[6] = 0.0011731741;
+	freq_[7] = 0.0035579609;
+	freq_[8] = 0.0027630465;
+	freq_[9] = 0.001229119;
+	freq_[10] = 0.012742081;
+	freq_[11] = 0.0004273804;
+	freq_[12] = 0.0025671348;
+	freq_[13] = 0.0513377024;
+	freq_[14] = 0.0013536738;
+	freq_[15] = 0.0011871674;
+	freq_[16] = 0.0014033068;
+	freq_[17] = 0.8640436936;
+	freq_[18] = 0.0390912582;
+	freq_[19] = 0.0033137266;
+}
+
+if (getName()=="C22"){
+	freq_[0] = 0.0468360682;
+	freq_[1] = 0.0639796924;
+	freq_[2] = 0.0205603686;
+	freq_[3] = 0.0185615516;
+	freq_[4] = 0.0059954138;
+	freq_[5] = 0.0557030821;
+	freq_[6] = 0.0705436036;
+	freq_[7] = 0.0045435329;
+	freq_[8] = 0.0152062773;
+	freq_[9] = 0.1550613356;
+	freq_[10] = 0.0824253382;
+	freq_[11] = 0.0866248354;
+	freq_[12] = 0.0245854443;
+	freq_[13] = 0.0080177192;
+	freq_[14] = 0.0081485616;
+	freq_[15] = 0.0237025617;
+	freq_[16] = 0.0962054496;
+	freq_[17] = 0.0018368673;
+	freq_[18] = 0.0067131723;
+	freq_[19] = 0.2047491243;
+}
+
+if (getName()=="C23"){
+	freq_[0] = 0.0258764792;
+	freq_[1] = 0.0201097124;
+	freq_[2] = 0.0298384107;
+	freq_[3] = 0.0107037437;
+	freq_[4] = 0.0142503909;
+	freq_[5] = 0.0158529432;
+	freq_[6] = 0.0105649532;
+	freq_[7] = 0.0073064999;
+	freq_[8] = 0.1411078834;
+	freq_[9] = 0.0114777629;
+	freq_[10] = 0.0407992414;
+	freq_[11] = 0.0119179202;
+	freq_[12] = 0.0098798997;
+	freq_[13] = 0.1876429961;
+	freq_[14] = 0.0051228805;
+	freq_[15] = 0.0275699644;
+	freq_[16] = 0.0170764901;
+	freq_[17] = 0.0405124999;
+	freq_[18] = 0.3536390834;
+	freq_[19] = 0.0187502449;
+}
+
+if (getName()=="C24"){
+	freq_[0] = 0.0296285022;
+	freq_[1] = 0.0046400334;
+	freq_[2] = 0.0034944393;
+	freq_[3] = 0.0008851024;
+	freq_[4] = 0.0090046468;
+	freq_[5] = 0.0055481111;
+	freq_[6] = 0.0033046518;
+	freq_[7] = 0.0027969482;
+	freq_[8] = 0.00507015;
+	freq_[9] = 0.258339775;
+	freq_[10] = 0.2668085481;
+	freq_[11] = 0.0046690936;
+	freq_[12] = 0.0770825277;
+	freq_[13] = 0.0408798247;
+	freq_[14] = 0.0026918193;
+	freq_[15] = 0.0068538089;
+	freq_[16] = 0.0322265673;
+	freq_[17] = 0.0035506055;
+	freq_[18] = 0.0153353414;
+	freq_[19] = 0.2271895033;
+}
+
+if (getName()=="C25"){
+	freq_[0] = 0.0555725806;
+	freq_[1] = 0.0098447861;
+	freq_[2] = 0.040906443;
+	freq_[3] = 0.0140389597;
+	freq_[4] = 0.0097418602;
+	freq_[5] = 0.006872771;
+	freq_[6] = 0.006944319;
+	freq_[7] = 0.0157956555;
+	freq_[8] = 0.0041631258;
+	freq_[9] = 0.0069826497;
+	freq_[10] = 0.0075271247;
+	freq_[11] = 0.0139224817;
+	freq_[12] = 0.0058762687;
+	freq_[13] = 0.003449673;
+	freq_[14] = 0.0119733364;
+	freq_[15] = 0.3482466393;
+	freq_[16] = 0.4213655981;
+	freq_[17] = 0.0010061491;
+	freq_[18] = 0.0026576772;
+	freq_[19] = 0.0131119012;
+}
+
+if (getName()=="C26"){
+	freq_[0] = 0.0682671212;
+	freq_[1] = 0.0615207091;
+	freq_[2] = 0.0530661192;
+	freq_[3] = 0.0360278709;
+	freq_[4] = 0.0141433148;
+	freq_[5] = 0.0612274332;
+	freq_[6] = 0.0497415394;
+	freq_[7] = 0.026869652;
+	freq_[8] = 0.1127674983;
+	freq_[9] = 0.0132646615;
+	freq_[10] = 0.0544493838;
+	freq_[11] = 0.0482609047;
+	freq_[12] = 0.0170033964;
+	freq_[13] = 0.0803375967;
+	freq_[14] = 0.019194985;
+	freq_[15] = 0.0671839752;
+	freq_[16] = 0.0443995774;
+	freq_[17] = 0.0199957919;
+	freq_[18] = 0.1255070748;
+	freq_[19] = 0.0267713947;
+}
+
+if (getName()=="C27"){
+	freq_[0] = 0.0792618808;
+	freq_[1] = 0.0638377192;
+	freq_[2] = 0.0635289371;
+	freq_[3] = 0.0436646174;
+	freq_[4] = 0.0049503302;
+	freq_[5] = 0.0666365188;
+	freq_[6] = 0.0829639117;
+	freq_[7] = 0.0183428565;
+	freq_[8] = 0.0233169239;
+	freq_[9] = 0.0249427251;
+	freq_[10] = 0.0221483402;
+	freq_[11] = 0.0932577596;
+	freq_[12] = 0.012089338;
+	freq_[13] = 0.0049131149;
+	freq_[14] = 0.0126360122;
+	freq_[15] = 0.1334848656;
+	freq_[16] = 0.1916745928;
+	freq_[17] = 0.0018040086;
+	freq_[18] = 0.0062353115;
+	freq_[19] = 0.050310236;
+}
+
+if (getName()=="C28"){
+	freq_[0] = 0.0731759112;
+	freq_[1] = 0.2105335985;
+	freq_[2] = 0.0324200854;
+	freq_[3] = 0.0110007149;
+	freq_[4] = 0.0123458504;
+	freq_[5] = 0.0858951989;
+	freq_[6] = 0.0349942684;
+	freq_[7] = 0.0224509173;
+	freq_[8] = 0.038690328;
+	freq_[9] = 0.0246226304;
+	freq_[10] = 0.0508307349;
+	freq_[11] = 0.1783344831;
+	freq_[12] = 0.018574072;
+	freq_[13] = 0.0093148787;
+	freq_[14] = 0.0148722772;
+	freq_[15] = 0.0603181436;
+	freq_[16] = 0.0649574934;
+	freq_[17] = 0.0051046395;
+	freq_[18] = 0.0130597421;
+	freq_[19] = 0.0385040321;
+}
+
+if (getName()=="C29"){
+	freq_[0] = 0.087840271;
+	freq_[1] = 0.011033175;
+	freq_[2] = 0.0060801213;
+	freq_[3] = 0.0032803903;
+	freq_[4] = 0.0171147088;
+	freq_[5] = 0.0109831614;
+	freq_[6] = 0.010146579;
+	freq_[7] = 0.0087090941;
+	freq_[8] = 0.0054902234;
+	freq_[9] = 0.1987761871;
+	freq_[10] = 0.1756460821;
+	freq_[11] = 0.0082096925;
+	freq_[12] = 0.0417232903;
+	freq_[13] = 0.0191954435;
+	freq_[14] = 0.0111283542;
+	freq_[15] = 0.0209862621;
+	freq_[16] = 0.0697718709;
+	freq_[17] = 0.0031744014;
+	freq_[18] = 0.0081905473;
+	freq_[19] = 0.2825201446;
+}
+
+if (getName()=="C30"){
+	freq_[0] = 0.099021582;
+	freq_[1] = 0.0349351987;
+	freq_[2] = 0.0211149501;
+	freq_[3] = 0.0118797946;
+	freq_[4] = 0.0108995677;
+	freq_[5] = 0.0557710676;
+	freq_[6] = 0.0278999992;
+	freq_[7] = 0.0240250097;
+	freq_[8] = 0.0123445071;
+	freq_[9] = 0.0776564721;
+	freq_[10] = 0.2354511299;
+	freq_[11] = 0.0322817789;
+	freq_[12] = 0.1207665429;
+	freq_[13] = 0.0214442058;
+	freq_[14] = 0.0075655541;
+	freq_[15] = 0.0524170141;
+	freq_[16] = 0.0649785115;
+	freq_[17] = 0.0047075806;
+	freq_[18] = 0.0077328724;
+	freq_[19] = 0.077106661;
+}
+
+if (getName()=="C31"){
+	freq_[0] = 0.0601641168;
+	freq_[1] = 0.0161995226;
+	freq_[2] = 0.2783522747;
+	freq_[3] = 0.0337188808;
+	freq_[4] = 0.0315066987;
+	freq_[5] = 0.0210645987;
+	freq_[6] = 0.0059839451;
+	freq_[7] = 0.054308071;
+	freq_[8] = 0.0531523512;
+	freq_[9] = 0.0070650825;
+	freq_[10] = 0.0070698142;
+	freq_[11] = 0.0139598368;
+	freq_[12] = 0.0088298653;
+	freq_[13] = 0.0069525877;
+	freq_[14] = 0.0075834331;
+	freq_[15] = 0.2829802556;
+	freq_[16] = 0.0860317092;
+	freq_[17] = 0.0014966551;
+	freq_[18] = 0.0134849454;
+	freq_[19] = 0.0100953553;
+}
+
+if (getName()=="C32"){
+	freq_[0] = 0.0049781737;
+	freq_[1] = 0.0018412331;
+	freq_[2] = 0.0007012207;
+	freq_[3] = 0.0005315368;
+	freq_[4] = 0.0052978737;
+	freq_[5] = 0.0024089907;
+	freq_[6] = 0.0007630546;
+	freq_[7] = 0.0015051317;
+	freq_[8] = 0.0041575221;
+	freq_[9] = 0.0443828633;
+	freq_[10] = 0.4417417476;
+	freq_[11] = 0.001161506;
+	freq_[12] = 0.0602807417;
+	freq_[13] = 0.335111714;
+	freq_[14] = 0.0027847686;
+	freq_[15] = 0.0025795769;
+	freq_[16] = 0.0030288544;
+	freq_[17] = 0.0171302592;
+	freq_[18] = 0.0458455751;
+	freq_[19] = 0.023767656;
+}
+
+if (getName()=="C33"){
+	freq_[0] = 0.0251996593;
+	freq_[1] = 0.111446811;
+	freq_[2] = 0.0142031925;
+	freq_[3] = 0.0041012288;
+	freq_[4] = 0.00970995;
+	freq_[5] = 0.0620070749;
+	freq_[6] = 0.0262571641;
+	freq_[7] = 0.0038067269;
+	freq_[8] = 0.0431938935;
+	freq_[9] = 0.0974043253;
+	freq_[10] = 0.2447197423;
+	freq_[11] = 0.0824312856;
+	freq_[12] = 0.0539323021;
+	freq_[13] = 0.0429091639;
+	freq_[14] = 0.0052658505;
+	freq_[15] = 0.0096093107;
+	freq_[16] = 0.0251183002;
+	freq_[17] = 0.01465719;
+	freq_[18] = 0.045696514;
+	freq_[19] = 0.0783303143;
+}
+
+if (getName()=="C34"){
+	freq_[0] = 0.0230361648;
+	freq_[1] = 0.0014748749;
+	freq_[2] = 0.001353439;
+	freq_[3] = 0.0006264439;
+	freq_[4] = 0.0048580122;
+	freq_[5] = 0.0009870046;
+	freq_[6] = 0.0015762583;
+	freq_[7] = 0.0011565336;
+	freq_[8] = 0.0008899238;
+	freq_[9] = 0.395289589;
+	freq_[10] = 0.0576537208;
+	freq_[11] = 0.0014663528;
+	freq_[12] = 0.0140986541;
+	freq_[13] = 0.007212704;
+	freq_[14] = 0.0020177885;
+	freq_[15] = 0.0028770237;
+	freq_[16] = 0.0205580852;
+	freq_[17] = 0.0005477695;
+	freq_[18] = 0.001953908;
+	freq_[19] = 0.4603657493;
+}
+
+if (getName()=="C35"){
+	freq_[0] = 0.1408776963;
+	freq_[1] = 0.0297808449;
+	freq_[2] = 0.0171297613;
+	freq_[3] = 0.0285076933;
+	freq_[4] = 0.0032213718;
+	freq_[5] = 0.0320632225;
+	freq_[6] = 0.0423838922;
+	freq_[7] = 0.0299558472;
+	freq_[8] = 0.0131321477;
+	freq_[9] = 0.0066914481;
+	freq_[10] = 0.0195120028;
+	freq_[11] = 0.0383781635;
+	freq_[12] = 0.0036276863;
+	freq_[13] = 0.0041231064;
+	freq_[14] = 0.4383466229;
+	freq_[15] = 0.0851400095;
+	freq_[16] = 0.0422765692;
+	freq_[17] = 0.0013236871;
+	freq_[18] = 0.0037087638;
+	freq_[19] = 0.0198194632;
+}
+
+if (getName()=="C36"){
+	freq_[0] = 0.444249122;
+	freq_[1] = 0.0050216551;
+	freq_[2] = 0.0102305117;
+	freq_[3] = 0.0057193038;
+	freq_[4] = 0.0235405374;
+	freq_[5] = 0.005599764;
+	freq_[6] = 0.0064889886;
+	freq_[7] = 0.082268771;
+	freq_[8] = 0.0025505743;
+	freq_[9] = 0.0033615104;
+	freq_[10] = 0.0040990063;
+	freq_[11] = 0.0038097073;
+	freq_[12] = 0.0028683069;
+	freq_[13] = 0.0024413211;
+	freq_[14] = 0.016289096;
+	freq_[15] = 0.2999969708;
+	freq_[16] = 0.0559664935;
+	freq_[17] = 0.0007735426;
+	freq_[18] = 0.0020639824;
+	freq_[19] = 0.0226608347;
+}
+
+if (getName()=="C37"){
+	freq_[0] = 0.0898717958;
+	freq_[1] = 0.0070958305;
+	freq_[2] = 0.0130067619;
+	freq_[3] = 0.0129166888;
+	freq_[4] = 0.0044131479;
+	freq_[5] = 0.0023806547;
+	freq_[6] = 0.0058957027;
+	freq_[7] = 0.8087563021;
+	freq_[8] = 0.0016517855;
+	freq_[9] = 0.0004339282;
+	freq_[10] = 0.0015564455;
+	freq_[11] = 0.0033939025;
+	freq_[12] = 0.0004253422;
+	freq_[13] = 0.0008073572;
+	freq_[14] = 0.003412814;
+	freq_[15] = 0.0362876891;
+	freq_[16] = 0.0032887534;
+	freq_[17] = 0.0015223902;
+	freq_[18] = 0.0008537454;
+	freq_[19] = 0.0020289624;
+}
+
+if (getName()=="C38"){
+	freq_[0] = 0.0550840246;
+	freq_[1] = 0.047225426;
+	freq_[2] = 0.1877829604;
+	freq_[3] = 0.1273796123;
+	freq_[4] = 0.0035824944;
+	freq_[5] = 0.0527969268;
+	freq_[6] = 0.065588473;
+	freq_[7] = 0.0637607521;
+	freq_[8] = 0.0404883483;
+	freq_[9] = 0.0075574152;
+	freq_[10] = 0.013630451;
+	freq_[11] = 0.0867682792;
+	freq_[12] = 0.0081684229;
+	freq_[13] = 0.0040375032;
+	freq_[14] = 0.0110681809;
+	freq_[15] = 0.1263380956;
+	freq_[16] = 0.0752544318;
+	freq_[17] = 0.0013563681;
+	freq_[18] = 0.0118590434;
+	freq_[19] = 0.0102727908;
+}
+
+if (getName()=="C39"){
+	freq_[0] = 0.0117681394;
+	freq_[1] = 0.0442558806;
+	freq_[2] = 0.0844144627;
+	freq_[3] = 0.0144712108;
+	freq_[4] = 0.0070388254;
+	freq_[5] = 0.1038342049;
+	freq_[6] = 0.0110901161;
+	freq_[7] = 0.0049626578;
+	freq_[8] = 0.4337194047;
+	freq_[9] = 0.0061337038;
+	freq_[10] = 0.0298794939;
+	freq_[11] = 0.0137928558;
+	freq_[12] = 0.0076237551;
+	freq_[13] = 0.0338266335;
+	freq_[14] = 0.0081346096;
+	freq_[15] = 0.0140571089;
+	freq_[16] = 0.0108276801;
+	freq_[17] = 0.0080683065;
+	freq_[18] = 0.1437251732;
+	freq_[19] = 0.0083757773;
+}
+
+if (getName()=="C40"){
+	freq_[0] = 0.0159285638;
+	freq_[1] = 0.0048098656;
+	freq_[2] = 0.0032692643;
+	freq_[3] = 0.0010966937;
+	freq_[4] = 0.0080519916;
+	freq_[5] = 0.0134552459;
+	freq_[6] = 0.0021324215;
+	freq_[7] = 0.0025086365;
+	freq_[8] = 0.0049192147;
+	freq_[9] = 0.0501543893;
+	freq_[10] = 0.5307634291;
+	freq_[11] = 0.0035599431;
+	freq_[12] = 0.2160085187;
+	freq_[13] = 0.0743650717;
+	freq_[14] = 0.004524735;
+	freq_[15] = 0.0066922196;
+	freq_[16] = 0.0119092283;
+	freq_[17] = 0.0070928134;
+	freq_[18] = 0.0106565111;
+	freq_[19] = 0.0281012433;
+}
+
+if (getName()=="C41"){
+	freq_[0] = 0.0195973253;
+	freq_[1] = 0.0105142992;
+	freq_[2] = 0.3289103336;
+	freq_[3] = 0.3099848991;
+	freq_[4] = 0.0034539049;
+	freq_[5] = 0.0116196758;
+	freq_[6] = 0.02507778;
+	freq_[7] = 0.0627528956;
+	freq_[8] = 0.0295961112;
+	freq_[9] = 0.0032650434;
+	freq_[10] = 0.0028246884;
+	freq_[11] = 0.0240963907;
+	freq_[12] = 0.0008425062;
+	freq_[13] = 0.001970655;
+	freq_[14] = 0.0049062781;
+	freq_[15] = 0.10649845;
+	freq_[16] = 0.0438053705;
+	freq_[17] = 0.0006333959;
+	freq_[18] = 0.0056197958;
+	freq_[19] = 0.0040302013;
+}
+
+if (getName()=="C42"){
+	freq_[0] = 0.083380436;
+	freq_[1] = 0.0125871438;
+	freq_[2] = 0.096982422;
+	freq_[3] = 0.0686820704;
+	freq_[4] = 0.0081981143;
+	freq_[5] = 0.012152093;
+	freq_[6] = 0.0227415415;
+	freq_[7] = 0.0982291876;
+	freq_[8] = 0.0073954898;
+	freq_[9] = 0.0017471177;
+	freq_[10] = 0.0039653113;
+	freq_[11] = 0.0129342146;
+	freq_[12] = 0.0019557975;
+	freq_[13] = 0.0024132583;
+	freq_[14] = 0.0355924232;
+	freq_[15] = 0.3115606483;
+	freq_[16] = 0.2113368612;
+	freq_[17] = 0.0016329034;
+	freq_[18] = 0.0017991083;
+	freq_[19] = 0.0047138579;
+}
+
+if (getName()=="C43"){
+	freq_[0] = 0.0181409133;
+	freq_[1] = 0.4129662563;
+	freq_[2] = 0.0233205154;
+	freq_[3] = 0.0033333547;
+	freq_[4] = 0.0085143598;
+	freq_[5] = 0.0526694251;
+	freq_[6] = 0.0096531879;
+	freq_[7] = 0.0224552642;
+	freq_[8] = 0.0375238929;
+	freq_[9] = 0.0035090482;
+	freq_[10] = 0.0149146621;
+	freq_[11] = 0.320806579;
+	freq_[12] = 0.0046098856;
+	freq_[13] = 0.0035426859;
+	freq_[14] = 0.0087197469;
+	freq_[15] = 0.0262309419;
+	freq_[16] = 0.0131791136;
+	freq_[17] = 0.0034766995;
+	freq_[18] = 0.0079588201;
+	freq_[19] = 0.0044746474;
+}
+
+if (getName()=="C44"){
+	freq_[0] = 0.2494227404;
+	freq_[1] = 0.0185481724;
+	freq_[2] = 0.0164119567;
+	freq_[3] = 0.0169234299;
+	freq_[4] = 0.0122862654;
+	freq_[5] = 0.0228501981;
+	freq_[6] = 0.0370491083;
+	freq_[7] = 0.0347467705;
+	freq_[8] = 0.0087069587;
+	freq_[9] = 0.0595718359;
+	freq_[10] = 0.0451065029;
+	freq_[11] = 0.0177064733;
+	freq_[12] = 0.0204556127;
+	freq_[13] = 0.0077360919;
+	freq_[14] = 0.0686403544;
+	freq_[15] = 0.0889295672;
+	freq_[16] = 0.0986017356;
+	freq_[17] = 0.0028603862;
+	freq_[18] = 0.0061938477;
+	freq_[19] = 0.1672519917;
+}
+
+if (getName()=="C45"){
+	freq_[0] = 0.1419737638;
+	freq_[1] = 0.0373945961;
+	freq_[2] = 0.0576296888;
+	freq_[3] = 0.0537452477;
+	freq_[4] = 0.0068856658;
+	freq_[5] = 0.0286239972;
+	freq_[6] = 0.0407540287;
+	freq_[7] = 0.3988107872;
+	freq_[8] = 0.0152895617;
+	freq_[9] = 0.0016627616;
+	freq_[10] = 0.0092348297;
+	freq_[11] = 0.0314273807;
+	freq_[12] = 0.00554255;
+	freq_[13] = 0.0040286132;
+	freq_[14] = 0.0180328866;
+	freq_[15] = 0.1123731997;
+	freq_[16] = 0.0242478202;
+	freq_[17] = 0.0025909098;
+	freq_[18] = 0.0049054208;
+	freq_[19] = 0.0048462908;
+}
+
+if (getName()=="C46"){
+	freq_[0] = 0.0178903305;
+	freq_[1] = 0.1958843646;
+	freq_[2] = 0.0155853897;
+	freq_[3] = 0.0031054277;
+	freq_[4] = 0.0290304227;
+	freq_[5] = 0.1051819261;
+	freq_[6] = 0.0040503389;
+	freq_[7] = 0.0100480293;
+	freq_[8] = 0.1252696215;
+	freq_[9] = 0.0016708003;
+	freq_[10] = 0.0722356645;
+	freq_[11] = 0.0233340169;
+	freq_[12] = 0.0116142354;
+	freq_[13] = 0.023891326;
+	freq_[14] = 0.0009938415;
+	freq_[15] = 0.0181675536;
+	freq_[16] = 0.0186260222;
+	freq_[17] = 0.2260554691;
+	freq_[18] = 0.0859787232;
+	freq_[19] = 0.0113864962;
+}
+
+if (getName()=="C47"){
+	freq_[0] = 0.1454758367;
+	freq_[1] = 0.0420979067;
+	freq_[2] = 0.040041972;
+	freq_[3] = 0.1294249748;
+	freq_[4] = 0.0014186329;
+	freq_[5] = 0.0906469055;
+	freq_[6] = 0.2471353458;
+	freq_[7] = 0.0319650773;
+	freq_[8] = 0.0130426183;
+	freq_[9] = 0.0058525371;
+	freq_[10] = 0.0123593139;
+	freq_[11] = 0.081815409;
+	freq_[12] = 0.0044178939;
+	freq_[13] = 0.0017552077;
+	freq_[14] = 0.0151135525;
+	freq_[15] = 0.0656688174;
+	freq_[16] = 0.0511289472;
+	freq_[17] = 0.0007731441;
+	freq_[18] = 0.0029258438;
+	freq_[19] = 0.0169400635;
+}
+
+if (getName()=="C48"){
+	freq_[0] = 0.0169799462;
+	freq_[1] = 0.0242346701;
+	freq_[2] = 0.1318047919;
+	freq_[3] = 0.1043655101;
+	freq_[4] = 0.0022087215;
+	freq_[5] = 0.0269349684;
+	freq_[6] = 0.0376379591;
+	freq_[7] = 0.5404470183;
+	freq_[8] = 0.0181137053;
+	freq_[9] = 0.0007459679;
+	freq_[10] = 0.0021146994;
+	freq_[11] = 0.0508617611;
+	freq_[12] = 0.0009473769;
+	freq_[13] = 0.0006780593;
+	freq_[14] = 0.0038754401;
+	freq_[15] = 0.0297030159;
+	freq_[16] = 0.004583618;
+	freq_[17] = 0.0006031889;
+	freq_[18] = 0.001570409;
+	freq_[19] = 0.0015891728;
+}
+
+if (getName()=="C49"){
+	freq_[0] = 0.0402646249;
+	freq_[1] = 0.1152022601;
+	freq_[2] = 0.0323829165;
+	freq_[3] = 0.0293968352;
+	freq_[4] = 0.0039388655;
+	freq_[5] = 0.2497008043;
+	freq_[6] = 0.1603524245;
+	freq_[7] = 0.0129260411;
+	freq_[8] = 0.0617967839;
+	freq_[9] = 0.0098491259;
+	freq_[10] = 0.0354918823;
+	freq_[11] = 0.1448804422;
+	freq_[12] = 0.0124818865;
+	freq_[13] = 0.0041153375;
+	freq_[14] = 0.0043374229;
+	freq_[15] = 0.0243246958;
+	freq_[16] = 0.0305645368;
+	freq_[17] = 0.0026676598;
+	freq_[18] = 0.0097227847;
+	freq_[19] = 0.0156026694;
+}
+
+if (getName()=="C50"){
+	freq_[0] = 0.225691461;
+	freq_[1] = 0.0523417493;
+	freq_[2] = 0.0244308734;
+	freq_[3] = 0.0637125217;
+	freq_[4] = 0.0043390149;
+	freq_[5] = 0.0578159236;
+	freq_[6] = 0.115483064;
+	freq_[7] = 0.0867335173;
+	freq_[8] = 0.0131066949;
+	freq_[9] = 0.0085086217;
+	freq_[10] = 0.0193314218;
+	freq_[11] = 0.0660468804;
+	freq_[12] = 0.0064877206;
+	freq_[13] = 0.0027440054;
+	freq_[14] = 0.0611149102;
+	freq_[15] = 0.1070877179;
+	freq_[16] = 0.0507677144;
+	freq_[17] = 0.0013695913;
+	freq_[18] = 0.0028982948;
+	freq_[19] = 0.0299883012;
+}
+
+if (getName()=="C51"){
+	freq_[0] = 0.0033164209;
+	freq_[1] = 0.0015310773;
+	freq_[2] = 0.0030830171;
+	freq_[3] = 0.0008266472;
+	freq_[4] = 0.005189073;
+	freq_[5] = 0.0011024889;
+	freq_[6] = 0.000513413;
+	freq_[7] = 0.001043283;
+	freq_[8] = 0.0278451262;
+	freq_[9] = 0.0041895268;
+	freq_[10] = 0.0111212494;
+	freq_[11] = 0.0007149922;
+	freq_[12] = 0.002362178;
+	freq_[13] = 0.3801761447;
+	freq_[14] = 0.0008365077;
+	freq_[15] = 0.0035876698;
+	freq_[16] = 0.0023608948;
+	freq_[17] = 0.0333346985;
+	freq_[18] = 0.5107889643;
+	freq_[19] = 0.0060766272;
+}
+
+if (getName()=="C52"){
+	freq_[0] = 0.1995014012;
+	freq_[1] = 0.0236078675;
+	freq_[2] = 0.0392254543;
+	freq_[3] = 0.0094955104;
+	freq_[4] = 0.0584590451;
+	freq_[5] = 0.0254265363;
+	freq_[6] = 0.0125535371;
+	freq_[7] = 0.0939787338;
+	freq_[8] = 0.0341857201;
+	freq_[9] = 0.0140209879;
+	freq_[10] = 0.0449387571;
+	freq_[11] = 0.0118723304;
+	freq_[12] = 0.0246990633;
+	freq_[13] = 0.0634433944;
+	freq_[14] = 0.014538532;
+	freq_[15] = 0.166392064;
+	freq_[16] = 0.0533159207;
+	freq_[17] = 0.0129802666;
+	freq_[18] = 0.0606346163;
+	freq_[19] = 0.0367302614;
+}
+
+if (getName()=="C53"){
+	freq_[0] = 0.0319448994;
+	freq_[1] = 0.1011667268;
+	freq_[2] = 0.208470922;
+	freq_[3] = 0.0378074649;
+	freq_[4] = 0.0066040348;
+	freq_[5] = 0.0766372935;
+	freq_[6] = 0.027948819;
+	freq_[7] = 0.036554113;
+	freq_[8] = 0.2088643258;
+	freq_[9] = 0.0047542347;
+	freq_[10] = 0.0156545731;
+	freq_[11] = 0.0868664783;
+	freq_[12] = 0.0043253317;
+	freq_[13] = 0.0108915768;
+	freq_[14] = 0.0060899575;
+	freq_[15] = 0.0577656939;
+	freq_[16] = 0.030205116;
+	freq_[17] = 0.0026001883;
+	freq_[18] = 0.0387897304;
+	freq_[19] = 0.0060585202;
+}
+
+if (getName()=="C54"){
+	freq_[0] = 0.0776799515;
+	freq_[1] = 0.0142518583;
+	freq_[2] = 0.0403216692;
+	freq_[3] = 0.0080651725;
+	freq_[4] = 0.0140092962;
+	freq_[5] = 0.0179995517;
+	freq_[6] = 0.0112622427;
+	freq_[7] = 0.0136868237;
+	freq_[8] = 0.0133729897;
+	freq_[9] = 0.123963538;
+	freq_[10] = 0.0724670993;
+	freq_[11] = 0.0129144967;
+	freq_[12] = 0.0420745442;
+	freq_[13] = 0.0173584908;
+	freq_[14] = 0.0117084432;
+	freq_[15] = 0.0922723571;
+	freq_[16] = 0.2316899445;
+	freq_[17] = 0.0028153633;
+	freq_[18] = 0.0141726542;
+	freq_[19] = 0.1679135132;
+}
+
+if (getName()=="C55"){
+	freq_[0] = 0.1183662657;
+	freq_[1] = 0.0805192606;
+	freq_[2] = 0.0259524932;
+	freq_[3] = 0.0495595439;
+	freq_[4] = 0.0035624835;
+	freq_[5] = 0.1204924917;
+	freq_[6] = 0.153758921;
+	freq_[7] = 0.0194993426;
+	freq_[8] = 0.0229373171;
+	freq_[9] = 0.0302661211;
+	freq_[10] = 0.0571250629;
+	freq_[11] = 0.0982304112;
+	freq_[12] = 0.0171727472;
+	freq_[13] = 0.0068665705;
+	freq_[14] = 0.017515303;
+	freq_[15] = 0.04865884;
+	freq_[16] = 0.063579621;
+	freq_[17] = 0.0023008307;
+	freq_[18] = 0.0083027431;
+	freq_[19] = 0.05533363;
+}
+
+if (getName()=="C56"){
+	freq_[0] = 0.0528559899;
+	freq_[1] = 0.0193569043;
+	freq_[2] = 0.0264743774;
+	freq_[3] = 0.2092761515;
+	freq_[4] = 0.0008625883;
+	freq_[5] = 0.1212409715;
+	freq_[6] = 0.4024189781;
+	freq_[7] = 0.0155838458;
+	freq_[8] = 0.0124148798;
+	freq_[9] = 0.0054864832;
+	freq_[10] = 0.0090256472;
+	freq_[11] = 0.0497017031;
+	freq_[12] = 0.0042357114;
+	freq_[13] = 0.0012650715;
+	freq_[14] = 0.0063185636;
+	freq_[15] = 0.0197262901;
+	freq_[16] = 0.0235463735;
+	freq_[17] = 0.000838161;
+	freq_[18] = 0.0033948741;
+	freq_[19] = 0.0159764347;
+}
+
+if (getName()=="C57"){
+	freq_[0] = 0.0344366215;
+	freq_[1] = 0.042622182;
+	freq_[2] = 0.1636716191;
+	freq_[3] = 0.1139007491;
+	freq_[4] = 0.0020985982;
+	freq_[5] = 0.0605413987;
+	freq_[6] = 0.054178022;
+	freq_[7] = 0.3361639671;
+	freq_[8] = 0.0461776737;
+	freq_[9] = 0.0003463416;
+	freq_[10] = 0.0048355678;
+	freq_[11] = 0.0667552967;
+	freq_[12] = 0.0019704509;
+	freq_[13] = 0.0031557619;
+	freq_[14] = 0.0040369775;
+	freq_[15] = 0.0481173332;
+	freq_[16] = 0.0089148085;
+	freq_[17] = 0.0006510101;
+	freq_[18] = 0.0054145649;
+	freq_[19] = 0.0020110555;
+}
+
+if (getName()=="C58"){
+	freq_[0] = 0.1153088951;
+	freq_[1] = 0.0151278638;
+	freq_[2] = 0.0458476603;
+	freq_[3] = 0.1755516676;
+	freq_[4] = 0.0014962362;
+	freq_[5] = 0.0366731222;
+	freq_[6] = 0.1749410045;
+	freq_[7] = 0.0394181311;
+	freq_[8] = 0.013240153;
+	freq_[9] = 0.0056912974;
+	freq_[10] = 0.0101409559;
+	freq_[11] = 0.0433118387;
+	freq_[12] = 0.0030332064;
+	freq_[13] = 0.0015700232;
+	freq_[14] = 0.1665802563;
+	freq_[15] = 0.0871536033;
+	freq_[16] = 0.0468260603;
+	freq_[17] = 0.0007515702;
+	freq_[18] = 0.0031432715;
+	freq_[19] = 0.0141931831;
+}
+
+if (getName()=="C59"){
+	freq_[0] = 0.3865149348;
+	freq_[1] = 0.0037579334;
+	freq_[2] = 0.0030420497;
+	freq_[3] = 0.002236681;
+	freq_[4] = 0.0218928357;
+	freq_[5] = 0.0021464743;
+	freq_[6] = 0.0031387843;
+	freq_[7] = 0.3694353983;
+	freq_[8] = 0.0014672902;
+	freq_[9] = 0.0085376076;
+	freq_[10] = 0.0127257242;
+	freq_[11] = 0.0018840458;
+	freq_[12] = 0.0080581695;
+	freq_[13] = 0.0039281367;
+	freq_[14] = 0.0158688291;
+	freq_[15] = 0.0808877279;
+	freq_[16] = 0.0305195935;
+	freq_[17] = 0.000992288;
+	freq_[18] = 0.0019020345;
+	freq_[19] = 0.0410634615;
+}
+
+if (getName()=="C60"){
+	freq_[0] = 0.0146570745;
+	freq_[1] = 0.0028841333;
+	freq_[2] = 0.0012998335;
+	freq_[3] = 0.0005210575;
+	freq_[4] = 0.0024317913;
+	freq_[5] = 0.004936275;
+	freq_[6] = 0.0014874369;
+	freq_[7] = 0.0020953252;
+	freq_[8] = 0.001018194;
+	freq_[9] = 0.1913901476;
+	freq_[10] = 0.4432797758;
+	freq_[11] = 0.0022898369;
+	freq_[12] = 0.2217427062;
+	freq_[13] = 0.0091637503;
+	freq_[14] = 0.0007685153;
+	freq_[15] = 0.0027251487;
+	freq_[16] = 0.0170997497;
+	freq_[17] = 0.000877938;
+	freq_[18] = 0.0014756028;
+	freq_[19] = 0.0778557075;
+}
+
diff --git a/src/Bpp/Phyl/Model/Protein/__CATC60RatesProps b/src/Bpp/Phyl/Model/Protein/__CATC60RatesProps
new file mode 100644
index 0000000..292e0be
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__CATC60RatesProps
@@ -0,0 +1,300 @@
+if (getName()=="C1"){
+	rate_ = 1.;
+	proportion_ = 0.0169698865;
+}
+
+if (getName()=="C2"){
+	rate_ = 1.;
+	proportion_ = 0.0211683374;
+}
+
+if (getName()=="C3"){
+	rate_ = 1.;
+	proportion_ = 0.0276589079;
+}
+
+if (getName()=="C4"){
+	rate_ = 1.;
+	proportion_ = 0.0065675964;
+}
+
+if (getName()=="C5"){
+	rate_ = 1.;
+	proportion_ = 0.0141221416;
+}
+
+if (getName()=="C6"){
+	rate_ = 1.;
+	proportion_ = 0.0068774834;
+}
+
+if (getName()=="C7"){
+	rate_ = 1.;
+	proportion_ = 0.0146909701;
+}
+
+if (getName()=="C8"){
+	rate_ = 1.;
+	proportion_ = 0.0067225777;
+}
+
+if (getName()=="C9"){
+	rate_ = 1.;
+	proportion_ = 0.001839666;
+}
+
+if (getName()=="C10"){
+	rate_ = 1.;
+	proportion_ = 0.0102547197;
+}
+
+if (getName()=="C11"){
+	rate_ = 1.;
+	proportion_ = 0.0230896163;
+}
+
+if (getName()=="C12"){
+	rate_ = 1.;
+	proportion_ = 0.0057941033;
+}
+
+if (getName()=="C13"){
+	rate_ = 1.;
+	proportion_ = 0.0125394534;
+}
+
+if (getName()=="C14"){
+	rate_ = 1.;
+	proportion_ = 0.0204526478;
+}
+
+if (getName()=="C15"){
+	rate_ = 1.;
+	proportion_ = 0.0070629602;
+}
+
+if (getName()=="C16"){
+	rate_ = 1.;
+	proportion_ = 0.0117982741;
+}
+
+if (getName()=="C17"){
+	rate_ = 1.;
+	proportion_ = 0.0068334668;
+}
+
+if (getName()=="C18"){
+	rate_ = 1.;
+	proportion_ = 0.0433775839;
+}
+
+if (getName()=="C19"){
+	rate_ = 1.;
+	proportion_ = 0.0318278731;
+}
+
+if (getName()=="C20"){
+	rate_ = 1.;
+	proportion_ = 0.0222546108;
+}
+
+if (getName()=="C21"){
+	rate_ = 1.;
+	proportion_ = 0.0102264969;
+}
+
+if (getName()=="C22"){
+	rate_ = 1.;
+	proportion_ = 0.0150545891;
+}
+
+if (getName()=="C23"){
+	rate_ = 1.;
+	proportion_ = 0.0134159878;
+}
+
+if (getName()=="C24"){
+	rate_ = 1.;
+	proportion_ = 0.0148552065;
+}
+
+if (getName()=="C25"){
+	rate_ = 1.;
+	proportion_ = 0.0239111516;
+}
+
+if (getName()=="C26"){
+	rate_ = 1.;
+	proportion_ = 0.0128776278;
+}
+
+if (getName()=="C27"){
+	rate_ = 1.;
+	proportion_ = 0.0222318842;
+}
+
+if (getName()=="C28"){
+	rate_ = 1.;
+	proportion_ = 0.0247444742;
+}
+
+if (getName()=="C29"){
+	rate_ = 1.;
+	proportion_ = 0.021427481;
+}
+
+if (getName()=="C30"){
+	rate_ = 1.;
+	proportion_ = 0.0115001882;
+}
+
+if (getName()=="C31"){
+	rate_ = 1.;
+	proportion_ = 0.0076017389;
+}
+
+if (getName()=="C32"){
+	rate_ = 1.;
+	proportion_ = 0.0130258568;
+}
+
+if (getName()=="C33"){
+	rate_ = 1.;
+	proportion_ = 0.0093701965;
+}
+
+if (getName()=="C34"){
+	rate_ = 1.;
+	proportion_ = 0.0467194264;
+}
+
+if (getName()=="C35"){
+	rate_ = 1.;
+	proportion_ = 0.0441940314;
+}
+
+if (getName()=="C36"){
+	rate_ = 1.;
+	proportion_ = 0.0322263154;
+}
+
+if (getName()=="C37"){
+	rate_ = 1.;
+	proportion_ = 0.0402999891;
+}
+
+if (getName()=="C38"){
+	rate_ = 1.;
+	proportion_ = 0.0150234227;
+}
+
+if (getName()=="C39"){
+	rate_ = 1.;
+	proportion_ = 0.0104589903;
+}
+
+if (getName()=="C40"){
+	rate_ = 1.;
+	proportion_ = 0.0214742395;
+}
+
+if (getName()=="C41"){
+	rate_ = 1.;
+	proportion_ = 0.0154957836;
+}
+
+if (getName()=="C42"){
+	rate_ = 1.;
+	proportion_ = 0.0101789953;
+}
+
+if (getName()=="C43"){
+	rate_ = 1.;
+	proportion_ = 0.0227980379;
+}
+
+if (getName()=="C44"){
+	rate_ = 1.;
+	proportion_ = 0.0123204539;
+}
+
+if (getName()=="C45"){
+	rate_ = 1.;
+	proportion_ = 0.0066777583;
+}
+
+if (getName()=="C46"){
+	rate_ = 1.;
+	proportion_ = 0.0004150083;
+}
+
+if (getName()=="C47"){
+	rate_ = 1.;
+	proportion_ = 0.034438513;
+}
+
+if (getName()=="C48"){
+	rate_ = 1.;
+	proportion_ = 0.0113663379;
+}
+
+if (getName()=="C49"){
+	rate_ = 1.;
+	proportion_ = 0.0127143049;
+}
+
+if (getName()=="C50"){
+	rate_ = 1.;
+	proportion_ = 0.0124323741;
+}
+
+if (getName()=="C51"){
+	rate_ = 1.;
+	proportion_ = 0.0262124415;
+}
+
+if (getName()=="C52"){
+	rate_ = 1.;
+	proportion_ = 0.0064994957;
+}
+
+if (getName()=="C53"){
+	rate_ = 1.;
+	proportion_ = 0.0103203293;
+}
+
+if (getName()=="C54"){
+	rate_ = 1.;
+	proportion_ = 0.0142463512;
+}
+
+if (getName()=="C55"){
+	rate_ = 1.;
+	proportion_ = 0.0215600067;
+}
+
+if (getName()=="C56"){
+	rate_ = 1.;
+	proportion_ = 0.01991507;
+}
+
+if (getName()=="C57"){
+	rate_ = 1.;
+	proportion_ = 0.00389642;
+}
+
+if (getName()=="C58"){
+	rate_ = 1.;
+	proportion_ = 0.0113448855;
+}
+
+if (getName()=="C59"){
+	rate_ = 1.;
+	proportion_ = 0.0128595846;
+}
+
+if (getName()=="C60"){
+	rate_ = 1.;
+	proportion_ = 0.0117656776;
+}
+
diff --git a/src/Bpp/Phyl/Model/Protein/__DSO78ExchangeabilityCode b/src/Bpp/Phyl/Model/Protein/__DSO78ExchangeabilityCode
new file mode 100755
index 0000000..54b4f62
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__DSO78ExchangeabilityCode
@@ -0,0 +1,400 @@
+exchangeability_(0,0) = -23.01709;
+exchangeability_(0,1) = 0.267828;
+exchangeability_(0,2) = 0.984474;
+exchangeability_(0,3) = 1.199805;
+exchangeability_(0,4) = 0.360016;
+exchangeability_(0,5) = 0.887753;
+exchangeability_(0,6) = 1.961167;
+exchangeability_(0,7) = 2.386111;
+exchangeability_(0,8) = 0.228116;
+exchangeability_(0,9) = 0.653416;
+exchangeability_(0,10) = 0.406431;
+exchangeability_(0,11) = 0.258635;
+exchangeability_(0,12) = 0.71784;
+exchangeability_(0,13) = 0.183641;
+exchangeability_(0,14) = 2.48592;
+exchangeability_(0,15) = 4.05187;
+exchangeability_(0,16) = 3.680365;
+exchangeability_(0,17) = 0;
+exchangeability_(0,18) = 0.244139;
+exchangeability_(0,19) = 2.059564;
+exchangeability_(1,0) = 0.267828;
+exchangeability_(1,1) = -17.31445;
+exchangeability_(1,2) = 0.327059;
+exchangeability_(1,3) = 0;
+exchangeability_(1,4) = 0.232374;
+exchangeability_(1,5) = 2.439939;
+exchangeability_(1,6) = 0;
+exchangeability_(1,7) = 0.087791;
+exchangeability_(1,8) = 2.383148;
+exchangeability_(1,9) = 0.632629;
+exchangeability_(1,10) = 0.154924;
+exchangeability_(1,11) = 4.610124;
+exchangeability_(1,12) = 0.896321;
+exchangeability_(1,13) = 0.136906;
+exchangeability_(1,14) = 1.028313;
+exchangeability_(1,15) = 1.53159;
+exchangeability_(1,16) = 0.265745;
+exchangeability_(1,17) = 2.001375;
+exchangeability_(1,18) = 0.078012;
+exchangeability_(1,19) = 0.240368;
+exchangeability_(2,0) = 0.984474;
+exchangeability_(2,1) = 0.327059;
+exchangeability_(2,2) = -32.74316;
+exchangeability_(2,3) = 8.931515;
+exchangeability_(2,4) = 0;
+exchangeability_(2,5) = 1.028509;
+exchangeability_(2,6) = 1.493409;
+exchangeability_(2,7) = 1.385352;
+exchangeability_(2,8) = 5.290024;
+exchangeability_(2,9) = 0.768024;
+exchangeability_(2,10) = 0.341113;
+exchangeability_(2,11) = 3.148371;
+exchangeability_(2,12) = 0;
+exchangeability_(2,13) = 0.138503;
+exchangeability_(2,14) = 0.419244;
+exchangeability_(2,15) = 4.885892;
+exchangeability_(2,16) = 2.271697;
+exchangeability_(2,17) = 0.224968;
+exchangeability_(2,18) = 0.94694;
+exchangeability_(2,19) = 0.158067;
+exchangeability_(3,0) = 1.199805;
+exchangeability_(3,1) = 0;
+exchangeability_(3,2) = 8.931515;
+exchangeability_(3,3) = -27.86320;
+exchangeability_(3,4) = 0;
+exchangeability_(3,5) = 1.348551;
+exchangeability_(3,6) = 11.38866;
+exchangeability_(3,7) = 1.240981;
+exchangeability_(3,8) = 0.868241;
+exchangeability_(3,9) = 0.239248;
+exchangeability_(3,10) = 0;
+exchangeability_(3,11) = 0.716913;
+exchangeability_(3,12) = 0;
+exchangeability_(3,13) = 0;
+exchangeability_(3,14) = 0.13394;
+exchangeability_(3,15) = 0.956097;
+exchangeability_(3,16) = 0.66093;
+exchangeability_(3,17) = 0;
+exchangeability_(3,18) = 0;
+exchangeability_(3,19) = 0.178316;
+exchangeability_(4,0) = 0.360016;
+exchangeability_(4,1) = 0.232374;
+exchangeability_(4,2) = 0;
+exchangeability_(4,3) = 0;
+exchangeability_(4,4) = -4.806585;
+exchangeability_(4,5) = 0;
+exchangeability_(4,6) = 0;
+exchangeability_(4,7) = 0.107278;
+exchangeability_(4,8) = 0.282729;
+exchangeability_(4,9) = 0.438074;
+exchangeability_(4,10) = 0;
+exchangeability_(4,11) = 0;
+exchangeability_(4,12) = 0;
+exchangeability_(4,13) = 0;
+exchangeability_(4,14) = 0.18755;
+exchangeability_(4,15) = 1.598356;
+exchangeability_(4,16) = 0.162366;
+exchangeability_(4,17) = 0;
+exchangeability_(4,18) = 0.953164;
+exchangeability_(4,19) = 0.484678;
+exchangeability_(5,0) = 0.887753;
+exchangeability_(5,1) = 2.439939;
+exchangeability_(5,2) = 1.028509;
+exchangeability_(5,3) = 1.348551;
+exchangeability_(5,4) = 0;
+exchangeability_(5,5) = -25.60236;
+exchangeability_(5,6) = 7.086022;
+exchangeability_(5,7) = 0.281581;
+exchangeability_(5,8) = 6.011613;
+exchangeability_(5,9) = 0.180393;
+exchangeability_(5,10) = 0.730772;
+exchangeability_(5,11) = 1.519078;
+exchangeability_(5,12) = 1.127499;
+exchangeability_(5,13) = 0;
+exchangeability_(5,14) = 1.526188;
+exchangeability_(5,15) = 0.561828;
+exchangeability_(5,16) = 0.525651;
+exchangeability_(5,17) = 0;
+exchangeability_(5,18) = 0;
+exchangeability_(5,19) = 0.346983;
+exchangeability_(6,0) = 1.961167;
+exchangeability_(6,1) = 0;
+exchangeability_(6,2) = 1.493409;
+exchangeability_(6,3) = 11.38866;
+exchangeability_(6,4) = 0;
+exchangeability_(6,5) = 7.086022;
+exchangeability_(6,6) = -27.26104;
+exchangeability_(6,7) = 0.811907;
+exchangeability_(6,8) = 0.439469;
+exchangeability_(6,9) = 0.609526;
+exchangeability_(6,10) = 0.11288;
+exchangeability_(6,11) = 0.830078;
+exchangeability_(6,12) = 0.304803;
+exchangeability_(6,13) = 0;
+exchangeability_(6,14) = 0.507003;
+exchangeability_(6,15) = 0.793999;
+exchangeability_(6,16) = 0.340156;
+exchangeability_(6,17) = 0;
+exchangeability_(6,18) = 0.214717;
+exchangeability_(6,19) = 0.36725;
+exchangeability_(7,0) = 2.386111;
+exchangeability_(7,1) = 0.087791;
+exchangeability_(7,2) = 1.385352;
+exchangeability_(7,3) = 1.240981;
+exchangeability_(7,4) = 0.107278;
+exchangeability_(7,5) = 0.281581;
+exchangeability_(7,6) = 0.811907;
+exchangeability_(7,7) = -10.58507;
+exchangeability_(7,8) = 0.106802;
+exchangeability_(7,9) = 0;
+exchangeability_(7,10) = 0.071514;
+exchangeability_(7,11) = 0.267683;
+exchangeability_(7,12) = 0.170372;
+exchangeability_(7,13) = 0.153478;
+exchangeability_(7,14) = 0.347153;
+exchangeability_(7,15) = 2.322243;
+exchangeability_(7,16) = 0.306662;
+exchangeability_(7,17) = 0;
+exchangeability_(7,18) = 0;
+exchangeability_(7,19) = 0.538165;
+exchangeability_(8,0) = 0.228116;
+exchangeability_(8,1) = 2.383148;
+exchangeability_(8,2) = 5.290024;
+exchangeability_(8,3) = 0.868241;
+exchangeability_(8,4) = 0.282729;
+exchangeability_(8,5) = 6.011613;
+exchangeability_(8,6) = 0.439469;
+exchangeability_(8,7) = 0.106802;
+exchangeability_(8,8) = -20.36539;
+exchangeability_(8,9) = 0.076981;
+exchangeability_(8,10) = 0.443504;
+exchangeability_(8,11) = 0.270475;
+exchangeability_(8,12) = 0;
+exchangeability_(8,13) = 0.475927;
+exchangeability_(8,14) = 0.933709;
+exchangeability_(8,15) = 0.353643;
+exchangeability_(8,16) = 0.226333;
+exchangeability_(8,17) = 0.270564;
+exchangeability_(8,18) = 1.2654;
+exchangeability_(8,19) = 0.438715;
+exchangeability_(9,0) = 0.653416;
+exchangeability_(9,1) = 0.632629;
+exchangeability_(9,2) = 0.768024;
+exchangeability_(9,3) = 0.239248;
+exchangeability_(9,4) = 0.438074;
+exchangeability_(9,5) = 0.180393;
+exchangeability_(9,6) = 0.609526;
+exchangeability_(9,7) = 0;
+exchangeability_(9,8) = 0.076981;
+exchangeability_(9,9) = -23.35323;
+exchangeability_(9,10) = 2.556685;
+exchangeability_(9,11) = 0.460857;
+exchangeability_(9,12) = 3.332732;
+exchangeability_(9,13) = 1.951951;
+exchangeability_(9,14) = 0.119152;
+exchangeability_(9,15) = 0.247955;
+exchangeability_(9,16) = 1.900739;
+exchangeability_(9,17) = 0;
+exchangeability_(9,18) = 0.374834;
+exchangeability_(9,19) = 8.810038;
+exchangeability_(10,0) = 0.406431;
+exchangeability_(10,1) = 0.154924;
+exchangeability_(10,2) = 0.341113;
+exchangeability_(10,3) = 0;
+exchangeability_(10,4) = 0;
+exchangeability_(10,5) = 0.730772;
+exchangeability_(10,6) = 0.11288;
+exchangeability_(10,7) = 0.071514;
+exchangeability_(10,8) = 0.443504;
+exchangeability_(10,9) = 2.556685;
+exchangeability_(10,10) = -15.10601;
+exchangeability_(10,11) = 0.180629;
+exchangeability_(10,12) = 5.230115;
+exchangeability_(10,13) = 1.56516;
+exchangeability_(10,14) = 0.316258;
+exchangeability_(10,15) = 0.171432;
+exchangeability_(10,16) = 0.33109;
+exchangeability_(10,17) = 0.461776;
+exchangeability_(10,18) = 0.286572;
+exchangeability_(10,19) = 1.745156;
+exchangeability_(11,0) = 0.258635;
+exchangeability_(11,1) = 4.610124;
+exchangeability_(11,2) = 3.148371;
+exchangeability_(11,3) = 0.716913;
+exchangeability_(11,4) = 0;
+exchangeability_(11,5) = 1.519078;
+exchangeability_(11,6) = 0.830078;
+exchangeability_(11,7) = 0.267683;
+exchangeability_(11,8) = 0.270475;
+exchangeability_(11,9) = 0.460857;
+exchangeability_(11,10) = 0.180629;
+exchangeability_(11,11) = -17.55115;
+exchangeability_(11,12) = 2.411739;
+exchangeability_(11,13) = 0;
+exchangeability_(11,14) = 0.335419;
+exchangeability_(11,15) = 0.954557;
+exchangeability_(11,16) = 1.350599;
+exchangeability_(11,17) = 0;
+exchangeability_(11,18) = 0.132142;
+exchangeability_(11,19) = 0.10385;
+exchangeability_(12,0) = 0.71784;
+exchangeability_(12,1) = 0.896321;
+exchangeability_(12,2) = 0;
+exchangeability_(12,3) = 0;
+exchangeability_(12,4) = 0;
+exchangeability_(12,5) = 1.127499;
+exchangeability_(12,6) = 0.304803;
+exchangeability_(12,7) = 0.170372;
+exchangeability_(12,8) = 0;
+exchangeability_(12,9) = 3.332732;
+exchangeability_(12,10) = 5.230115;
+exchangeability_(12,11) = 2.411739;
+exchangeability_(12,12) = -19.50093;
+exchangeability_(12,13) = 0.92186;
+exchangeability_(12,14) = 0.170205;
+exchangeability_(12,15) = 0.619951;
+exchangeability_(12,16) = 1.031534;
+exchangeability_(12,17) = 0;
+exchangeability_(12,18) = 0;
+exchangeability_(12,19) = 2.565955;
+exchangeability_(13,0) = 0.183641;
+exchangeability_(13,1) = 0.136906;
+exchangeability_(13,2) = 0.138503;
+exchangeability_(13,3) = 0;
+exchangeability_(13,4) = 0;
+exchangeability_(13,5) = 0;
+exchangeability_(13,6) = 0;
+exchangeability_(13,7) = 0.153478;
+exchangeability_(13,8) = 0.475927;
+exchangeability_(13,9) = 1.951951;
+exchangeability_(13,10) = 1.56516;
+exchangeability_(13,11) = 0;
+exchangeability_(13,12) = 0.92186;
+exchangeability_(13,13) = -14.07308;
+exchangeability_(13,14) = 0.110506;
+exchangeability_(13,15) = 0.459901;
+exchangeability_(13,16) = 0.136655;
+exchangeability_(13,17) = 0.762354;
+exchangeability_(13,18) = 6.952629;
+exchangeability_(13,19) = 0.123606;
+exchangeability_(14,0) = 2.48592;
+exchangeability_(14,1) = 1.028313;
+exchangeability_(14,2) = 0.419244;
+exchangeability_(14,3) = 0.13394;
+exchangeability_(14,4) = 0.18755;
+exchangeability_(14,5) = 1.526188;
+exchangeability_(14,6) = 0.507003;
+exchangeability_(14,7) = 0.347153;
+exchangeability_(14,8) = 0.933709;
+exchangeability_(14,9) = 0.119152;
+exchangeability_(14,10) = 0.316258;
+exchangeability_(14,11) = 0.335419;
+exchangeability_(14,12) = 0.170205;
+exchangeability_(14,13) = 0.110506;
+exchangeability_(14,14) = -12.31564;
+exchangeability_(14,15) = 2.427202;
+exchangeability_(14,16) = 0.782857;
+exchangeability_(14,17) = 0;
+exchangeability_(14,18) = 0;
+exchangeability_(14,19) = 0.485026;
+exchangeability_(15,0) = 4.05187;
+exchangeability_(15,1) = 1.53159;
+exchangeability_(15,2) = 4.885892;
+exchangeability_(15,3) = 0.956097;
+exchangeability_(15,4) = 1.598356;
+exchangeability_(15,5) = 0.561828;
+exchangeability_(15,6) = 0.793999;
+exchangeability_(15,7) = 2.322243;
+exchangeability_(15,8) = 0.353643;
+exchangeability_(15,9) = 0.247955;
+exchangeability_(15,10) = 0.171432;
+exchangeability_(15,11) = 0.954557;
+exchangeability_(15,12) = 0.619951;
+exchangeability_(15,13) = 0.459901;
+exchangeability_(15,14) = 2.427202;
+exchangeability_(15,15) = -28.75413;
+exchangeability_(15,16) = 5.436674;
+exchangeability_(15,17) = 0.740819;
+exchangeability_(15,18) = 0.336289;
+exchangeability_(15,19) = 0.303836;
+exchangeability_(16,0) = 3.680365;
+exchangeability_(16,1) = 0.265745;
+exchangeability_(16,2) = 2.271697;
+exchangeability_(16,3) = 0.66093;
+exchangeability_(16,4) = 0.162366;
+exchangeability_(16,5) = 0.525651;
+exchangeability_(16,6) = 0.340156;
+exchangeability_(16,7) = 0.306662;
+exchangeability_(16,8) = 0.226333;
+exchangeability_(16,9) = 1.900739;
+exchangeability_(16,10) = 0.33109;
+exchangeability_(16,11) = 1.350599;
+exchangeability_(16,12) = 1.031534;
+exchangeability_(16,13) = 0.136655;
+exchangeability_(16,14) = 0.782857;
+exchangeability_(16,15) = 5.436674;
+exchangeability_(16,16) = -21.38989;
+exchangeability_(16,17) = 0;
+exchangeability_(16,18) = 0.417839;
+exchangeability_(16,19) = 1.561997;
+exchangeability_(17,0) = 0;
+exchangeability_(17,1) = 2.001375;
+exchangeability_(17,2) = 0.224968;
+exchangeability_(17,3) = 0;
+exchangeability_(17,4) = 0;
+exchangeability_(17,5) = 0;
+exchangeability_(17,6) = 0;
+exchangeability_(17,7) = 0;
+exchangeability_(17,8) = 0.270564;
+exchangeability_(17,9) = 0;
+exchangeability_(17,10) = 0.461776;
+exchangeability_(17,11) = 0;
+exchangeability_(17,12) = 0;
+exchangeability_(17,13) = 0.762354;
+exchangeability_(17,14) = 0;
+exchangeability_(17,15) = 0.740819;
+exchangeability_(17,16) = 0;
+exchangeability_(17,17) = -5.069926;
+exchangeability_(17,18) = 0.60807;
+exchangeability_(17,19) = 0;
+exchangeability_(18,0) = 0.244139;
+exchangeability_(18,1) = 0.078012;
+exchangeability_(18,2) = 0.94694;
+exchangeability_(18,3) = 0;
+exchangeability_(18,4) = 0.953164;
+exchangeability_(18,5) = 0;
+exchangeability_(18,6) = 0.214717;
+exchangeability_(18,7) = 0;
+exchangeability_(18,8) = 1.2654;
+exchangeability_(18,9) = 0.374834;
+exchangeability_(18,10) = 0.286572;
+exchangeability_(18,11) = 0.132142;
+exchangeability_(18,12) = 0;
+exchangeability_(18,13) = 6.952629;
+exchangeability_(18,14) = 0;
+exchangeability_(18,15) = 0.336289;
+exchangeability_(18,16) = 0.417839;
+exchangeability_(18,17) = 0.60807;
+exchangeability_(18,18) = -13.09013;
+exchangeability_(18,19) = 0.279379;
+exchangeability_(19,0) = 2.059564;
+exchangeability_(19,1) = 0.240368;
+exchangeability_(19,2) = 0.158067;
+exchangeability_(19,3) = 0.178316;
+exchangeability_(19,4) = 0.484678;
+exchangeability_(19,5) = 0.346983;
+exchangeability_(19,6) = 0.36725;
+exchangeability_(19,7) = 0.538165;
+exchangeability_(19,8) = 0.438715;
+exchangeability_(19,9) = 8.810038;
+exchangeability_(19,10) = 1.745156;
+exchangeability_(19,11) = 0.10385;
+exchangeability_(19,12) = 2.565955;
+exchangeability_(19,13) = 0.123606;
+exchangeability_(19,14) = 0.485026;
+exchangeability_(19,15) = 0.303836;
+exchangeability_(19,16) = 1.561997;
+exchangeability_(19,17) = 0;
+exchangeability_(19,18) = 0.279379;
+exchangeability_(19,19) = -20.79095;
diff --git a/src/Bpp/Phyl/Model/Protein/__DSO78FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__DSO78FrequenciesCode
new file mode 100755
index 0000000..d1a37f6
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__DSO78FrequenciesCode
@@ -0,0 +1,20 @@
+freq_[0] = 0.087127;
+freq_[1] = 0.040904;
+freq_[2] = 0.040432;
+freq_[3] = 0.046872;
+freq_[4] = 0.033474;
+freq_[5] = 0.038255;
+freq_[6] = 0.04953;
+freq_[7] = 0.088612;
+freq_[8] = 0.033619;
+freq_[9] = 0.036886;
+freq_[10] = 0.085357;
+freq_[11] = 0.080481;
+freq_[12] = 0.014753;
+freq_[13] = 0.039772;
+freq_[14] = 0.050679;
+freq_[15] = 0.069577;
+freq_[16] = 0.058542;
+freq_[17] = 0.010494;
+freq_[18] = 0.029916;
+freq_[19] = 0.064718;
diff --git a/src/Bpp/Phyl/Model/Protein/__JTT92ExchangeabilityCode b/src/Bpp/Phyl/Model/Protein/__JTT92ExchangeabilityCode
new file mode 100755
index 0000000..e266ce5
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__JTT92ExchangeabilityCode
@@ -0,0 +1,400 @@
+exchangeability_(0,0) = -21.30116;
+exchangeability_(0,1) = 0.531678;
+exchangeability_(0,2) = 0.557967;
+exchangeability_(0,3) = 0.827445;
+exchangeability_(0,4) = 0.574478;
+exchangeability_(0,5) = 0.556725;
+exchangeability_(0,6) = 1.066681;
+exchangeability_(0,7) = 1.740159;
+exchangeability_(0,8) = 0.21997;
+exchangeability_(0,9) = 0.361684;
+exchangeability_(0,10) = 0.310007;
+exchangeability_(0,11) = 0.369437;
+exchangeability_(0,12) = 0.469395;
+exchangeability_(0,13) = 0.138293;
+exchangeability_(0,14) = 1.959599;
+exchangeability_(0,15) = 3.887095;
+exchangeability_(0,16) = 4.582565;
+exchangeability_(0,17) = 0.084329;
+exchangeability_(0,18) = 0.139492;
+exchangeability_(0,19) = 2.924161;
+exchangeability_(1,0) = 0.531678;
+exchangeability_(1,1) = -21.73326;
+exchangeability_(1,2) = 0.451095;
+exchangeability_(1,3) = 0.154899;
+exchangeability_(1,4) = 1.019843;
+exchangeability_(1,5) = 3.021995;
+exchangeability_(1,6) = 0.318483;
+exchangeability_(1,7) = 1.359652;
+exchangeability_(1,8) = 3.210671;
+exchangeability_(1,9) = 0.239195;
+exchangeability_(1,10) = 0.372261;
+exchangeability_(1,11) = 6.529255;
+exchangeability_(1,12) = 0.431045;
+exchangeability_(1,13) = 0.065314;
+exchangeability_(1,14) = 0.710489;
+exchangeability_(1,15) = 1.001551;
+exchangeability_(1,16) = 0.650282;
+exchangeability_(1,17) = 1.257961;
+exchangeability_(1,18) = 0.235601;
+exchangeability_(1,19) = 0.171995;
+exchangeability_(2,0) = 0.557967;
+exchangeability_(2,1) = 0.451095;
+exchangeability_(2,2) = -25.00395;
+exchangeability_(2,3) = 5.54953;
+exchangeability_(2,4) = 0.313311;
+exchangeability_(2,5) = 0.768834;
+exchangeability_(2,6) = 0.578115;
+exchangeability_(2,7) = 0.773313;
+exchangeability_(2,8) = 4.025778;
+exchangeability_(2,9) = 0.491003;
+exchangeability_(2,10) = 0.137289;
+exchangeability_(2,11) = 2.529517;
+exchangeability_(2,12) = 0.33072;
+exchangeability_(2,13) = 0.073481;
+exchangeability_(2,14) = 0.121804;
+exchangeability_(2,15) = 5.057964;
+exchangeability_(2,16) = 2.351311;
+exchangeability_(2,17) = 0.0277;
+exchangeability_(2,18) = 0.700693;
+exchangeability_(2,19) = 0.164525;
+exchangeability_(3,0) = 0.827445;
+exchangeability_(3,1) = 0.154899;
+exchangeability_(3,2) = 5.54953;
+exchangeability_(3,3) = -19.88119;
+exchangeability_(3,4) = 0.105625;
+exchangeability_(3,5) = 0.521646;
+exchangeability_(3,6) = 7.766557;
+exchangeability_(3,7) = 1.272434;
+exchangeability_(3,8) = 1.032342;
+exchangeability_(3,9) = 0.115968;
+exchangeability_(3,10) = 0.061486;
+exchangeability_(3,11) = 0.282466;
+exchangeability_(3,12) = 0.190001;
+exchangeability_(3,13) = 0.032522;
+exchangeability_(3,14) = 0.127164;
+exchangeability_(3,15) = 0.589268;
+exchangeability_(3,16) = 0.425159;
+exchangeability_(3,17) = 0.057466;
+exchangeability_(3,18) = 0.453952;
+exchangeability_(3,19) = 0.315261;
+exchangeability_(4,0) = 0.574478;
+exchangeability_(4,1) = 1.019843;
+exchangeability_(4,2) = 0.313311;
+exchangeability_(4,3) = 0.105625;
+exchangeability_(4,4) = -11.47072;
+exchangeability_(4,5) = 0.091304;
+exchangeability_(4,6) = 0.053907;
+exchangeability_(4,7) = 0.546389;
+exchangeability_(4,8) = 0.724998;
+exchangeability_(4,9) = 0.150559;
+exchangeability_(4,10) = 0.164593;
+exchangeability_(4,11) = 0.049009;
+exchangeability_(4,12) = 0.409202;
+exchangeability_(4,13) = 0.678335;
+exchangeability_(4,14) = 0.123653;
+exchangeability_(4,15) = 2.155331;
+exchangeability_(4,16) = 0.469823;
+exchangeability_(4,17) = 1.104181;
+exchangeability_(4,18) = 2.114852;
+exchangeability_(4,19) = 0.621323;
+exchangeability_(5,0) = 0.556725;
+exchangeability_(5,1) = 3.021995;
+exchangeability_(5,2) = 0.768834;
+exchangeability_(5,3) = 0.521646;
+exchangeability_(5,4) = 0.091304;
+exchangeability_(5,5) = -21.83765;
+exchangeability_(5,6) = 3.417706;
+exchangeability_(5,7) = 0.231294;
+exchangeability_(5,8) = 5.68408;
+exchangeability_(5,9) = 0.07827;
+exchangeability_(5,10) = 0.709004;
+exchangeability_(5,11) = 2.966732;
+exchangeability_(5,12) = 0.456901;
+exchangeability_(5,13) = 0.045683;
+exchangeability_(5,14) = 1.608126;
+exchangeability_(5,15) = 0.548807;
+exchangeability_(5,16) = 0.523825;
+exchangeability_(5,17) = 0.172206;
+exchangeability_(5,18) = 0.254745;
+exchangeability_(5,19) = 0.179771;
+exchangeability_(6,0) = 1.066681;
+exchangeability_(6,1) = 0.318483;
+exchangeability_(6,2) = 0.578115;
+exchangeability_(6,3) = 7.766557;
+exchangeability_(6,4) = 0.053907;
+exchangeability_(6,5) = 3.417706;
+exchangeability_(6,6) = -18.19984;
+exchangeability_(6,7) = 1.115632;
+exchangeability_(6,8) = 0.243768;
+exchangeability_(6,9) = 0.111773;
+exchangeability_(6,10) = 0.097485;
+exchangeability_(6,11) = 1.731684;
+exchangeability_(6,12) = 0.175084;
+exchangeability_(6,13) = 0.043829;
+exchangeability_(6,14) = 0.191994;
+exchangeability_(6,15) = 0.312449;
+exchangeability_(6,16) = 0.331584;
+exchangeability_(6,17) = 0.114381;
+exchangeability_(6,18) = 0.063452;
+exchangeability_(6,19) = 0.465271;
+exchangeability_(7,0) = 1.740159;
+exchangeability_(7,1) = 1.359652;
+exchangeability_(7,2) = 0.773313;
+exchangeability_(7,3) = 1.272434;
+exchangeability_(7,4) = 0.546389;
+exchangeability_(7,5) = 0.231294;
+exchangeability_(7,6) = 1.115632;
+exchangeability_(7,7) = -11.28032;
+exchangeability_(7,8) = 0.201696;
+exchangeability_(7,9) = 0.053769;
+exchangeability_(7,10) = 0.069492;
+exchangeability_(7,11) = 0.26984;
+exchangeability_(7,12) = 0.130379;
+exchangeability_(7,13) = 0.050212;
+exchangeability_(7,14) = 0.208081;
+exchangeability_(7,15) = 1.874296;
+exchangeability_(7,16) = 0.316862;
+exchangeability_(7,17) = 0.54418;
+exchangeability_(7,18) = 0.0525;
+exchangeability_(7,19) = 0.47014;
+exchangeability_(8,0) = 0.21997;
+exchangeability_(8,1) = 3.210671;
+exchangeability_(8,2) = 4.025778;
+exchangeability_(8,3) = 1.032342;
+exchangeability_(8,4) = 0.724998;
+exchangeability_(8,5) = 5.68408;
+exchangeability_(8,6) = 0.243768;
+exchangeability_(8,7) = 0.201696;
+exchangeability_(8,8) = -25.83504;
+exchangeability_(8,9) = 0.181788;
+exchangeability_(8,10) = 0.540571;
+exchangeability_(8,11) = 0.525096;
+exchangeability_(8,12) = 0.32966;
+exchangeability_(8,13) = 0.453428;
+exchangeability_(8,14) = 1.141961;
+exchangeability_(8,15) = 0.743458;
+exchangeability_(8,16) = 0.477355;
+exchangeability_(8,17) = 0.128193;
+exchangeability_(8,18) = 5.8484;
+exchangeability_(8,19) = 0.121827;
+exchangeability_(9,0) = 0.361684;
+exchangeability_(9,1) = 0.239195;
+exchangeability_(9,2) = 0.491003;
+exchangeability_(9,3) = 0.115968;
+exchangeability_(9,4) = 0.150559;
+exchangeability_(9,5) = 0.07827;
+exchangeability_(9,6) = 0.111773;
+exchangeability_(9,7) = 0.053769;
+exchangeability_(9,8) = 0.181788;
+exchangeability_(9,9) = -22.95987;
+exchangeability_(9,10) = 2.335139;
+exchangeability_(9,11) = 0.202562;
+exchangeability_(9,12) = 4.831666;
+exchangeability_(9,13) = 0.77709;
+exchangeability_(9,14) = 0.09858;
+exchangeability_(9,15) = 0.405119;
+exchangeability_(9,16) = 2.553806;
+exchangeability_(9,17) = 0.13451;
+exchangeability_(9,18) = 0.303445;
+exchangeability_(9,19) = 9.533943;
+exchangeability_(10,0) = 0.310007;
+exchangeability_(10,1) = 0.372261;
+exchangeability_(10,2) = 0.137289;
+exchangeability_(10,3) = 0.061486;
+exchangeability_(10,4) = 0.164593;
+exchangeability_(10,5) = 0.709004;
+exchangeability_(10,6) = 0.097485;
+exchangeability_(10,7) = 0.069492;
+exchangeability_(10,8) = 0.540571;
+exchangeability_(10,9) = 2.335139;
+exchangeability_(10,10) = -15.75939;
+exchangeability_(10,11) = 0.146481;
+exchangeability_(10,12) = 3.856906;
+exchangeability_(10,13) = 2.500294;
+exchangeability_(10,14) = 1.060504;
+exchangeability_(10,15) = 0.592511;
+exchangeability_(10,16) = 0.272514;
+exchangeability_(10,17) = 0.530324;
+exchangeability_(10,18) = 0.241094;
+exchangeability_(10,19) = 1.761439;
+exchangeability_(11,0) = 0.369437;
+exchangeability_(11,1) = 6.529255;
+exchangeability_(11,2) = 2.529517;
+exchangeability_(11,3) = 0.282466;
+exchangeability_(11,4) = 0.049009;
+exchangeability_(11,5) = 2.966732;
+exchangeability_(11,6) = 1.731684;
+exchangeability_(11,7) = 0.26984;
+exchangeability_(11,8) = 0.525096;
+exchangeability_(11,9) = 0.202562;
+exchangeability_(11,10) = 0.146481;
+exchangeability_(11,11) = -18.20875;
+exchangeability_(11,12) = 0.624581;
+exchangeability_(11,13) = 0.024521;
+exchangeability_(11,14) = 0.216345;
+exchangeability_(11,15) = 0.474478;
+exchangeability_(11,16) = 0.965641;
+exchangeability_(11,17) = 0.089134;
+exchangeability_(11,18) = 0.087904;
+exchangeability_(11,19) = 0.124066;
+exchangeability_(12,0) = 0.469395;
+exchangeability_(12,1) = 0.431045;
+exchangeability_(12,2) = 0.33072;
+exchangeability_(12,3) = 0.190001;
+exchangeability_(12,4) = 0.409202;
+exchangeability_(12,5) = 0.456901;
+exchangeability_(12,6) = 0.175084;
+exchangeability_(12,7) = 0.130379;
+exchangeability_(12,8) = 0.32966;
+exchangeability_(12,9) = 4.831666;
+exchangeability_(12,10) = 3.856906;
+exchangeability_(12,11) = 0.624581;
+exchangeability_(12,12) = -18.66596;
+exchangeability_(12,13) = 0.436181;
+exchangeability_(12,14) = 0.164215;
+exchangeability_(12,15) = 0.285564;
+exchangeability_(12,16) = 2.114728;
+exchangeability_(12,17) = 0.201334;
+exchangeability_(12,18) = 0.18987;
+exchangeability_(12,19) = 3.038533;
+exchangeability_(13,0) = 0.138293;
+exchangeability_(13,1) = 0.065314;
+exchangeability_(13,2) = 0.073481;
+exchangeability_(13,3) = 0.032522;
+exchangeability_(13,4) = 0.678335;
+exchangeability_(13,5) = 0.045683;
+exchangeability_(13,6) = 0.043829;
+exchangeability_(13,7) = 0.050212;
+exchangeability_(13,8) = 0.453428;
+exchangeability_(13,9) = 0.77709;
+exchangeability_(13,10) = 2.500294;
+exchangeability_(13,11) = 0.024521;
+exchangeability_(13,12) = 0.436181;
+exchangeability_(13,13) = -13.16618;
+exchangeability_(13,14) = 0.148483;
+exchangeability_(13,15) = 0.943971;
+exchangeability_(13,16) = 0.138904;
+exchangeability_(13,17) = 0.537922;
+exchangeability_(13,18) = 5.484236;
+exchangeability_(13,19) = 0.593478;
+exchangeability_(14,0) = 1.959599;
+exchangeability_(14,1) = 0.710489;
+exchangeability_(14,2) = 0.121804;
+exchangeability_(14,3) = 0.127164;
+exchangeability_(14,4) = 0.123653;
+exchangeability_(14,5) = 1.608126;
+exchangeability_(14,6) = 0.191994;
+exchangeability_(14,7) = 0.208081;
+exchangeability_(14,8) = 1.141961;
+exchangeability_(14,9) = 0.09858;
+exchangeability_(14,10) = 1.060504;
+exchangeability_(14,11) = 0.216345;
+exchangeability_(14,12) = 0.164215;
+exchangeability_(14,13) = 0.148483;
+exchangeability_(14,14) = -12.24174;
+exchangeability_(14,15) = 2.788406;
+exchangeability_(14,16) = 1.176961;
+exchangeability_(14,17) = 0.069965;
+exchangeability_(14,18) = 0.11385;
+exchangeability_(14,19) = 0.211561;
+exchangeability_(15,0) = 3.887095;
+exchangeability_(15,1) = 1.001551;
+exchangeability_(15,2) = 5.057964;
+exchangeability_(15,3) = 0.589268;
+exchangeability_(15,4) = 2.155331;
+exchangeability_(15,5) = 0.548807;
+exchangeability_(15,6) = 0.312449;
+exchangeability_(15,7) = 1.874296;
+exchangeability_(15,8) = 0.743458;
+exchangeability_(15,9) = 0.405119;
+exchangeability_(15,10) = 0.592511;
+exchangeability_(15,11) = 0.474478;
+exchangeability_(15,12) = 0.285564;
+exchangeability_(15,13) = 0.943971;
+exchangeability_(15,14) = 2.788406;
+exchangeability_(15,15) = -27.78598;
+exchangeability_(15,16) = 4.777647;
+exchangeability_(15,17) = 0.310927;
+exchangeability_(15,18) = 0.628608;
+exchangeability_(15,19) = 0.408532;
+exchangeability_(16,0) = 4.582565;
+exchangeability_(16,1) = 0.650282;
+exchangeability_(16,2) = 2.351311;
+exchangeability_(16,3) = 0.425159;
+exchangeability_(16,4) = 0.469823;
+exchangeability_(16,5) = 0.523825;
+exchangeability_(16,6) = 0.331584;
+exchangeability_(16,7) = 0.316862;
+exchangeability_(16,8) = 0.477355;
+exchangeability_(16,9) = 2.553806;
+exchangeability_(16,10) = 0.272514;
+exchangeability_(16,11) = 0.965641;
+exchangeability_(16,12) = 2.114728;
+exchangeability_(16,13) = 0.138904;
+exchangeability_(16,14) = 1.176961;
+exchangeability_(16,15) = 4.777647;
+exchangeability_(16,16) = -23.55460;
+exchangeability_(16,17) = 0.080556;
+exchangeability_(16,18) = 0.201094;
+exchangeability_(16,19) = 1.14398;
+exchangeability_(17,0) = 0.084329;
+exchangeability_(17,1) = 1.257961;
+exchangeability_(17,2) = 0.0277;
+exchangeability_(17,3) = 0.057466;
+exchangeability_(17,4) = 1.104181;
+exchangeability_(17,5) = 0.172206;
+exchangeability_(17,6) = 0.114381;
+exchangeability_(17,7) = 0.54418;
+exchangeability_(17,8) = 0.128193;
+exchangeability_(17,9) = 0.13451;
+exchangeability_(17,10) = 0.530324;
+exchangeability_(17,11) = 0.089134;
+exchangeability_(17,12) = 0.201334;
+exchangeability_(17,13) = 0.537922;
+exchangeability_(17,14) = 0.069965;
+exchangeability_(17,15) = 0.310927;
+exchangeability_(17,16) = 0.080556;
+exchangeability_(17,17) = -6.432855;
+exchangeability_(17,18) = 0.747889;
+exchangeability_(17,19) = 0.239697;
+exchangeability_(18,0) = 0.139492;
+exchangeability_(18,1) = 0.235601;
+exchangeability_(18,2) = 0.700693;
+exchangeability_(18,3) = 0.453952;
+exchangeability_(18,4) = 2.114852;
+exchangeability_(18,5) = 0.254745;
+exchangeability_(18,6) = 0.063452;
+exchangeability_(18,7) = 0.0525;
+exchangeability_(18,8) = 5.8484;
+exchangeability_(18,9) = 0.303445;
+exchangeability_(18,10) = 0.241094;
+exchangeability_(18,11) = 0.087904;
+exchangeability_(18,12) = 0.18987;
+exchangeability_(18,13) = 5.484236;
+exchangeability_(18,14) = 0.11385;
+exchangeability_(18,15) = 0.628608;
+exchangeability_(18,16) = 0.201094;
+exchangeability_(18,17) = 0.747889;
+exchangeability_(18,18) = -18.02715;
+exchangeability_(18,19) = 0.165473;
+exchangeability_(19,0) = 2.924161;
+exchangeability_(19,1) = 0.171995;
+exchangeability_(19,2) = 0.164525;
+exchangeability_(19,3) = 0.315261;
+exchangeability_(19,4) = 0.621323;
+exchangeability_(19,5) = 0.179771;
+exchangeability_(19,6) = 0.465271;
+exchangeability_(19,7) = 0.47014;
+exchangeability_(19,8) = 0.121827;
+exchangeability_(19,9) = 9.533943;
+exchangeability_(19,10) = 1.761439;
+exchangeability_(19,11) = 0.124066;
+exchangeability_(19,12) = 3.038533;
+exchangeability_(19,13) = 0.593478;
+exchangeability_(19,14) = 0.211561;
+exchangeability_(19,15) = 0.408532;
+exchangeability_(19,16) = 1.14398;
+exchangeability_(19,17) = 0.239697;
+exchangeability_(19,18) = 0.165473;
+exchangeability_(19,19) = -22.65498;
diff --git a/src/Bpp/Phyl/Model/Protein/__JTT92FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__JTT92FrequenciesCode
new file mode 100755
index 0000000..a43f6ef
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__JTT92FrequenciesCode
@@ -0,0 +1,20 @@
+freq_[0] = 0.076862;
+freq_[1] = 0.051057;
+freq_[2] = 0.042546;
+freq_[3] = 0.051268;
+freq_[4] = 0.020279;
+freq_[5] = 0.041061;
+freq_[6] = 0.06182;
+freq_[7] = 0.074714;
+freq_[8] = 0.022983;
+freq_[9] = 0.052569;
+freq_[10] = 0.091111;
+freq_[11] = 0.059498;
+freq_[12] = 0.023414;
+freq_[13] = 0.04053;
+freq_[14] = 0.050532;
+freq_[15] = 0.068225;
+freq_[16] = 0.058518;
+freq_[17] = 0.014336;
+freq_[18] = 0.032303;
+freq_[19] = 0.066374;
diff --git a/src/Bpp/Phyl/Model/Protein/__LG08ExchangeabilityCode b/src/Bpp/Phyl/Model/Protein/__LG08ExchangeabilityCode
new file mode 100644
index 0000000..a5a8c41
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LG08ExchangeabilityCode
@@ -0,0 +1,400 @@
+exchangeability_(10,17)=0.61963;
+exchangeability_(17,10)=0.61963;
+exchangeability_(6,11)=1.80718;
+exchangeability_(11,6)=1.80718;
+exchangeability_(4,7)=0.56926;
+exchangeability_(7,4)=0.56926;
+exchangeability_(17,19)=0.18951;
+exchangeability_(19,17)=0.18951;
+exchangeability_(9,19)=10.6491;
+exchangeability_(19,9)=10.6491;
+exchangeability_(5,6)=4.12859;
+exchangeability_(6,5)=4.12859;
+exchangeability_(1,6)=0.36397;
+exchangeability_(6,1)=0.36397;
+exchangeability_(0,12)=1.12404;
+exchangeability_(12,0)=1.12404;
+exchangeability_(1,2)=0.75188;
+exchangeability_(2,1)=0.75188;
+exchangeability_(11,16)=1.13686;
+exchangeability_(16,11)=1.13686;
+exchangeability_(1,17)=0.59361;
+exchangeability_(17,1)=0.59361;
+exchangeability_(8,15)=0.99001;
+exchangeability_(15,8)=0.99001;
+exchangeability_(13,17)=2.45712;
+exchangeability_(17,13)=2.45712;
+exchangeability_(10,16)=0.30294;
+exchangeability_(16,10)=0.30294;
+exchangeability_(13,15)=0.36182;
+exchangeability_(15,13)=0.36182;
+exchangeability_(9,18)=0.23252;
+exchangeability_(18,9)=0.23252;
+exchangeability_(2,18)=0.61202;
+exchangeability_(18,2)=0.61202;
+exchangeability_(7,9)=0.00871;
+exchangeability_(9,7)=0.00871;
+exchangeability_(3,5)=0.52339;
+exchangeability_(5,3)=0.52339;
+exchangeability_(3,13)=0.01742;
+exchangeability_(13,3)=0.01742;
+exchangeability_(0,10)=0.39534;
+exchangeability_(10,0)=0.39534;
+exchangeability_(9,11)=0.15907;
+exchangeability_(11,9)=0.15907;
+exchangeability_(8,14)=0.50885;
+exchangeability_(14,8)=0.50885;
+exchangeability_(2,8)=4.50924;
+exchangeability_(8,2)=4.50924;
+exchangeability_(4,6)=0.0035;
+exchangeability_(6,4)=0.0035;
+exchangeability_(8,13)=0.68214;
+exchangeability_(13,8)=0.68214;
+exchangeability_(5,7)=0.26796;
+exchangeability_(7,5)=0.26796;
+exchangeability_(1,7)=0.39019;
+exchangeability_(7,1)=0.39019;
+exchangeability_(4,15)=2.78448;
+exchangeability_(15,4)=2.78448;
+exchangeability_(1,14)=0.33253;
+exchangeability_(14,1)=0.33253;
+exchangeability_(1,18)=0.31444;
+exchangeability_(18,1)=0.31444;
+exchangeability_(11,18)=0.13193;
+exchangeability_(18,11)=0.13193;
+exchangeability_(0,5)=0.96989;
+exchangeability_(5,0)=0.96989;
+exchangeability_(2,9)=0.1915;
+exchangeability_(9,2)=0.1915;
+exchangeability_(7,18)=0.05468;
+exchangeability_(18,7)=0.05468;
+exchangeability_(7,14)=0.19696;
+exchangeability_(14,7)=0.19696;
+exchangeability_(3,19)=0.03797;
+exchangeability_(19,3)=0.03797;
+exchangeability_(5,13)=0.03586;
+exchangeability_(13,5)=0.03586;
+exchangeability_(15,19)=0.09837;
+exchangeability_(19,15)=0.09837;
+exchangeability_(11,17)=0.04991;
+exchangeability_(17,11)=0.04991;
+exchangeability_(7,13)=0.08959;
+exchangeability_(13,7)=0.08959;
+exchangeability_(0,2)=0.27682;
+exchangeability_(2,0)=0.27682;
+exchangeability_(9,12)=4.27361;
+exchangeability_(12,9)=4.27361;
+exchangeability_(3,12)=0.02555;
+exchangeability_(12,3)=0.02555;
+exchangeability_(8,19)=0.11901;
+exchangeability_(19,8)=0.11901;
+exchangeability_(0,14)=1.17765;
+exchangeability_(14,0)=1.17765;
+exchangeability_(5,17)=0.2362;
+exchangeability_(17,5)=0.2362;
+exchangeability_(4,10)=0.59401;
+exchangeability_(10,4)=0.59401;
+exchangeability_(10,15)=0.18229;
+exchangeability_(15,10)=0.18229;
+exchangeability_(14,17)=0.09513;
+exchangeability_(17,14)=0.09513;
+exchangeability_(16,18)=0.24584;
+exchangeability_(18,16)=0.24584;
+exchangeability_(1,9)=0.12699;
+exchangeability_(9,1)=0.12699;
+exchangeability_(4,5)=0.08481;
+exchangeability_(5,4)=0.08481;
+exchangeability_(9,10)=4.14507;
+exchangeability_(10,9)=4.14507;
+exchangeability_(11,14)=0.39032;
+exchangeability_(14,11)=0.39032;
+exchangeability_(8,17)=0.59705;
+exchangeability_(17,8)=0.59705;
+exchangeability_(0,15)=4.72718;
+exchangeability_(15,0)=4.72718;
+exchangeability_(2,11)=2.14508;
+exchangeability_(11,2)=2.14508;
+exchangeability_(10,14)=0.24906;
+exchangeability_(14,10)=0.24906;
+exchangeability_(13,16)=0.165;
+exchangeability_(16,13)=0.165;
+exchangeability_(7,19)=0.0767;
+exchangeability_(19,7)=0.0767;
+exchangeability_(3,16)=0.42586;
+exchangeability_(16,3)=0.42586;
+exchangeability_(7,12)=0.13954;
+exchangeability_(12,7)=0.13954;
+exchangeability_(15,16)=6.47228;
+exchangeability_(16,15)=6.47228;
+exchangeability_(14,15)=1.33813;
+exchangeability_(15,14)=1.33813;
+exchangeability_(3,11)=0.28296;
+exchangeability_(11,3)=0.28296;
+exchangeability_(6,7)=0.34885;
+exchangeability_(7,6)=0.34885;
+exchangeability_(8,16)=0.58426;
+exchangeability_(16,8)=0.58426;
+exchangeability_(0,1)=0.42509;
+exchangeability_(1,0)=0.42509;
+exchangeability_(5,9)=0.07285;
+exchangeability_(9,5)=0.07285;
+exchangeability_(12,18)=0.48131;
+exchangeability_(18,12)=0.48131;
+exchangeability_(6,16)=0.60454;
+exchangeability_(16,6)=0.60454;
+exchangeability_(1,11)=6.32607;
+exchangeability_(11,1)=6.32607;
+exchangeability_(2,14)=0.16179;
+exchangeability_(14,2)=0.16179;
+exchangeability_(0,4)=2.48908;
+exchangeability_(4,0)=2.48908;
+exchangeability_(1,16)=0.57899;
+exchangeability_(16,1)=0.57899;
+exchangeability_(6,13)=0.01881;
+exchangeability_(13,6)=0.01881;
+exchangeability_(18,19)=0.24931;
+exchangeability_(19,18)=0.24931;
+exchangeability_(5,8)=4.8135;
+exchangeability_(8,5)=4.8135;
+exchangeability_(16,19)=2.18816;
+exchangeability_(19,16)=2.18816;
+exchangeability_(7,16)=0.12984;
+exchangeability_(16,7)=0.12984;
+exchangeability_(8,11)=0.69726;
+exchangeability_(11,8)=0.69726;
+exchangeability_(3,17)=0.02989;
+exchangeability_(17,3)=0.02989;
+exchangeability_(6,17)=0.07785;
+exchangeability_(17,6)=0.07785;
+exchangeability_(2,3)=5.07615;
+exchangeability_(3,2)=5.07615;
+exchangeability_(3,9)=0.01069;
+exchangeability_(9,3)=0.01069;
+exchangeability_(0,16)=2.1395;
+exchangeability_(16,0)=2.1395;
+exchangeability_(5,11)=3.23429;
+exchangeability_(11,5)=3.23429;
+exchangeability_(4,8)=0.64054;
+exchangeability_(8,4)=0.64054;
+exchangeability_(16,17)=0.14082;
+exchangeability_(17,16)=0.14082;
+exchangeability_(5,19)=0.21033;
+exchangeability_(19,5)=0.21033;
+exchangeability_(1,3)=0.12395;
+exchangeability_(3,1)=0.12395;
+exchangeability_(4,19)=1.95929;
+exchangeability_(19,4)=1.95929;
+exchangeability_(6,19)=0.24503;
+exchangeability_(19,6)=0.24503;
+exchangeability_(1,12)=0.48413;
+exchangeability_(12,1)=0.48413;
+exchangeability_(0,6)=1.03854;
+exchangeability_(6,0)=1.03854;
+exchangeability_(2,6)=0.54171;
+exchangeability_(6,2)=0.54171;
+exchangeability_(1,19)=0.17089;
+exchangeability_(19,1)=0.17089;
+exchangeability_(0,17)=0.18072;
+exchangeability_(17,0)=0.18072;
+exchangeability_(2,17)=0.04538;
+exchangeability_(17,2)=0.04538;
+exchangeability_(7,15)=1.73999;
+exchangeability_(15,7)=1.73999;
+exchangeability_(3,14)=0.39446;
+exchangeability_(14,3)=0.39446;
+exchangeability_(8,9)=0.10888;
+exchangeability_(9,8)=0.10888;
+exchangeability_(3,18)=0.13511;
+exchangeability_(18,3)=0.13511;
+exchangeability_(0,3)=0.39514;
+exchangeability_(3,0)=0.39514;
+exchangeability_(2,13)=0.08953;
+exchangeability_(13,2)=0.08953;
+exchangeability_(0,19)=2.54787;
+exchangeability_(19,0)=2.54787;
+exchangeability_(5,12)=1.67257;
+exchangeability_(12,5)=1.67257;
+exchangeability_(4,13)=1.10525;
+exchangeability_(13,4)=1.10525;
+exchangeability_(10,12)=6.31236;
+exchangeability_(12,10)=6.31236;
+exchangeability_(5,18)=0.25734;
+exchangeability_(18,5)=0.25734;
+exchangeability_(14,16)=0.57147;
+exchangeability_(16,14)=0.57147;
+exchangeability_(1,13)=0.05272;
+exchangeability_(13,1)=0.05272;
+exchangeability_(4,16)=1.14348;
+exchangeability_(16,4)=1.14348;
+exchangeability_(6,14)=0.41941;
+exchangeability_(14,6)=0.41941;
+exchangeability_(11,15)=0.74868;
+exchangeability_(15,11)=0.74868;
+exchangeability_(0,7)=2.06604;
+exchangeability_(7,0)=2.06604;
+exchangeability_(2,7)=1.43765;
+exchangeability_(7,2)=1.43765;
+exchangeability_(8,18)=5.30683;
+exchangeability_(18,8)=5.30683;
+exchangeability_(5,10)=0.58246;
+exchangeability_(10,5)=0.58246;
+exchangeability_(15,18)=0.40055;
+exchangeability_(18,15)=0.40055;
+exchangeability_(12,16)=2.02037;
+exchangeability_(16,12)=2.02037;
+exchangeability_(5,14)=0.62429;
+exchangeability_(14,5)=0.62429;
+exchangeability_(7,8)=0.31148;
+exchangeability_(8,7)=0.31148;
+exchangeability_(15,17)=0.24886;
+exchangeability_(17,15)=0.24886;
+exchangeability_(3,7)=0.84493;
+exchangeability_(7,3)=0.84493;
+exchangeability_(6,15)=0.61197;
+exchangeability_(15,6)=0.61197;
+exchangeability_(12,13)=1.79885;
+exchangeability_(13,12)=1.79885;
+exchangeability_(13,14)=0.09446;
+exchangeability_(14,13)=0.09446;
+exchangeability_(3,10)=0.01508;
+exchangeability_(10,3)=0.01508;
+exchangeability_(0,13)=0.2537;
+exchangeability_(13,0)=0.2537;
+exchangeability_(6,12)=0.17374;
+exchangeability_(12,6)=0.17374;
+exchangeability_(4,12)=0.89368;
+exchangeability_(12,4)=0.89368;
+exchangeability_(9,14)=0.07828;
+exchangeability_(14,9)=0.07828;
+exchangeability_(10,11)=0.1375;
+exchangeability_(11,10)=0.1375;
+exchangeability_(12,17)=0.69618;
+exchangeability_(17,12)=0.69618;
+exchangeability_(2,19)=0.08369;
+exchangeability_(19,2)=0.08369;
+exchangeability_(8,10)=0.36632;
+exchangeability_(10,8)=0.36632;
+exchangeability_(1,8)=2.4266;
+exchangeability_(8,1)=2.4266;
+exchangeability_(1,5)=2.80791;
+exchangeability_(5,1)=2.80791;
+exchangeability_(2,5)=1.69575;
+exchangeability_(5,2)=1.69575;
+exchangeability_(0,18)=0.21896;
+exchangeability_(18,0)=0.21896;
+exchangeability_(13,18)=7.8039;
+exchangeability_(18,13)=7.8039;
+exchangeability_(6,10)=0.06967;
+exchangeability_(10,6)=0.06967;
+exchangeability_(9,15)=0.06411;
+exchangeability_(15,9)=0.06411;
+exchangeability_(2,15)=4.00836;
+exchangeability_(15,2)=4.00836;
+exchangeability_(7,17)=0.26849;
+exchangeability_(17,7)=0.26849;
+exchangeability_(2,16)=2.00068;
+exchangeability_(16,2)=2.00068;
+exchangeability_(12,19)=1.89872;
+exchangeability_(19,12)=1.89872;
+exchangeability_(8,12)=0.44247;
+exchangeability_(12,8)=0.44247;
+exchangeability_(3,6)=5.24387;
+exchangeability_(6,3)=5.24387;
+exchangeability_(4,11)=0.01327;
+exchangeability_(11,4)=0.01327;
+exchangeability_(4,18)=1.16553;
+exchangeability_(18,4)=1.16553;
+exchangeability_(0,9)=0.14983;
+exchangeability_(9,0)=0.14983;
+exchangeability_(4,14)=0.07538;
+exchangeability_(14,4)=0.07538;
+exchangeability_(1,15)=0.85815;
+exchangeability_(15,1)=0.85815;
+exchangeability_(2,4)=0.52877;
+exchangeability_(4,2)=0.52877;
+exchangeability_(11,13)=0.02392;
+exchangeability_(13,11)=0.02392;
+exchangeability_(11,12)=0.6566;
+exchangeability_(12,11)=0.6566;
+exchangeability_(10,13)=2.59269;
+exchangeability_(13,10)=2.59269;
+exchangeability_(12,14)=0.09985;
+exchangeability_(14,12)=0.09985;
+exchangeability_(7,10)=0.04426;
+exchangeability_(10,7)=0.04426;
+exchangeability_(0,8)=0.35886;
+exchangeability_(8,0)=0.35886;
+exchangeability_(3,4)=0.06256;
+exchangeability_(4,3)=0.06256;
+exchangeability_(3,8)=0.92711;
+exchangeability_(8,3)=0.92711;
+exchangeability_(2,10)=0.06843;
+exchangeability_(10,2)=0.06843;
+exchangeability_(17,18)=3.15181;
+exchangeability_(18,17)=3.15181;
+exchangeability_(10,18)=0.29965;
+exchangeability_(18,10)=0.29965;
+exchangeability_(6,9)=0.04427;
+exchangeability_(9,6)=0.04427;
+exchangeability_(4,9)=0.32063;
+exchangeability_(9,4)=0.32063;
+exchangeability_(14,19)=0.2965;
+exchangeability_(19,14)=0.2965;
+exchangeability_(9,16)=1.03374;
+exchangeability_(16,9)=1.03374;
+exchangeability_(12,15)=0.34696;
+exchangeability_(15,12)=0.34696;
+exchangeability_(1,4)=0.53455;
+exchangeability_(4,1)=0.53455;
+exchangeability_(4,17)=0.67013;
+exchangeability_(17,4)=0.67013;
+exchangeability_(0,11)=0.53652;
+exchangeability_(11,0)=0.53652;
+exchangeability_(9,13)=1.11273;
+exchangeability_(13,9)=1.11273;
+exchangeability_(1,10)=0.30185;
+exchangeability_(10,1)=0.30185;
+exchangeability_(11,19)=0.1852;
+exchangeability_(19,11)=0.1852;
+exchangeability_(2,12)=0.371;
+exchangeability_(12,2)=0.371;
+exchangeability_(10,19)=1.70275;
+exchangeability_(19,10)=1.70275;
+exchangeability_(6,8)=0.42388;
+exchangeability_(8,6)=0.42388;
+exchangeability_(9,17)=0.11166;
+exchangeability_(17,9)=0.11166;
+exchangeability_(7,11)=0.29664;
+exchangeability_(11,7)=0.29664;
+exchangeability_(3,15)=1.24027;
+exchangeability_(15,3)=1.24027;
+exchangeability_(13,19)=0.65468;
+exchangeability_(19,13)=0.65468;
+exchangeability_(14,18)=0.08961;
+exchangeability_(18,14)=0.08961;
+exchangeability_(6,18)=0.12004;
+exchangeability_(18,6)=0.12004;
+exchangeability_(5,16)=1.08014;
+exchangeability_(16,5)=1.08014;
+exchangeability_(5,15)=1.22383;
+exchangeability_(15,5)=1.22383;
+exchangeability_(0,0)=-21.4708;
+exchangeability_(4,4)=-15.6382;
+exchangeability_(6,6)=-16.2854;
+exchangeability_(3,3)=-15.8124;
+exchangeability_(7,7)=-9.28176;
+exchangeability_(13,13)=-19.4102;
+exchangeability_(9,9)=-22.8942;
+exchangeability_(8,8)=-24.8143;
+exchangeability_(11,11)=-18.9593;
+exchangeability_(12,12)=-23.9115;
+exchangeability_(10,10)=-18.9814;
+exchangeability_(2,2)=-24.5954;
+exchangeability_(5,5)=-24.522;
+exchangeability_(14,14)=-7.19413;
+exchangeability_(15,15)=-28.4463;
+exchangeability_(1,1)=-17.9645;
+exchangeability_(16,16)=-22.9648;
+exchangeability_(17,17)=-10.4599;
+exchangeability_(19,19)=-23.5631;
+exchangeability_(18,18)=-21.2714;
diff --git a/src/Bpp/Phyl/Model/Protein/__LG08FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__LG08FrequenciesCode
new file mode 100644
index 0000000..ccc10a6
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LG08FrequenciesCode
@@ -0,0 +1,21 @@
+freq_[0] = 0.079066;
+freq_[4] = 0.012937;
+freq_[6] = 0.071586;
+freq_[3] = 0.053052;
+freq_[7] = 0.057337;
+freq_[13] = 0.042302;
+freq_[9] = 0.062157;
+freq_[8] = 0.022355;
+freq_[11] = 0.0646;
+freq_[12] = 0.022951;
+freq_[10] = 0.099081;
+freq_[2] = 0.041977;
+freq_[5] = 0.040767;
+freq_[14] = 0.04404;
+freq_[15] = 0.061197;
+freq_[1] = 0.055941;
+freq_[16] = 0.053286;
+freq_[17] = 0.012066;
+freq_[19] = 0.069147;
+freq_[18] = 0.034155;
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_EHOExchangeabilityCode b/src/Bpp/Phyl/Model/Protein/__LLG08_EHOExchangeabilityCode
new file mode 100644
index 0000000..c606c30
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_EHOExchangeabilityCode
@@ -0,0 +1,1224 @@
+if (getName()=="Other"){
+      	exchangeability_(10,17)=0.97928;
+	exchangeability_(17,10)=0.97928;
+	exchangeability_(6,11)=1.13107;
+	exchangeability_(11,6)=1.13107;
+	exchangeability_(4,7)=0.5549;
+	exchangeability_(7,4)=0.5549;
+	exchangeability_(17,19)=0.1865;
+	exchangeability_(19,17)=0.1865;
+	exchangeability_(9,19)=22.4356;
+	exchangeability_(19,9)=22.4356;
+	exchangeability_(5,6)=3.74387;
+	exchangeability_(6,5)=3.74387;
+	exchangeability_(1,6)=0.15446;
+	exchangeability_(6,1)=0.15446;
+	exchangeability_(0,12)=1.05675;
+	exchangeability_(12,0)=1.05675;
+	exchangeability_(1,2)=0.61233;
+	exchangeability_(2,1)=0.61233;
+	exchangeability_(11,16)=1.14323;
+	exchangeability_(16,11)=1.14323;
+	exchangeability_(1,17)=0.54429;
+	exchangeability_(17,1)=0.54429;
+	exchangeability_(8,15)=0.89748;
+	exchangeability_(15,8)=0.89748;
+	exchangeability_(13,17)=4.85076;
+	exchangeability_(17,13)=4.85076;
+	exchangeability_(10,16)=0.40842;
+	exchangeability_(16,10)=0.40842;
+	exchangeability_(13,15)=0.40876;
+	exchangeability_(15,13)=0.40876;
+	exchangeability_(9,18)=0.29924;
+	exchangeability_(18,9)=0.29924;
+	exchangeability_(2,18)=0.5801;
+	exchangeability_(18,2)=0.5801;
+	exchangeability_(7,9)=0.0056;
+	exchangeability_(9,7)=0.0056;
+	exchangeability_(3,5)=0.44226;
+	exchangeability_(5,3)=0.44226;
+	exchangeability_(3,13)=0.01677;
+	exchangeability_(13,3)=0.01677;
+	exchangeability_(0,10)=0.34036;
+	exchangeability_(10,0)=0.34036;
+	exchangeability_(9,11)=0.17983;
+	exchangeability_(11,9)=0.17983;
+	exchangeability_(8,14)=0.29992;
+	exchangeability_(14,8)=0.29992;
+	exchangeability_(2,8)=4.803;
+	exchangeability_(8,2)=4.803;
+	exchangeability_(4,6)=0.01557;
+	exchangeability_(6,4)=0.01557;
+	exchangeability_(8,13)=1.40318;
+	exchangeability_(13,8)=1.40318;
+	exchangeability_(5,7)=0.33266;
+	exchangeability_(7,5)=0.33266;
+	exchangeability_(1,7)=0.38932;
+	exchangeability_(7,1)=0.38932;
+	exchangeability_(4,15)=4.95278;
+	exchangeability_(15,4)=4.95278;
+	exchangeability_(1,14)=0.25248;
+	exchangeability_(14,1)=0.25248;
+	exchangeability_(1,18)=0.24351;
+	exchangeability_(18,1)=0.24351;
+	exchangeability_(11,18)=0.06789;
+	exchangeability_(18,11)=0.06789;
+	exchangeability_(0,5)=1.31226;
+	exchangeability_(5,0)=1.31226;
+	exchangeability_(2,9)=0.21964;
+	exchangeability_(9,2)=0.21964;
+	exchangeability_(7,18)=0.03748;
+	exchangeability_(18,7)=0.03748;
+	exchangeability_(7,14)=0.05891;
+	exchangeability_(14,7)=0.05891;
+	exchangeability_(3,19)=0.05538;
+	exchangeability_(19,3)=0.05538;
+	exchangeability_(5,13)=0.07761;
+	exchangeability_(13,5)=0.07761;
+	exchangeability_(15,19)=0.1529;
+	exchangeability_(19,15)=0.1529;
+	exchangeability_(11,17)=0.03879;
+	exchangeability_(17,11)=0.03879;
+	exchangeability_(7,13)=0.04891;
+	exchangeability_(13,7)=0.04891;
+	exchangeability_(0,2)=0.37948;
+	exchangeability_(2,0)=0.37948;
+	exchangeability_(9,12)=8.13606;
+	exchangeability_(12,9)=8.13606;
+	exchangeability_(3,12)=0.0539;
+	exchangeability_(12,3)=0.0539;
+	exchangeability_(8,19)=0.21439;
+	exchangeability_(19,8)=0.21439;
+	exchangeability_(0,14)=1.51883;
+	exchangeability_(14,0)=1.51883;
+	exchangeability_(5,17)=0.22804;
+	exchangeability_(17,5)=0.22804;
+	exchangeability_(4,10)=1.19286;
+	exchangeability_(10,4)=1.19286;
+	exchangeability_(10,15)=0.2657;
+	exchangeability_(15,10)=0.2657;
+	exchangeability_(14,17)=0.05242;
+	exchangeability_(17,14)=0.05242;
+	exchangeability_(16,18)=0.18304;
+	exchangeability_(18,16)=0.18304;
+	exchangeability_(1,9)=0.15508;
+	exchangeability_(9,1)=0.15508;
+	exchangeability_(4,5)=0.33757;
+	exchangeability_(5,4)=0.33757;
+	exchangeability_(9,10)=7.87354;
+	exchangeability_(10,9)=7.87354;
+	exchangeability_(11,14)=0.24948;
+	exchangeability_(14,11)=0.24948;
+	exchangeability_(8,17)=0.74815;
+	exchangeability_(17,8)=0.74815;
+	exchangeability_(0,15)=5.59574;
+	exchangeability_(15,0)=5.59574;
+	exchangeability_(2,11)=1.84781;
+	exchangeability_(11,2)=1.84781;
+	exchangeability_(10,14)=0.29757;
+	exchangeability_(14,10)=0.29757;
+	exchangeability_(13,16)=0.13178;
+	exchangeability_(16,13)=0.13178;
+	exchangeability_(7,19)=0.06717;
+	exchangeability_(19,7)=0.06717;
+	exchangeability_(3,16)=0.36186;
+	exchangeability_(16,3)=0.36186;
+	exchangeability_(7,12)=0.08509;
+	exchangeability_(12,7)=0.08509;
+	exchangeability_(15,16)=7.57434;
+	exchangeability_(16,15)=7.57434;
+	exchangeability_(14,15)=0.99361;
+	exchangeability_(15,14)=0.99361;
+	exchangeability_(3,11)=0.12811;
+	exchangeability_(11,3)=0.12811;
+	exchangeability_(6,7)=0.31977;
+	exchangeability_(7,6)=0.31977;
+	exchangeability_(8,16)=0.45066;
+	exchangeability_(16,8)=0.45066;
+	exchangeability_(0,1)=0.52926;
+	exchangeability_(1,0)=0.52926;
+	exchangeability_(5,9)=0.10074;
+	exchangeability_(9,5)=0.10074;
+	exchangeability_(12,18)=0.68525;
+	exchangeability_(18,12)=0.68525;
+	exchangeability_(6,16)=0.52309;
+	exchangeability_(16,6)=0.52309;
+	exchangeability_(1,11)=5.73463;
+	exchangeability_(11,1)=5.73463;
+	exchangeability_(2,14)=0.04948;
+	exchangeability_(14,2)=0.04948;
+	exchangeability_(0,4)=3.77489;
+	exchangeability_(4,0)=3.77489;
+	exchangeability_(1,16)=0.61362;
+	exchangeability_(16,1)=0.61362;
+	exchangeability_(6,13)=0.01265;
+	exchangeability_(13,6)=0.01265;
+	exchangeability_(18,19)=0.30383;
+	exchangeability_(19,18)=0.30383;
+	exchangeability_(5,8)=4.88903;
+	exchangeability_(8,5)=4.88903;
+	exchangeability_(16,19)=2.4234;
+	exchangeability_(19,16)=2.4234;
+	exchangeability_(7,16)=0.09102;
+	exchangeability_(16,7)=0.09102;
+	exchangeability_(8,11)=0.64356;
+	exchangeability_(11,8)=0.64356;
+	exchangeability_(3,17)=0.04343;
+	exchangeability_(17,3)=0.04343;
+	exchangeability_(6,17)=0.04508;
+	exchangeability_(17,6)=0.04508;
+	exchangeability_(2,3)=4.01291;
+	exchangeability_(3,2)=4.01291;
+	exchangeability_(3,9)=0.0191;
+	exchangeability_(9,3)=0.0191;
+	exchangeability_(0,16)=2.15746;
+	exchangeability_(16,0)=2.15746;
+	exchangeability_(5,11)=3.61663;
+	exchangeability_(11,5)=3.61663;
+	exchangeability_(4,8)=1.22366;
+	exchangeability_(8,4)=1.22366;
+	exchangeability_(16,17)=0.11423;
+	exchangeability_(17,16)=0.11423;
+	exchangeability_(5,19)=0.50095;
+	exchangeability_(19,5)=0.50095;
+	exchangeability_(1,3)=0.06773;
+	exchangeability_(3,1)=0.06773;
+	exchangeability_(4,19)=4.14939;
+	exchangeability_(19,4)=4.14939;
+	exchangeability_(6,19)=0.43596;
+	exchangeability_(19,6)=0.43596;
+	exchangeability_(1,12)=0.66536;
+	exchangeability_(12,1)=0.66536;
+	exchangeability_(0,6)=1.40344;
+	exchangeability_(6,0)=1.40344;
+	exchangeability_(2,6)=0.33333;
+	exchangeability_(6,2)=0.33333;
+	exchangeability_(1,19)=0.27874;
+	exchangeability_(19,1)=0.27874;
+	exchangeability_(0,17)=0.15189;
+	exchangeability_(17,0)=0.15189;
+	exchangeability_(2,17)=0.06018;
+	exchangeability_(17,2)=0.06018;
+	exchangeability_(7,15)=1.19074;
+	exchangeability_(15,7)=1.19074;
+	exchangeability_(3,14)=0.17101;
+	exchangeability_(14,3)=0.17101;
+	exchangeability_(8,9)=0.18475;
+	exchangeability_(9,8)=0.18475;
+	exchangeability_(3,18)=0.13021;
+	exchangeability_(18,3)=0.13021;
+	exchangeability_(0,3)=0.51669;
+	exchangeability_(3,0)=0.51669;
+	exchangeability_(2,13)=0.1303;
+	exchangeability_(13,2)=0.1303;
+	exchangeability_(0,19)=3.04998;
+	exchangeability_(19,0)=3.04998;
+	exchangeability_(5,12)=2.29971;
+	exchangeability_(12,5)=2.29971;
+	exchangeability_(4,13)=1.90224;
+	exchangeability_(13,4)=1.90224;
+	exchangeability_(10,12)=14.2132;
+	exchangeability_(12,10)=14.2132;
+	exchangeability_(5,18)=0.19658;
+	exchangeability_(18,5)=0.19658;
+	exchangeability_(14,16)=0.38101;
+	exchangeability_(16,14)=0.38101;
+	exchangeability_(1,13)=0.07947;
+	exchangeability_(13,1)=0.07947;
+	exchangeability_(4,16)=2.14578;
+	exchangeability_(16,4)=2.14578;
+	exchangeability_(6,14)=0.3466;
+	exchangeability_(14,6)=0.3466;
+	exchangeability_(11,15)=0.6071;
+	exchangeability_(15,11)=0.6071;
+	exchangeability_(0,7)=1.2724;
+	exchangeability_(7,0)=1.2724;
+	exchangeability_(2,7)=1.24322;
+	exchangeability_(7,2)=1.24322;
+	exchangeability_(8,18)=6.90761;
+	exchangeability_(18,8)=6.90761;
+	exchangeability_(5,10)=1.15652;
+	exchangeability_(10,5)=1.15652;
+	exchangeability_(15,18)=0.32321;
+	exchangeability_(18,15)=0.32321;
+	exchangeability_(12,16)=2.37857;
+	exchangeability_(16,12)=2.37857;
+	exchangeability_(5,14)=0.5012;
+	exchangeability_(14,5)=0.5012;
+	exchangeability_(7,8)=0.30098;
+	exchangeability_(8,7)=0.30098;
+	exchangeability_(15,17)=0.24975;
+	exchangeability_(17,15)=0.24975;
+	exchangeability_(3,7)=0.66198;
+	exchangeability_(7,3)=0.66198;
+	exchangeability_(6,15)=0.46326;
+	exchangeability_(15,6)=0.46326;
+	exchangeability_(12,13)=2.88863;
+	exchangeability_(13,12)=2.88863;
+	exchangeability_(13,14)=0.06892;
+	exchangeability_(14,13)=0.06892;
+	exchangeability_(3,10)=0.01595;
+	exchangeability_(10,3)=0.01595;
+	exchangeability_(0,13)=0.23396;
+	exchangeability_(13,0)=0.23396;
+	exchangeability_(6,12)=0.16808;
+	exchangeability_(12,6)=0.16808;
+	exchangeability_(4,12)=1.89395;
+	exchangeability_(12,4)=1.89395;
+	exchangeability_(9,14)=0.07301;
+	exchangeability_(14,9)=0.07301;
+	exchangeability_(10,11)=0.22432;
+	exchangeability_(11,10)=0.22432;
+	exchangeability_(12,17)=0.90825;
+	exchangeability_(17,12)=0.90825;
+	exchangeability_(2,19)=0.13412;
+	exchangeability_(19,2)=0.13412;
+	exchangeability_(8,10)=0.64629;
+	exchangeability_(10,8)=0.64629;
+	exchangeability_(1,8)=2.81664;
+	exchangeability_(8,1)=2.81664;
+	exchangeability_(1,5)=2.91367;
+	exchangeability_(5,1)=2.91367;
+	exchangeability_(2,5)=1.53368;
+	exchangeability_(5,2)=1.53368;
+	exchangeability_(0,18)=0.21951;
+	exchangeability_(18,0)=0.21951;
+	exchangeability_(13,18)=19.405;
+	exchangeability_(18,13)=19.405;
+	exchangeability_(6,10)=0.08315;
+	exchangeability_(10,6)=0.08315;
+	exchangeability_(9,15)=0.13175;
+	exchangeability_(15,9)=0.13175;
+	exchangeability_(2,15)=3.74963;
+	exchangeability_(15,2)=3.74963;
+	exchangeability_(7,17)=0.1348;
+	exchangeability_(17,7)=0.1348;
+	exchangeability_(2,16)=1.73338;
+	exchangeability_(16,2)=1.73338;
+	exchangeability_(12,19)=3.36945;
+	exchangeability_(19,12)=3.36945;
+	exchangeability_(8,12)=0.55602;
+	exchangeability_(12,8)=0.55602;
+	exchangeability_(3,6)=3.81589;
+	exchangeability_(6,3)=3.81589;
+	exchangeability_(4,11)=0.0509;
+	exchangeability_(11,4)=0.0509;
+	exchangeability_(4,18)=2.32502;
+	exchangeability_(18,4)=2.32502;
+	exchangeability_(0,9)=0.12406;
+	exchangeability_(9,0)=0.12406;
+	exchangeability_(4,14)=0.10891;
+	exchangeability_(14,4)=0.10891;
+	exchangeability_(1,15)=0.86102;
+	exchangeability_(15,1)=0.86102;
+	exchangeability_(2,4)=0.88866;
+	exchangeability_(4,2)=0.88866;
+	exchangeability_(11,13)=0.03606;
+	exchangeability_(13,11)=0.03606;
+	exchangeability_(11,12)=0.93169;
+	exchangeability_(12,11)=0.93169;
+	exchangeability_(10,13)=4.27586;
+	exchangeability_(13,10)=4.27586;
+	exchangeability_(12,14)=0.09162;
+	exchangeability_(14,12)=0.09162;
+	exchangeability_(7,10)=0.03103;
+	exchangeability_(10,7)=0.03103;
+	exchangeability_(0,8)=0.55873;
+	exchangeability_(8,0)=0.55873;
+	exchangeability_(3,4)=0.16581;
+	exchangeability_(4,3)=0.16581;
+	exchangeability_(3,8)=0.76134;
+	exchangeability_(8,3)=0.76134;
+	exchangeability_(2,10)=0.11984;
+	exchangeability_(10,2)=0.11984;
+	exchangeability_(17,18)=4.70488;
+	exchangeability_(18,17)=4.70488;
+	exchangeability_(10,18)=0.55292;
+	exchangeability_(18,10)=0.55292;
+	exchangeability_(6,9)=0.03808;
+	exchangeability_(9,6)=0.03808;
+	exchangeability_(4,9)=0.56096;
+	exchangeability_(9,4)=0.56096;
+	exchangeability_(14,19)=0.31598;
+	exchangeability_(19,14)=0.31598;
+	exchangeability_(9,16)=1.4924;
+	exchangeability_(16,9)=1.4924;
+	exchangeability_(12,15)=0.39954;
+	exchangeability_(15,12)=0.39954;
+	exchangeability_(1,4)=1.61518;
+	exchangeability_(4,1)=1.61518;
+	exchangeability_(4,17)=1.25961;
+	exchangeability_(17,4)=1.25961;
+	exchangeability_(0,11)=0.70673;
+	exchangeability_(11,0)=0.70673;
+	exchangeability_(9,13)=1.58182;
+	exchangeability_(13,9)=1.58182;
+	exchangeability_(1,10)=0.58009;
+	exchangeability_(10,1)=0.58009;
+	exchangeability_(11,19)=0.32389;
+	exchangeability_(19,11)=0.32389;
+	exchangeability_(2,12)=0.39994;
+	exchangeability_(12,2)=0.39994;
+	exchangeability_(10,19)=2.8833;
+	exchangeability_(19,10)=2.8833;
+	exchangeability_(6,8)=0.32362;
+	exchangeability_(8,6)=0.32362;
+	exchangeability_(9,17)=0.13442;
+	exchangeability_(17,9)=0.13442;
+	exchangeability_(7,11)=0.28395;
+	exchangeability_(11,7)=0.28395;
+	exchangeability_(3,15)=0.98708;
+	exchangeability_(15,3)=0.98708;
+	exchangeability_(13,19)=0.72257;
+	exchangeability_(19,13)=0.72257;
+	exchangeability_(14,18)=0.04784;
+	exchangeability_(18,14)=0.04784;
+	exchangeability_(6,18)=0.07966;
+	exchangeability_(18,6)=0.07966;
+	exchangeability_(5,16)=1.01159;
+	exchangeability_(16,5)=1.01159;
+	exchangeability_(5,15)=1.04507;
+	exchangeability_(15,5)=1.04507;
+}
+
+
+if (getName()=="Extended"){
+   exchangeability_(10,17)=0.42927;
+	exchangeability_(17,10)=0.42927;
+	exchangeability_(6,11)=1.21104;
+	exchangeability_(11,6)=1.21104;
+	exchangeability_(4,7)=1.24918;
+	exchangeability_(7,4)=1.24918;
+	exchangeability_(17,19)=0.07316;
+	exchangeability_(19,17)=0.07316;
+	exchangeability_(9,19)=6.81524;
+	exchangeability_(19,9)=6.81524;
+	exchangeability_(5,6)=4.32653;
+	exchangeability_(6,5)=4.32653;
+	exchangeability_(1,6)=0.2908;
+	exchangeability_(6,1)=0.2908;
+	exchangeability_(0,12)=0.99283;
+	exchangeability_(12,0)=0.99283;
+	exchangeability_(1,2)=0.59537;
+	exchangeability_(2,1)=0.59537;
+	exchangeability_(11,16)=1.25644;
+	exchangeability_(16,11)=1.25644;
+	exchangeability_(1,17)=0.45227;
+	exchangeability_(17,1)=0.45227;
+	exchangeability_(8,15)=1.07411;
+	exchangeability_(15,8)=1.07411;
+	exchangeability_(13,17)=2.17851;
+	exchangeability_(17,13)=2.17851;
+	exchangeability_(10,16)=0.14233;
+	exchangeability_(16,10)=0.14233;
+	exchangeability_(13,15)=0.38242;
+	exchangeability_(15,13)=0.38242;
+	exchangeability_(9,18)=0.12283;
+	exchangeability_(18,9)=0.12283;
+	exchangeability_(2,18)=0.45118;
+	exchangeability_(18,2)=0.45118;
+	exchangeability_(7,9)=0.00178;
+	exchangeability_(9,7)=0.00178;
+	exchangeability_(3,5)=0.49727;
+	exchangeability_(5,3)=0.49727;
+	exchangeability_(3,13)=0.01481;
+	exchangeability_(13,3)=0.01481;
+	exchangeability_(0,10)=0.22682;
+	exchangeability_(10,0)=0.22682;
+	exchangeability_(9,11)=0.08222;
+	exchangeability_(11,9)=0.08222;
+	exchangeability_(8,14)=0.38172;
+	exchangeability_(14,8)=0.38172;
+	exchangeability_(2,8)=5.15929;
+	exchangeability_(8,2)=5.15929;
+	exchangeability_(4,6)=0.00378;
+	exchangeability_(6,4)=0.00378;
+	exchangeability_(8,13)=0.64127;
+	exchangeability_(13,8)=0.64127;
+	exchangeability_(5,7)=0.17387;
+	exchangeability_(7,5)=0.17387;
+	exchangeability_(1,7)=0.30295;
+	exchangeability_(7,1)=0.30295;
+	exchangeability_(4,15)=4.26393;
+	exchangeability_(15,4)=4.26393;
+	exchangeability_(1,14)=0.39517;
+	exchangeability_(14,1)=0.39517;
+	exchangeability_(1,18)=0.11209;
+	exchangeability_(18,1)=0.11209;
+	exchangeability_(11,18)=0.09667;
+	exchangeability_(18,11)=0.09667;
+	exchangeability_(0,5)=0.54266;
+	exchangeability_(5,0)=0.54266;
+	exchangeability_(2,9)=0.16671;
+	exchangeability_(9,2)=0.16671;
+	exchangeability_(7,18)=0.03042;
+	exchangeability_(18,7)=0.03042;
+	exchangeability_(7,14)=0.20534;
+	exchangeability_(14,7)=0.20534;
+	exchangeability_(3,19)=0.04104;
+	exchangeability_(19,3)=0.04104;
+	exchangeability_(5,13)=0.04278;
+	exchangeability_(13,5)=0.04278;
+	exchangeability_(15,19)=0.07666;
+	exchangeability_(19,15)=0.07666;
+	exchangeability_(11,17)=0.05086;
+	exchangeability_(17,11)=0.05086;
+	exchangeability_(7,13)=0.04099;
+	exchangeability_(13,7)=0.04099;
+	exchangeability_(0,2)=0.25649;
+	exchangeability_(2,0)=0.25649;
+	exchangeability_(9,12)=3.32916;
+	exchangeability_(12,9)=3.32916;
+	exchangeability_(3,12)=0.04151;
+	exchangeability_(12,3)=0.04151;
+	exchangeability_(8,19)=0.12332;
+	exchangeability_(19,8)=0.12332;
+	exchangeability_(0,14)=1.87651;
+	exchangeability_(14,0)=1.87651;
+	exchangeability_(5,17)=0.16404;
+	exchangeability_(17,5)=0.16404;
+	exchangeability_(4,10)=0.76355;
+	exchangeability_(10,4)=0.76355;
+	exchangeability_(10,15)=0.14707;
+	exchangeability_(15,10)=0.14707;
+	exchangeability_(14,17)=0.02277;
+	exchangeability_(17,14)=0.02277;
+	exchangeability_(16,18)=0.13531;
+	exchangeability_(18,16)=0.13531;
+	exchangeability_(1,9)=0.05303;
+	exchangeability_(9,1)=0.05303;
+	exchangeability_(4,5)=0.13329;
+	exchangeability_(5,4)=0.13329;
+	exchangeability_(9,10)=3.21716;
+	exchangeability_(10,9)=3.21716;
+	exchangeability_(11,14)=0.3933;
+	exchangeability_(14,11)=0.3933;
+	exchangeability_(8,17)=0.74138;
+	exchangeability_(17,8)=0.74138;
+	exchangeability_(0,15)=6.06603;
+	exchangeability_(15,0)=6.06603;
+	exchangeability_(2,11)=2.54318;
+	exchangeability_(11,2)=2.54318;
+	exchangeability_(10,14)=0.31513;
+	exchangeability_(14,10)=0.31513;
+	exchangeability_(13,16)=0.07965;
+	exchangeability_(16,13)=0.07965;
+	exchangeability_(7,19)=0.05339;
+	exchangeability_(19,7)=0.05339;
+	exchangeability_(3,16)=0.28752;
+	exchangeability_(16,3)=0.28752;
+	exchangeability_(7,12)=0.1176;
+	exchangeability_(12,7)=0.1176;
+	exchangeability_(15,16)=6.09255;
+	exchangeability_(16,15)=6.09255;
+	exchangeability_(14,15)=1.46267;
+	exchangeability_(15,14)=1.46267;
+	exchangeability_(3,11)=0.22351;
+	exchangeability_(11,3)=0.22351;
+	exchangeability_(6,7)=0.31678;
+	exchangeability_(7,6)=0.31678;
+	exchangeability_(8,16)=0.512;
+	exchangeability_(16,8)=0.512;
+	exchangeability_(0,1)=0.22175;
+	exchangeability_(1,0)=0.22175;
+	exchangeability_(5,9)=0.05593;
+	exchangeability_(9,5)=0.05593;
+	exchangeability_(12,18)=0.3441;
+	exchangeability_(18,12)=0.3441;
+	exchangeability_(6,16)=0.78108;
+	exchangeability_(16,6)=0.78108;
+	exchangeability_(1,11)=6.0173;
+	exchangeability_(11,1)=6.0173;
+	exchangeability_(2,14)=0.36265;
+	exchangeability_(14,2)=0.36265;
+	exchangeability_(0,4)=4.89314;
+	exchangeability_(4,0)=4.89314;
+	exchangeability_(1,16)=0.64513;
+	exchangeability_(16,1)=0.64513;
+	exchangeability_(6,13)=0.01118;
+	exchangeability_(13,6)=0.01118;
+	exchangeability_(18,19)=0.10173;
+	exchangeability_(19,18)=0.10173;
+	exchangeability_(5,8)=5.08607;
+	exchangeability_(8,5)=5.08607;
+	exchangeability_(16,19)=1.05244;
+	exchangeability_(19,16)=1.05244;
+	exchangeability_(7,16)=0.05514;
+	exchangeability_(16,7)=0.05514;
+	exchangeability_(8,11)=0.67104;
+	exchangeability_(11,8)=0.67104;
+	exchangeability_(3,17)=0.03417;
+	exchangeability_(17,3)=0.03417;
+	exchangeability_(6,17)=0.04967;
+	exchangeability_(17,6)=0.04967;
+	exchangeability_(2,3)=7.76982;
+	exchangeability_(3,2)=7.76982;
+	exchangeability_(3,9)=0.01649;
+	exchangeability_(9,3)=0.01649;
+	exchangeability_(0,16)=1.82747;
+	exchangeability_(16,0)=1.82747;
+	exchangeability_(5,11)=3.43285;
+	exchangeability_(11,5)=3.43285;
+	exchangeability_(4,8)=0.7378;
+	exchangeability_(8,4)=0.7378;
+	exchangeability_(16,17)=0.11124;
+	exchangeability_(17,16)=0.11124;
+	exchangeability_(5,19)=0.2229;
+	exchangeability_(19,5)=0.2229;
+	exchangeability_(1,3)=0.11231;
+	exchangeability_(3,1)=0.11231;
+	exchangeability_(4,19)=1.75082;
+	exchangeability_(19,4)=1.75082;
+	exchangeability_(6,19)=0.22596;
+	exchangeability_(19,6)=0.22596;
+	exchangeability_(1,12)=0.35197;
+	exchangeability_(12,1)=0.35197;
+	exchangeability_(0,6)=0.54946;
+	exchangeability_(6,0)=0.54946;
+	exchangeability_(2,6)=0.51826;
+	exchangeability_(6,2)=0.51826;
+	exchangeability_(1,19)=0.11902;
+	exchangeability_(19,1)=0.11902;
+	exchangeability_(0,17)=0.10142;
+	exchangeability_(17,0)=0.10142;
+	exchangeability_(2,17)=0.06521;
+	exchangeability_(17,2)=0.06521;
+	exchangeability_(7,15)=2.2663;
+	exchangeability_(15,7)=2.2663;
+	exchangeability_(3,14)=0.55053;
+	exchangeability_(14,3)=0.55053;
+	exchangeability_(8,9)=0.0986;
+	exchangeability_(9,8)=0.0986;
+	exchangeability_(3,18)=0.10876;
+	exchangeability_(18,3)=0.10876;
+	exchangeability_(0,3)=0.44775;
+	exchangeability_(3,0)=0.44775;
+	exchangeability_(2,13)=0.09052;
+	exchangeability_(13,2)=0.09052;
+	exchangeability_(0,19)=1.97043;
+	exchangeability_(19,0)=1.97043;
+	exchangeability_(5,12)=1.70068;
+	exchangeability_(12,5)=1.70068;
+	exchangeability_(4,13)=1.00469;
+	exchangeability_(13,4)=1.00469;
+	exchangeability_(10,12)=7.49664;
+	exchangeability_(12,10)=7.49664;
+	exchangeability_(5,18)=0.13219;
+	exchangeability_(18,5)=0.13219;
+	exchangeability_(14,16)=0.41739;
+	exchangeability_(16,14)=0.41739;
+	exchangeability_(1,13)=0.04122;
+	exchangeability_(13,1)=0.04122;
+	exchangeability_(4,16)=1.39593;
+	exchangeability_(16,4)=1.39593;
+	exchangeability_(6,14)=0.41291;
+	exchangeability_(14,6)=0.41291;
+	exchangeability_(11,15)=0.68329;
+	exchangeability_(15,11)=0.68329;
+	exchangeability_(0,7)=5.41132;
+	exchangeability_(7,0)=5.41132;
+	exchangeability_(2,7)=0.90771;
+	exchangeability_(7,2)=0.90771;
+	exchangeability_(8,18)=4.37336;
+	exchangeability_(18,8)=4.37336;
+	exchangeability_(5,10)=0.53771;
+	exchangeability_(10,5)=0.53771;
+	exchangeability_(15,18)=0.32523;
+	exchangeability_(18,15)=0.32523;
+	exchangeability_(12,16)=1.43518;
+	exchangeability_(16,12)=1.43518;
+	exchangeability_(5,14)=0.73123;
+	exchangeability_(14,5)=0.73123;
+	exchangeability_(7,8)=0.20928;
+	exchangeability_(8,7)=0.20928;
+	exchangeability_(15,17)=0.30484;
+	exchangeability_(17,15)=0.30484;
+	exchangeability_(3,7)=0.96165;
+	exchangeability_(7,3)=0.96165;
+	exchangeability_(6,15)=0.7668;
+	exchangeability_(15,6)=0.7668;
+	exchangeability_(12,13)=1.86324;
+	exchangeability_(13,12)=1.86324;
+	exchangeability_(13,14)=0.04385;
+	exchangeability_(14,13)=0.04385;
+	exchangeability_(3,10)=0.01584;
+	exchangeability_(10,3)=0.01584;
+	exchangeability_(0,13)=0.19197;
+	exchangeability_(13,0)=0.19197;
+	exchangeability_(6,12)=0.11198;
+	exchangeability_(12,6)=0.11198;
+	exchangeability_(4,12)=1.27163;
+	exchangeability_(12,4)=1.27163;
+	exchangeability_(9,14)=0.0116;
+	exchangeability_(14,9)=0.0116;
+	exchangeability_(10,11)=0.10618;
+	exchangeability_(11,10)=0.10618;
+	exchangeability_(12,17)=0.54545;
+	exchangeability_(17,12)=0.54545;
+	exchangeability_(2,19)=0.09186;
+	exchangeability_(19,2)=0.09186;
+	exchangeability_(8,10)=0.32161;
+	exchangeability_(10,8)=0.32161;
+	exchangeability_(1,8)=2.76004;
+	exchangeability_(8,1)=2.76004;
+	exchangeability_(1,5)=2.88679;
+	exchangeability_(5,1)=2.88679;
+	exchangeability_(2,5)=1.92707;
+	exchangeability_(5,2)=1.92707;
+	exchangeability_(0,18)=0.09191;
+	exchangeability_(18,0)=0.09191;
+	exchangeability_(13,18)=8.27626;
+	exchangeability_(18,13)=8.27626;
+	exchangeability_(6,10)=0.04291;
+	exchangeability_(10,6)=0.04291;
+	exchangeability_(9,15)=0.0479;
+	exchangeability_(15,9)=0.0479;
+	exchangeability_(2,15)=5.61271;
+	exchangeability_(15,2)=5.61271;
+	exchangeability_(7,17)=0.18347;
+	exchangeability_(17,7)=0.18347;
+	exchangeability_(2,16)=1.88317;
+	exchangeability_(16,2)=1.88317;
+	exchangeability_(12,19)=1.42707;
+	exchangeability_(19,12)=1.42707;
+	exchangeability_(8,12)=0.32639;
+	exchangeability_(12,8)=0.32639;
+	exchangeability_(3,6)=5.39325;
+	exchangeability_(6,3)=5.39325;
+	exchangeability_(4,11)=0.02357;
+	exchangeability_(11,4)=0.02357;
+	exchangeability_(4,18)=1.18357;
+	exchangeability_(18,4)=1.18357;
+	exchangeability_(0,9)=0.02668;
+	exchangeability_(9,0)=0.02668;
+	exchangeability_(4,14)=0.17403;
+	exchangeability_(14,4)=0.17403;
+	exchangeability_(1,15)=1.08323;
+	exchangeability_(15,1)=1.08323;
+	exchangeability_(2,4)=1.06188;
+	exchangeability_(4,2)=1.06188;
+	exchangeability_(11,13)=0.02317;
+	exchangeability_(13,11)=0.02317;
+	exchangeability_(11,12)=0.51982;
+	exchangeability_(12,11)=0.51982;
+	exchangeability_(10,13)=2.23332;
+	exchangeability_(13,10)=2.23332;
+	exchangeability_(12,14)=0.13536;
+	exchangeability_(14,12)=0.13536;
+	exchangeability_(7,10)=0.03294;
+	exchangeability_(10,7)=0.03294;
+	exchangeability_(0,8)=0.28375;
+	exchangeability_(8,0)=0.28375;
+	exchangeability_(3,4)=0.16447;
+	exchangeability_(4,3)=0.16447;
+	exchangeability_(3,8)=0.97842;
+	exchangeability_(8,3)=0.97842;
+	exchangeability_(2,10)=0.06226;
+	exchangeability_(10,2)=0.06226;
+	exchangeability_(17,18)=2.5979;
+	exchangeability_(18,17)=2.5979;
+	exchangeability_(10,18)=0.18694;
+	exchangeability_(18,10)=0.18694;
+	exchangeability_(6,9)=0.02673;
+	exchangeability_(9,6)=0.02673;
+	exchangeability_(4,9)=0.15194;
+	exchangeability_(9,4)=0.15194;
+	exchangeability_(14,19)=0.12704;
+	exchangeability_(19,14)=0.12704;
+	exchangeability_(9,16)=0.58836;
+	exchangeability_(16,9)=0.58836;
+	exchangeability_(12,15)=0.35212;
+	exchangeability_(15,12)=0.35212;
+	exchangeability_(1,4)=0.92913;
+	exchangeability_(4,1)=0.92913;
+	exchangeability_(4,17)=0.59203;
+	exchangeability_(17,4)=0.59203;
+	exchangeability_(0,11)=0.23551;
+	exchangeability_(11,0)=0.23551;
+	exchangeability_(9,13)=0.81301;
+	exchangeability_(13,9)=0.81301;
+	exchangeability_(1,10)=0.25164;
+	exchangeability_(10,1)=0.25164;
+	exchangeability_(11,19)=0.12428;
+	exchangeability_(19,11)=0.12428;
+	exchangeability_(2,12)=0.41545;
+	exchangeability_(12,2)=0.41545;
+	exchangeability_(10,19)=1.42766;
+	exchangeability_(19,10)=1.42766;
+	exchangeability_(6,8)=0.42181;
+	exchangeability_(8,6)=0.42181;
+	exchangeability_(9,17)=0.06929;
+	exchangeability_(17,9)=0.06929;
+	exchangeability_(7,11)=0.16054;
+	exchangeability_(11,7)=0.16054;
+	exchangeability_(3,15)=1.03554;
+	exchangeability_(15,3)=1.03554;
+	exchangeability_(13,19)=0.34126;
+	exchangeability_(19,13)=0.34126;
+	exchangeability_(14,18)=0.05325;
+	exchangeability_(18,14)=0.05325;
+	exchangeability_(6,18)=0.04295;
+	exchangeability_(18,6)=0.04295;
+	exchangeability_(5,16)=1.01371;
+	exchangeability_(16,5)=1.01371;
+	exchangeability_(5,15)=1.42921;
+	exchangeability_(15,5)=1.42921;
+}
+
+
+if (getName()=="Helix"){
+	exchangeability_(10,17)=0.62433;
+	exchangeability_(17,10)=0.62433;
+	exchangeability_(6,11)=0.76892;
+	exchangeability_(11,6)=0.76892;
+	exchangeability_(4,7)=1.46554;
+	exchangeability_(7,4)=1.46554;
+	exchangeability_(17,19)=0.17514;
+	exchangeability_(19,17)=0.17514;
+	exchangeability_(9,19)=14.4608;
+	exchangeability_(19,9)=14.4608;
+	exchangeability_(5,6)=2.32068;
+	exchangeability_(6,5)=2.32068;
+	exchangeability_(1,6)=0.15841;
+	exchangeability_(6,1)=0.15841;
+	exchangeability_(0,12)=0.61043;
+	exchangeability_(12,0)=0.61043;
+	exchangeability_(1,2)=0.66487;
+	exchangeability_(2,1)=0.66487;
+	exchangeability_(11,16)=1.1114;
+	exchangeability_(16,11)=1.1114;
+	exchangeability_(1,17)=0.36901;
+	exchangeability_(17,1)=0.36901;
+	exchangeability_(8,15)=1.08833;
+	exchangeability_(15,8)=1.08833;
+	exchangeability_(13,17)=3.91597;
+	exchangeability_(17,13)=3.91597;
+	exchangeability_(10,16)=0.4027;
+	exchangeability_(16,10)=0.4027;
+	exchangeability_(13,15)=0.47062;
+	exchangeability_(15,13)=0.47062;
+	exchangeability_(9,18)=0.19554;
+	exchangeability_(18,9)=0.19554;
+	exchangeability_(2,18)=0.59471;
+	exchangeability_(18,2)=0.59471;
+	exchangeability_(7,9)=0.02125;
+	exchangeability_(9,7)=0.02125;
+	exchangeability_(3,5)=0.51736;
+	exchangeability_(5,3)=0.51736;
+	exchangeability_(3,13)=0.01847;
+	exchangeability_(13,3)=0.01847;
+	exchangeability_(0,10)=0.19302;
+	exchangeability_(10,0)=0.19302;
+	exchangeability_(9,11)=0.14705;
+	exchangeability_(11,9)=0.14705;
+	exchangeability_(8,14)=0.45844;
+	exchangeability_(14,8)=0.45844;
+	exchangeability_(2,8)=5.8459;
+	exchangeability_(8,2)=5.8459;
+	exchangeability_(4,6)=1e-05;
+	exchangeability_(6,4)=1e-05;
+	exchangeability_(8,13)=1.24454;
+	exchangeability_(13,8)=1.24454;
+	exchangeability_(5,7)=0.51149;
+	exchangeability_(7,5)=0.51149;
+	exchangeability_(1,7)=0.66121;
+	exchangeability_(7,1)=0.66121;
+	exchangeability_(4,15)=6.39829;
+	exchangeability_(15,4)=6.39829;
+	exchangeability_(1,14)=0.18161;
+	exchangeability_(14,1)=0.18161;
+	exchangeability_(1,18)=0.17098;
+	exchangeability_(18,1)=0.17098;
+	exchangeability_(11,18)=0.06919;
+	exchangeability_(18,11)=0.06919;
+	exchangeability_(0,5)=0.77654;
+	exchangeability_(5,0)=0.77654;
+	exchangeability_(2,9)=0.23322;
+	exchangeability_(9,2)=0.23322;
+	exchangeability_(7,18)=0.06438;
+	exchangeability_(18,7)=0.06438;
+	exchangeability_(7,14)=0.5681;
+	exchangeability_(14,7)=0.5681;
+	exchangeability_(3,19)=0.04617;
+	exchangeability_(19,3)=0.04617;
+	exchangeability_(5,13)=0.04721;
+	exchangeability_(13,5)=0.04721;
+	exchangeability_(15,19)=0.18025;
+	exchangeability_(19,15)=0.18025;
+	exchangeability_(11,17)=0.0415;
+	exchangeability_(17,11)=0.0415;
+	exchangeability_(7,13)=0.08654;
+	exchangeability_(13,7)=0.08654;
+	exchangeability_(0,2)=0.37436;
+	exchangeability_(2,0)=0.37436;
+	exchangeability_(9,12)=6.26068;
+	exchangeability_(12,9)=6.26068;
+	exchangeability_(3,12)=0.03566;
+	exchangeability_(12,3)=0.03566;
+	exchangeability_(8,19)=0.17498;
+	exchangeability_(19,8)=0.17498;
+	exchangeability_(0,14)=1.09058;
+	exchangeability_(14,0)=1.09058;
+	exchangeability_(5,17)=0.1833;
+	exchangeability_(17,5)=0.1833;
+	exchangeability_(4,10)=1.13654;
+	exchangeability_(10,4)=1.13654;
+	exchangeability_(10,15)=0.19386;
+	exchangeability_(15,10)=0.19386;
+	exchangeability_(14,17)=0.05381;
+	exchangeability_(17,14)=0.05381;
+	exchangeability_(16,18)=0.2016;
+	exchangeability_(18,16)=0.2016;
+	exchangeability_(1,9)=0.09964;
+	exchangeability_(9,1)=0.09964;
+	exchangeability_(4,5)=0.11203;
+	exchangeability_(5,4)=0.11203;
+	exchangeability_(9,10)=4.91571;
+	exchangeability_(10,9)=4.91571;
+	exchangeability_(11,14)=0.19829;
+	exchangeability_(14,11)=0.19829;
+	exchangeability_(8,17)=0.95029;
+	exchangeability_(17,8)=0.95029;
+	exchangeability_(0,15)=6.24368;
+	exchangeability_(15,0)=6.24368;
+	exchangeability_(2,11)=1.92631;
+	exchangeability_(11,2)=1.92631;
+	exchangeability_(10,14)=0.20746;
+	exchangeability_(14,10)=0.20746;
+	exchangeability_(13,16)=0.23112;
+	exchangeability_(16,13)=0.23112;
+	exchangeability_(7,19)=0.20284;
+	exchangeability_(19,7)=0.20284;
+	exchangeability_(3,16)=0.34705;
+	exchangeability_(16,3)=0.34705;
+	exchangeability_(7,12)=0.17116;
+	exchangeability_(12,7)=0.17116;
+	exchangeability_(15,16)=8.83247;
+	exchangeability_(16,15)=8.83247;
+	exchangeability_(14,15)=1.53427;
+	exchangeability_(15,14)=1.53427;
+	exchangeability_(3,11)=0.16331;
+	exchangeability_(11,3)=0.16331;
+	exchangeability_(6,7)=0.57321;
+	exchangeability_(7,6)=0.57321;
+	exchangeability_(8,16)=0.64277;
+	exchangeability_(16,8)=0.64277;
+	exchangeability_(0,1)=0.34648;
+	exchangeability_(1,0)=0.34648;
+	exchangeability_(5,9)=0.08948;
+	exchangeability_(9,5)=0.08948;
+	exchangeability_(12,18)=0.46578;
+	exchangeability_(18,12)=0.46578;
+	exchangeability_(6,16)=0.4957;
+	exchangeability_(16,6)=0.4957;
+	exchangeability_(1,11)=3.82787;
+	exchangeability_(11,1)=3.82787;
+	exchangeability_(2,14)=0.09366;
+	exchangeability_(14,2)=0.09366;
+	exchangeability_(0,4)=3.19247;
+	exchangeability_(4,0)=3.19247;
+	exchangeability_(1,16)=0.56636;
+	exchangeability_(16,1)=0.56636;
+	exchangeability_(6,13)=0.01027;
+	exchangeability_(13,6)=0.01027;
+	exchangeability_(18,19)=0.28172;
+	exchangeability_(19,18)=0.28172;
+	exchangeability_(5,8)=3.96096;
+	exchangeability_(8,5)=3.96096;
+	exchangeability_(16,19)=3.58533;
+	exchangeability_(19,16)=3.58533;
+	exchangeability_(7,16)=0.50003;
+	exchangeability_(16,7)=0.50003;
+	exchangeability_(8,11)=0.53421;
+	exchangeability_(11,8)=0.53421;
+	exchangeability_(3,17)=0.04682;
+	exchangeability_(17,3)=0.04682;
+	exchangeability_(6,17)=0.04079;
+	exchangeability_(17,6)=0.04079;
+	exchangeability_(2,3)=3.71053;
+	exchangeability_(3,2)=3.71053;
+	exchangeability_(3,9)=0.00563;
+	exchangeability_(9,3)=0.00563;
+	exchangeability_(0,16)=2.84716;
+	exchangeability_(16,0)=2.84716;
+	exchangeability_(5,11)=2.4879;
+	exchangeability_(11,5)=2.4879;
+	exchangeability_(4,8)=1.08491;
+	exchangeability_(8,4)=1.08491;
+	exchangeability_(16,17)=0.10066;
+	exchangeability_(17,16)=0.10066;
+	exchangeability_(5,19)=0.19162;
+	exchangeability_(19,5)=0.19162;
+	exchangeability_(1,3)=0.07916;
+	exchangeability_(3,1)=0.07916;
+	exchangeability_(4,19)=4.01169;
+	exchangeability_(19,4)=4.01169;
+	exchangeability_(6,19)=0.19229;
+	exchangeability_(19,6)=0.19229;
+	exchangeability_(1,12)=0.34403;
+	exchangeability_(12,1)=0.34403;
+	exchangeability_(0,6)=0.84189;
+	exchangeability_(6,0)=0.84189;
+	exchangeability_(2,6)=0.44306;
+	exchangeability_(6,2)=0.44306;
+	exchangeability_(1,19)=0.13645;
+	exchangeability_(19,1)=0.13645;
+	exchangeability_(0,17)=0.09098;
+	exchangeability_(17,0)=0.09098;
+	exchangeability_(2,17)=0.08558;
+	exchangeability_(17,2)=0.08558;
+	exchangeability_(7,15)=5.46314;
+	exchangeability_(15,7)=5.46314;
+	exchangeability_(3,14)=0.38649;
+	exchangeability_(14,3)=0.38649;
+	exchangeability_(8,9)=0.13215;
+	exchangeability_(9,8)=0.13215;
+	exchangeability_(3,18)=0.1061;
+	exchangeability_(18,3)=0.1061;
+	exchangeability_(0,3)=0.55735;
+	exchangeability_(3,0)=0.55735;
+	exchangeability_(2,13)=0.10628;
+	exchangeability_(13,2)=0.10628;
+	exchangeability_(0,19)=2.14051;
+	exchangeability_(19,0)=2.14051;
+	exchangeability_(5,12)=1.14617;
+	exchangeability_(12,5)=1.14617;
+	exchangeability_(4,13)=1.86491;
+	exchangeability_(13,4)=1.86491;
+	exchangeability_(10,12)=7.73862;
+	exchangeability_(12,10)=7.73862;
+	exchangeability_(5,18)=0.12142;
+	exchangeability_(18,5)=0.12142;
+	exchangeability_(14,16)=0.68516;
+	exchangeability_(16,14)=0.68516;
+	exchangeability_(1,13)=0.03517;
+	exchangeability_(13,1)=0.03517;
+	exchangeability_(4,16)=3.71197;
+	exchangeability_(16,4)=3.71197;
+	exchangeability_(6,14)=0.29015;
+	exchangeability_(14,6)=0.29015;
+	exchangeability_(11,15)=0.70737;
+	exchangeability_(15,11)=0.70737;
+	exchangeability_(0,7)=4.03711;
+	exchangeability_(7,0)=4.03711;
+	exchangeability_(2,7)=1.86696;
+	exchangeability_(7,2)=1.86696;
+	exchangeability_(8,18)=8.16704;
+	exchangeability_(18,8)=8.16704;
+	exchangeability_(5,10)=0.58419;
+	exchangeability_(10,5)=0.58419;
+	exchangeability_(15,18)=0.40546;
+	exchangeability_(18,15)=0.40546;
+	exchangeability_(12,16)=2.48346;
+	exchangeability_(16,12)=2.48346;
+	exchangeability_(5,14)=0.46256;
+	exchangeability_(14,5)=0.46256;
+	exchangeability_(7,8)=0.38076;
+	exchangeability_(8,7)=0.38076;
+	exchangeability_(15,17)=0.29972;
+	exchangeability_(17,15)=0.29972;
+	exchangeability_(3,7)=1.14492;
+	exchangeability_(7,3)=1.14492;
+	exchangeability_(6,15)=0.4306;
+	exchangeability_(15,6)=0.4306;
+	exchangeability_(12,13)=2.32653;
+	exchangeability_(13,12)=2.32653;
+	exchangeability_(13,14)=0.06759;
+	exchangeability_(14,13)=0.06759;
+	exchangeability_(3,10)=0.00965;
+	exchangeability_(10,3)=0.00965;
+	exchangeability_(0,13)=0.14728;
+	exchangeability_(13,0)=0.14728;
+	exchangeability_(6,12)=0.10324;
+	exchangeability_(12,6)=0.10324;
+	exchangeability_(4,12)=1.62403;
+	exchangeability_(12,4)=1.62403;
+	exchangeability_(9,14)=0.04324;
+	exchangeability_(14,9)=0.04324;
+	exchangeability_(10,11)=0.13616;
+	exchangeability_(11,10)=0.13616;
+	exchangeability_(12,17)=0.98067;
+	exchangeability_(17,12)=0.98067;
+	exchangeability_(2,19)=0.14538;
+	exchangeability_(19,2)=0.14538;
+	exchangeability_(8,10)=0.4859;
+	exchangeability_(10,8)=0.4859;
+	exchangeability_(1,8)=2.12376;
+	exchangeability_(8,1)=2.12376;
+	exchangeability_(1,5)=1.90286;
+	exchangeability_(5,1)=1.90286;
+	exchangeability_(2,5)=1.561;
+	exchangeability_(5,2)=1.561;
+	exchangeability_(0,18)=0.15285;
+	exchangeability_(18,0)=0.15285;
+	exchangeability_(13,18)=15.1789;
+	exchangeability_(18,13)=15.1789;
+	exchangeability_(6,10)=0.03984;
+	exchangeability_(10,6)=0.03984;
+	exchangeability_(9,15)=0.10213;
+	exchangeability_(15,9)=0.10213;
+	exchangeability_(2,15)=5.63366;
+	exchangeability_(15,2)=5.63366;
+	exchangeability_(7,17)=0.39109;
+	exchangeability_(17,7)=0.39109;
+	exchangeability_(2,16)=2.98473;
+	exchangeability_(16,2)=2.98473;
+	exchangeability_(12,19)=2.39384;
+	exchangeability_(19,12)=2.39384;
+	exchangeability_(8,12)=0.36484;
+	exchangeability_(12,8)=0.36484;
+	exchangeability_(3,6)=3.79285;
+	exchangeability_(6,3)=3.79285;
+	exchangeability_(4,11)=0.02175;
+	exchangeability_(11,4)=0.02175;
+	exchangeability_(4,18)=2.05164;
+	exchangeability_(18,4)=2.05164;
+	exchangeability_(0,9)=0.11135;
+	exchangeability_(9,0)=0.11135;
+	exchangeability_(4,14)=0.09765;
+	exchangeability_(14,4)=0.09765;
+	exchangeability_(1,15)=0.83614;
+	exchangeability_(15,1)=0.83614;
+	exchangeability_(2,4)=0.8912;
+	exchangeability_(4,2)=0.8912;
+	exchangeability_(11,13)=0.01626;
+	exchangeability_(13,11)=0.01626;
+	exchangeability_(11,12)=0.5494;
+	exchangeability_(12,11)=0.5494;
+	exchangeability_(10,13)=3.24363;
+	exchangeability_(13,10)=3.24363;
+	exchangeability_(12,14)=0.06103;
+	exchangeability_(14,12)=0.06103;
+	exchangeability_(7,10)=0.04811;
+	exchangeability_(10,7)=0.04811;
+	exchangeability_(0,8)=0.39422;
+	exchangeability_(8,0)=0.39422;
+	exchangeability_(3,4)=0.00672;
+	exchangeability_(4,3)=0.00672;
+	exchangeability_(3,8)=0.73787;
+	exchangeability_(8,3)=0.73787;
+	exchangeability_(2,10)=0.1155;
+	exchangeability_(10,2)=0.1155;
+	exchangeability_(17,18)=4.03582;
+	exchangeability_(18,17)=4.03582;
+	exchangeability_(10,18)=0.3526;
+	exchangeability_(18,10)=0.3526;
+	exchangeability_(6,9)=0.01952;
+	exchangeability_(9,6)=0.01952;
+	exchangeability_(4,9)=0.83953;
+	exchangeability_(9,4)=0.83953;
+	exchangeability_(14,19)=0.4185;
+	exchangeability_(19,14)=0.4185;
+	exchangeability_(9,16)=1.69895;
+	exchangeability_(16,9)=1.69895;
+	exchangeability_(12,15)=0.43851;
+	exchangeability_(15,12)=0.43851;
+	exchangeability_(1,4)=1.02723;
+	exchangeability_(4,1)=1.02723;
+	exchangeability_(4,17)=0.95052;
+	exchangeability_(17,4)=0.95052;
+	exchangeability_(0,11)=0.48168;
+	exchangeability_(11,0)=0.48168;
+	exchangeability_(9,13)=0.92733;
+	exchangeability_(13,9)=0.92733;
+	exchangeability_(1,10)=0.30762;
+	exchangeability_(10,1)=0.30762;
+	exchangeability_(11,19)=0.13632;
+	exchangeability_(19,11)=0.13632;
+	exchangeability_(2,12)=0.45264;
+	exchangeability_(12,2)=0.45264;
+	exchangeability_(10,19)=2.17503;
+	exchangeability_(19,10)=2.17503;
+	exchangeability_(6,8)=0.27015;
+	exchangeability_(8,6)=0.27015;
+	exchangeability_(9,17)=0.07578;
+	exchangeability_(17,9)=0.07578;
+	exchangeability_(7,11)=0.327;
+	exchangeability_(11,7)=0.327;
+	exchangeability_(3,15)=0.95213;
+	exchangeability_(15,3)=0.95213;
+	exchangeability_(13,19)=0.6593;
+	exchangeability_(19,13)=0.6593;
+	exchangeability_(14,18)=0.05826;
+	exchangeability_(18,14)=0.05826;
+	exchangeability_(6,18)=0.04761;
+	exchangeability_(18,6)=0.04761;
+	exchangeability_(5,16)=1.08318;
+	exchangeability_(16,5)=1.08318;
+	exchangeability_(5,15)=1.2674;
+	exchangeability_(15,5)=1.2674;
+}
+
+
+if (getName()=="Extended"){
+	exchangeability_(0,0)=-26.2139;
+	exchangeability_(4,4)=-21.7484;
+	exchangeability_(6,6)=-15.5039;
+	exchangeability_(3,3)=-18.6947;
+	exchangeability_(7,7)=-12.6806;
+	exchangeability_(13,13)=-18.3141;
+	exchangeability_(9,9)=-15.6947;
+	exchangeability_(8,8)=-24.9013;
+	exchangeability_(11,11)=-17.8548;
+	exchangeability_(12,12)=-22.7782;
+	exchangeability_(10,10)=-17.957;
+	exchangeability_(2,2)=-29.9408;
+	exchangeability_(5,5)=-25.0368;
+	exchangeability_(14,14)=-8.07245;
+	exchangeability_(15,15)=-33.4726;
+	exchangeability_(1,1)=-17.6212;
+	exchangeability_(16,16)=-19.712;
+	exchangeability_(17,17)=-8.76695;
+	exchangeability_(19,19)=-16.1653;
+	exchangeability_(18,18)=-18.7666;
+}
+
+
+if (getName()=="Other"){
+	exchangeability_(0,0)=-24.9024;
+	exchangeability_(4,4)=-29.1186;
+	exchangeability_(6,6)=-13.4366;
+	exchangeability_(3,3)=-12.4274;
+	exchangeability_(7,7)=-7.10993;
+	exchangeability_(13,13)=-38.2752;
+	exchangeability_(9,9)=-43.7457;
+	exchangeability_(8,8)=-28.629;
+	exchangeability_(11,11)=-17.9457;
+	exchangeability_(12,12)=-41.1811;
+	exchangeability_(10,10)=-36.1402;
+	exchangeability_(2,2)=-22.831;
+	exchangeability_(5,5)=-26.2396;
+	exchangeability_(14,14)=-5.8788;
+	exchangeability_(15,15)=-30.8495;
+	exchangeability_(1,1)=-19.1069;
+	exchangeability_(16,16)=-25.3189;
+	exchangeability_(17,17)=-15.4348;
+	exchangeability_(19,19)=-42.0036;
+	exchangeability_(18,18)=-37.2928;
+}
+
+
+if (getName()=="Helix"){
+	exchangeability_(0,0)=-24.6299;
+	exchangeability_(4,4)=-30.4886;
+	exchangeability_(6,6)=-10.8392;
+	exchangeability_(3,3)=-12.6642;
+	exchangeability_(7,7)=-18.4848;
+	exchangeability_(13,13)=-30.5979;
+	exchangeability_(9,9)=-30.379;
+	exchangeability_(8,8)=-29.042;
+	exchangeability_(11,11)=-13.6519;
+	exchangeability_(12,12)=-28.5507;
+	exchangeability_(10,10)=-22.9105;
+	exchangeability_(2,2)=-27.7295;
+	exchangeability_(5,5)=-19.3273;
+	exchangeability_(14,14)=-6.95685;
+	exchangeability_(15,15)=-41.478;
+	exchangeability_(1,1)=-13.8389;
+	exchangeability_(16,16)=-32.5118;
+	exchangeability_(17,17)=-13.4118;
+	exchangeability_(19,19)=-31.7082;
+	exchangeability_(18,18)=-32.7216;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_EHOFrequenciesCode b/src/Bpp/Phyl/Model/Protein/__LLG08_EHOFrequenciesCode
new file mode 100644
index 0000000..9ff251c
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_EHOFrequenciesCode
@@ -0,0 +1,72 @@
+if (getName()=="Other"){
+	freq_[0] = 0.076458;
+	freq_[4] = 0.007473;
+	freq_[6] = 0.080952;
+	freq_[3] = 0.088634;
+	freq_[7] = 0.100192;
+	freq_[13] = 0.023159;
+	freq_[9] = 0.03173;
+	freq_[8] = 0.025439;
+	freq_[11] = 0.070835;
+	freq_[12] = 0.014039;
+	freq_[10] = 0.0532;
+	freq_[2] = 0.055429;
+	freq_[5] = 0.040671;
+	freq_[14] = 0.087111;
+	freq_[15] = 0.063636;
+	freq_[1] = 0.052393;
+	freq_[16] = 0.055346;
+	freq_[17] = 0.007033;
+	freq_[19] = 0.04259;
+	freq_[18] = 0.023779;
+}
+
+
+if (getName()=="Extended"){
+	freq_[0] = 0.062087;
+	freq_[4] = 0.013132;
+	freq_[6] = 0.061043;
+	freq_[3] = 0.032063;
+	freq_[7] = 0.030664;
+	freq_[13] = 0.045996;
+	freq_[9] = 0.104732;
+	freq_[8] = 0.022696;
+	freq_[11] = 0.054991;
+	freq_[12] = 0.022312;
+	freq_[10] = 0.099541;
+	freq_[2] = 0.023743;
+	freq_[5] = 0.034151;
+	freq_[14] = 0.025392;
+	freq_[15] = 0.045673;
+	freq_[1] = 0.053435;
+	freq_[16] = 0.072789;
+	freq_[17] = 0.012691;
+	freq_[19] = 0.139079;
+	freq_[18] = 0.04379;
+}
+
+
+if (getName()=="Helix"){
+	freq_[0] = 0.121953;
+	freq_[4] = 0.006842;
+	freq_[6] = 0.131841;
+	freq_[3] = 0.066765;
+	freq_[7] = 0.026596;
+	freq_[13] = 0.024145;
+	freq_[9] = 0.047287;
+	freq_[8] = 0.020392;
+	freq_[11] = 0.084678;
+	freq_[12] = 0.02097;
+	freq_[10] = 0.087918;
+	freq_[2] = 0.032215;
+	freq_[5] = 0.061304;
+	freq_[14] = 0.025871;
+	freq_[15] = 0.042103;
+	freq_[1] = 0.076797;
+	freq_[16] = 0.038715;
+	freq_[17] = 0.008346;
+	freq_[19] = 0.051421;
+	freq_[18] = 0.023841;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_EHORatesProps b/src/Bpp/Phyl/Model/Protein/__LLG08_EHORatesProps
new file mode 100644
index 0000000..8b59f34
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_EHORatesProps
@@ -0,0 +1,18 @@
+if (getName()=="Other"){
+	rate_ = 0.9323975;
+	proportion_ = 0.4316;
+}
+
+
+if (getName()=="Extended"){
+	rate_ = 0.8575975;
+	proportion_ = 0.2078;
+}
+
+
+if (getName()=="Helix"){
+	rate_ = 1.162975;
+	proportion_ = 0.3606;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_EX2ExchangeabilityCode b/src/Bpp/Phyl/Model/Protein/__LLG08_EX2ExchangeabilityCode
new file mode 100644
index 0000000..1bbb094
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_EX2ExchangeabilityCode
@@ -0,0 +1,816 @@
+if (getName()=="Exposed"){
+	exchangeability_(10,17)=1.13072;
+	exchangeability_(17,10)=1.13072;
+	exchangeability_(6,11)=0.73034;
+	exchangeability_(11,6)=0.73034;
+	exchangeability_(4,7)=0.88656;
+	exchangeability_(7,4)=0.88656;
+	exchangeability_(17,19)=0.25213;
+	exchangeability_(19,17)=0.25213;
+	exchangeability_(9,19)=23.7112;
+	exchangeability_(19,9)=23.7112;
+	exchangeability_(5,6)=2.51438;
+	exchangeability_(6,5)=2.51438;
+	exchangeability_(1,6)=0.13793;
+	exchangeability_(6,1)=0.13793;
+	exchangeability_(0,12)=1.04394;
+	exchangeability_(12,0)=1.04394;
+	exchangeability_(1,2)=0.50584;
+	exchangeability_(2,1)=0.50584;
+	exchangeability_(11,16)=1.14746;
+	exchangeability_(16,11)=1.14746;
+	exchangeability_(1,17)=0.47559;
+	exchangeability_(17,1)=0.47559;
+	exchangeability_(8,15)=0.99331;
+	exchangeability_(15,8)=0.99331;
+	exchangeability_(13,17)=5.21;
+	exchangeability_(17,13)=5.21;
+	exchangeability_(10,16)=0.52233;
+	exchangeability_(16,10)=0.52233;
+	exchangeability_(13,15)=0.66883;
+	exchangeability_(15,13)=0.66883;
+	exchangeability_(9,18)=0.51712;
+	exchangeability_(18,9)=0.51712;
+	exchangeability_(2,18)=0.59937;
+	exchangeability_(18,2)=0.59937;
+	exchangeability_(7,9)=0.01228;
+	exchangeability_(9,7)=0.01228;
+	exchangeability_(3,5)=0.39906;
+	exchangeability_(5,3)=0.39906;
+	exchangeability_(3,13)=0.02692;
+	exchangeability_(13,3)=0.02692;
+	exchangeability_(0,10)=0.43051;
+	exchangeability_(10,0)=0.43051;
+	exchangeability_(9,11)=0.33878;
+	exchangeability_(11,9)=0.33878;
+	exchangeability_(8,14)=0.32314;
+	exchangeability_(14,8)=0.32314;
+	exchangeability_(2,8)=4.94931;
+	exchangeability_(8,2)=4.94931;
+	exchangeability_(4,6)=0.03395;
+	exchangeability_(6,4)=0.03395;
+	exchangeability_(8,13)=2.04716;
+	exchangeability_(13,8)=2.04716;
+	exchangeability_(5,7)=0.32075;
+	exchangeability_(7,5)=0.32075;
+	exchangeability_(1,7)=0.36337;
+	exchangeability_(7,1)=0.36337;
+	exchangeability_(4,15)=5.29415;
+	exchangeability_(15,4)=5.29415;
+	exchangeability_(1,14)=0.16653;
+	exchangeability_(14,1)=0.16653;
+	exchangeability_(1,18)=0.19627;
+	exchangeability_(18,1)=0.19627;
+	exchangeability_(11,18)=0.08496;
+	exchangeability_(18,11)=0.08496;
+	exchangeability_(0,5)=1.28;
+	exchangeability_(5,0)=1.28;
+	exchangeability_(2,9)=0.33723;
+	exchangeability_(9,2)=0.33723;
+	exchangeability_(7,18)=0.03928;
+	exchangeability_(18,7)=0.03928;
+	exchangeability_(7,14)=0.1489;
+	exchangeability_(14,7)=0.1489;
+	exchangeability_(3,19)=0.07371;
+	exchangeability_(19,3)=0.07371;
+	exchangeability_(5,13)=0.08019;
+	exchangeability_(13,5)=0.08019;
+	exchangeability_(15,19)=0.26653;
+	exchangeability_(19,15)=0.26653;
+	exchangeability_(11,17)=0.05286;
+	exchangeability_(17,11)=0.05286;
+	exchangeability_(7,13)=0.08466;
+	exchangeability_(13,7)=0.08466;
+	exchangeability_(0,2)=0.48315;
+	exchangeability_(2,0)=0.48315;
+	exchangeability_(9,12)=9.4835;
+	exchangeability_(12,9)=9.4835;
+	exchangeability_(3,12)=0.06693;
+	exchangeability_(12,3)=0.06693;
+	exchangeability_(8,19)=0.3299;
+	exchangeability_(19,8)=0.3299;
+	exchangeability_(0,14)=1.27069;
+	exchangeability_(14,0)=1.27069;
+	exchangeability_(5,17)=0.21033;
+	exchangeability_(17,5)=0.21033;
+	exchangeability_(4,10)=1.70207;
+	exchangeability_(10,4)=1.70207;
+	exchangeability_(10,15)=0.3891;
+	exchangeability_(15,10)=0.3891;
+	exchangeability_(14,17)=0.04594;
+	exchangeability_(17,14)=0.04594;
+	exchangeability_(16,18)=0.23422;
+	exchangeability_(18,16)=0.23422;
+	exchangeability_(1,9)=0.23702;
+	exchangeability_(9,1)=0.23702;
+	exchangeability_(4,5)=0.45652;
+	exchangeability_(5,4)=0.45652;
+	exchangeability_(9,10)=8.67534;
+	exchangeability_(10,9)=8.67534;
+	exchangeability_(11,14)=0.19547;
+	exchangeability_(14,11)=0.19547;
+	exchangeability_(8,17)=0.96155;
+	exchangeability_(17,8)=0.96155;
+	exchangeability_(0,15)=4.82667;
+	exchangeability_(15,0)=4.82667;
+	exchangeability_(2,11)=1.67719;
+	exchangeability_(11,2)=1.67719;
+	exchangeability_(10,14)=0.34392;
+	exchangeability_(14,10)=0.34392;
+	exchangeability_(13,16)=0.24442;
+	exchangeability_(16,13)=0.24442;
+	exchangeability_(7,19)=0.1325;
+	exchangeability_(19,7)=0.1325;
+	exchangeability_(3,16)=0.36889;
+	exchangeability_(16,3)=0.36889;
+	exchangeability_(7,12)=0.15814;
+	exchangeability_(12,7)=0.15814;
+	exchangeability_(15,16)=7.3847;
+	exchangeability_(16,15)=7.3847;
+	exchangeability_(14,15)=1.22398;
+	exchangeability_(15,14)=1.22398;
+	exchangeability_(3,11)=0.10545;
+	exchangeability_(11,3)=0.10545;
+	exchangeability_(6,7)=0.30397;
+	exchangeability_(7,6)=0.30397;
+	exchangeability_(8,16)=0.58096;
+	exchangeability_(16,8)=0.58096;
+	exchangeability_(0,1)=0.52674;
+	exchangeability_(1,0)=0.52674;
+	exchangeability_(5,9)=0.21203;
+	exchangeability_(9,5)=0.21203;
+	exchangeability_(12,18)=0.81214;
+	exchangeability_(18,12)=0.81214;
+	exchangeability_(6,16)=0.51139;
+	exchangeability_(16,6)=0.51139;
+	exchangeability_(1,11)=3.88108;
+	exchangeability_(11,1)=3.88108;
+	exchangeability_(2,14)=0.06869;
+	exchangeability_(14,2)=0.06869;
+	exchangeability_(0,4)=2.05187;
+	exchangeability_(4,0)=2.05187;
+	exchangeability_(1,16)=0.58433;
+	exchangeability_(16,1)=0.58433;
+	exchangeability_(6,13)=0.024;
+	exchangeability_(13,6)=0.024;
+	exchangeability_(18,19)=0.45919;
+	exchangeability_(19,18)=0.45919;
+	exchangeability_(5,8)=3.75542;
+	exchangeability_(8,5)=3.75542;
+	exchangeability_(16,19)=3.18487;
+	exchangeability_(19,16)=3.18487;
+	exchangeability_(7,16)=0.17453;
+	exchangeability_(16,7)=0.17453;
+	exchangeability_(8,11)=0.59829;
+	exchangeability_(11,8)=0.59829;
+	exchangeability_(3,17)=0.04262;
+	exchangeability_(17,3)=0.04262;
+	exchangeability_(6,17)=0.04828;
+	exchangeability_(17,6)=0.04828;
+	exchangeability_(2,3)=3.90246;
+	exchangeability_(3,2)=3.90246;
+	exchangeability_(3,9)=0.01831;
+	exchangeability_(9,3)=0.01831;
+	exchangeability_(0,16)=2.13182;
+	exchangeability_(16,0)=2.13182;
+	exchangeability_(5,11)=2.57025;
+	exchangeability_(11,5)=2.57025;
+	exchangeability_(4,8)=2.17228;
+	exchangeability_(8,4)=2.17228;
+	exchangeability_(16,17)=0.14439;
+	exchangeability_(17,16)=0.14439;
+	exchangeability_(5,19)=0.4974;
+	exchangeability_(19,5)=0.4974;
+	exchangeability_(1,3)=0.05105;
+	exchangeability_(3,1)=0.05105;
+	exchangeability_(4,19)=4.20765;
+	exchangeability_(19,4)=4.20765;
+	exchangeability_(6,19)=0.48462;
+	exchangeability_(19,6)=0.48462;
+	exchangeability_(1,12)=0.65694;
+	exchangeability_(12,1)=0.65694;
+	exchangeability_(0,6)=1.30657;
+	exchangeability_(6,0)=1.30657;
+	exchangeability_(2,6)=0.28581;
+	exchangeability_(6,2)=0.28581;
+	exchangeability_(1,19)=0.31344;
+	exchangeability_(19,1)=0.31344;
+	exchangeability_(0,17)=0.14308;
+	exchangeability_(17,0)=0.14308;
+	exchangeability_(2,17)=0.06109;
+	exchangeability_(17,2)=0.06109;
+	exchangeability_(7,15)=1.97086;
+	exchangeability_(15,7)=1.97086;
+	exchangeability_(3,14)=0.22883;
+	exchangeability_(14,3)=0.22883;
+	exchangeability_(8,9)=0.31724;
+	exchangeability_(9,8)=0.31724;
+	exchangeability_(3,18)=0.12131;
+	exchangeability_(18,3)=0.12131;
+	exchangeability_(0,3)=0.6589;
+	exchangeability_(3,0)=0.6589;
+	exchangeability_(2,13)=0.18252;
+	exchangeability_(13,2)=0.18252;
+	exchangeability_(0,19)=2.54446;
+	exchangeability_(19,0)=2.54446;
+	exchangeability_(5,12)=1.97359;
+	exchangeability_(12,5)=1.97359;
+	exchangeability_(4,13)=3.00259;
+	exchangeability_(13,4)=3.00259;
+	exchangeability_(10,12)=14.1769;
+	exchangeability_(12,10)=14.1769;
+	exchangeability_(5,18)=0.15847;
+	exchangeability_(18,5)=0.15847;
+	exchangeability_(14,16)=0.41315;
+	exchangeability_(16,14)=0.41315;
+	exchangeability_(1,13)=0.09744;
+	exchangeability_(13,1)=0.09744;
+	exchangeability_(4,16)=2.06739;
+	exchangeability_(16,4)=2.06739;
+	exchangeability_(6,14)=0.21485;
+	exchangeability_(14,6)=0.21485;
+	exchangeability_(11,15)=0.59216;
+	exchangeability_(15,11)=0.59216;
+	exchangeability_(0,7)=1.37078;
+	exchangeability_(7,0)=1.37078;
+	exchangeability_(2,7)=1.8201;
+	exchangeability_(7,2)=1.8201;
+	exchangeability_(8,18)=8.23028;
+	exchangeability_(18,8)=8.23028;
+	exchangeability_(5,10)=1.26111;
+	exchangeability_(10,5)=1.26111;
+	exchangeability_(15,18)=0.40531;
+	exchangeability_(18,15)=0.40531;
+	exchangeability_(12,16)=2.96009;
+	exchangeability_(16,12)=2.96009;
+	exchangeability_(5,14)=0.3625;
+	exchangeability_(14,5)=0.3625;
+	exchangeability_(7,8)=0.40131;
+	exchangeability_(8,7)=0.40131;
+	exchangeability_(15,17)=0.31608;
+	exchangeability_(17,15)=0.31608;
+	exchangeability_(3,7)=0.88532;
+	exchangeability_(7,3)=0.88532;
+	exchangeability_(6,15)=0.38223;
+	exchangeability_(15,6)=0.38223;
+	exchangeability_(12,13)=3.2614;
+	exchangeability_(13,12)=3.2614;
+	exchangeability_(13,14)=0.08702;
+	exchangeability_(14,13)=0.08702;
+	exchangeability_(3,10)=0.02195;
+	exchangeability_(10,3)=0.02195;
+	exchangeability_(0,13)=0.26521;
+	exchangeability_(13,0)=0.26521;
+	exchangeability_(6,12)=0.18816;
+	exchangeability_(12,6)=0.18816;
+	exchangeability_(4,12)=1.84656;
+	exchangeability_(12,4)=1.84656;
+	exchangeability_(9,14)=0.07199;
+	exchangeability_(14,9)=0.07199;
+	exchangeability_(10,11)=0.3131;
+	exchangeability_(11,10)=0.3131;
+	exchangeability_(12,17)=1.32878;
+	exchangeability_(17,12)=1.32878;
+	exchangeability_(2,19)=0.17226;
+	exchangeability_(19,2)=0.17226;
+	exchangeability_(8,10)=0.86925;
+	exchangeability_(10,8)=0.86925;
+	exchangeability_(1,8)=2.28892;
+	exchangeability_(8,1)=2.28892;
+	exchangeability_(1,5)=2.03955;
+	exchangeability_(5,1)=2.03955;
+	exchangeability_(2,5)=1.30179;
+	exchangeability_(5,2)=1.30179;
+	exchangeability_(0,18)=0.20864;
+	exchangeability_(18,0)=0.20864;
+	exchangeability_(13,18)=23.2289;
+	exchangeability_(18,13)=23.2289;
+	exchangeability_(6,10)=0.11051;
+	exchangeability_(10,6)=0.11051;
+	exchangeability_(9,15)=0.19051;
+	exchangeability_(15,9)=0.19051;
+	exchangeability_(2,15)=4.41226;
+	exchangeability_(15,2)=4.41226;
+	exchangeability_(7,17)=0.18638;
+	exchangeability_(17,7)=0.18638;
+	exchangeability_(2,16)=2.1336;
+	exchangeability_(16,2)=2.1336;
+	exchangeability_(12,19)=4.13644;
+	exchangeability_(19,12)=4.13644;
+	exchangeability_(8,12)=0.51999;
+	exchangeability_(12,8)=0.51999;
+	exchangeability_(3,6)=3.1004;
+	exchangeability_(6,3)=3.1004;
+	exchangeability_(4,11)=0.14626;
+	exchangeability_(11,4)=0.14626;
+	exchangeability_(4,18)=3.84263;
+	exchangeability_(18,4)=3.84263;
+	exchangeability_(0,9)=0.17199;
+	exchangeability_(9,0)=0.17199;
+	exchangeability_(4,14)=0.15622;
+	exchangeability_(14,4)=0.15622;
+	exchangeability_(1,15)=0.75195;
+	exchangeability_(15,1)=0.75195;
+	exchangeability_(2,4)=0.9611;
+	exchangeability_(4,2)=0.9611;
+	exchangeability_(11,13)=0.04479;
+	exchangeability_(13,11)=0.04479;
+	exchangeability_(11,12)=1.01327;
+	exchangeability_(12,11)=1.01327;
+	exchangeability_(10,13)=4.80282;
+	exchangeability_(13,10)=4.80282;
+	exchangeability_(12,14)=0.09925;
+	exchangeability_(14,12)=0.09925;
+	exchangeability_(7,10)=0.05295;
+	exchangeability_(10,7)=0.05295;
+	exchangeability_(0,8)=0.54081;
+	exchangeability_(8,0)=0.54081;
+	exchangeability_(3,4)=0.12999;
+	exchangeability_(4,3)=0.12999;
+	exchangeability_(3,8)=0.70089;
+	exchangeability_(8,3)=0.70089;
+	exchangeability_(2,10)=0.15894;
+	exchangeability_(10,2)=0.15894;
+	exchangeability_(17,18)=4.90389;
+	exchangeability_(18,17)=4.90389;
+	exchangeability_(10,18)=0.71343;
+	exchangeability_(18,10)=0.71343;
+	exchangeability_(6,9)=0.08444;
+	exchangeability_(9,6)=0.08444;
+	exchangeability_(4,9)=1.03705;
+	exchangeability_(9,4)=1.03705;
+	exchangeability_(14,19)=0.36823;
+	exchangeability_(19,14)=0.36823;
+	exchangeability_(9,16)=2.56363;
+	exchangeability_(16,9)=2.56363;
+	exchangeability_(12,15)=0.55725;
+	exchangeability_(15,12)=0.55725;
+	exchangeability_(1,4)=2.21433;
+	exchangeability_(4,1)=2.21433;
+	exchangeability_(4,17)=1.60312;
+	exchangeability_(17,4)=1.60312;
+	exchangeability_(0,11)=0.69773;
+	exchangeability_(11,0)=0.69773;
+	exchangeability_(9,13)=2.19306;
+	exchangeability_(13,9)=2.19306;
+	exchangeability_(1,10)=0.67051;
+	exchangeability_(10,1)=0.67051;
+	exchangeability_(11,19)=0.34836;
+	exchangeability_(19,11)=0.34836;
+	exchangeability_(2,12)=0.53983;
+	exchangeability_(12,2)=0.53983;
+	exchangeability_(10,19)=3.46699;
+	exchangeability_(19,10)=3.46699;
+	exchangeability_(6,8)=0.27096;
+	exchangeability_(8,6)=0.27096;
+	exchangeability_(9,17)=0.20831;
+	exchangeability_(17,9)=0.20831;
+	exchangeability_(7,11)=0.27986;
+	exchangeability_(11,7)=0.27986;
+	exchangeability_(3,15)=0.97556;
+	exchangeability_(15,3)=0.97556;
+	exchangeability_(13,19)=1.19976;
+	exchangeability_(19,13)=1.19976;
+	exchangeability_(14,18)=0.04325;
+	exchangeability_(18,14)=0.04325;
+	exchangeability_(6,18)=0.06465;
+	exchangeability_(18,6)=0.06465;
+	exchangeability_(5,16)=1.01361;
+	exchangeability_(16,5)=1.01361;
+	exchangeability_(5,15)=1.03346;
+	exchangeability_(15,5)=1.03346;
+}
+
+
+if (getName()=="Buried"){
+	exchangeability_(10,17)=0.37457;
+	exchangeability_(17,10)=0.37457;
+	exchangeability_(6,11)=3.48294;
+	exchangeability_(11,6)=3.48294;
+	exchangeability_(4,7)=0.70132;
+	exchangeability_(7,4)=0.70132;
+	exchangeability_(17,19)=0.08114;
+	exchangeability_(19,17)=0.08114;
+	exchangeability_(9,19)=6.42728;
+	exchangeability_(19,9)=6.42728;
+	exchangeability_(5,6)=8.67011;
+	exchangeability_(6,5)=8.67011;
+	exchangeability_(1,6)=0.91798;
+	exchangeability_(6,1)=0.91798;
+	exchangeability_(0,12)=0.49748;
+	exchangeability_(12,0)=0.49748;
+	exchangeability_(1,2)=0.98163;
+	exchangeability_(2,1)=0.98163;
+	exchangeability_(11,16)=1.40168;
+	exchangeability_(16,11)=1.40168;
+	exchangeability_(1,17)=0.78445;
+	exchangeability_(17,1)=0.78445;
+	exchangeability_(8,15)=0.88613;
+	exchangeability_(15,8)=0.88613;
+	exchangeability_(13,17)=2.363;
+	exchangeability_(17,13)=2.363;
+	exchangeability_(10,16)=0.20281;
+	exchangeability_(16,10)=0.20281;
+	exchangeability_(13,15)=0.27458;
+	exchangeability_(15,13)=0.27458;
+	exchangeability_(9,18)=0.1018;
+	exchangeability_(18,9)=0.1018;
+	exchangeability_(2,18)=0.61509;
+	exchangeability_(18,2)=0.61509;
+	exchangeability_(7,9)=0.00502;
+	exchangeability_(9,7)=0.00502;
+	exchangeability_(3,5)=0.68205;
+	exchangeability_(5,3)=0.68205;
+	exchangeability_(3,13)=0.02616;
+	exchangeability_(13,3)=0.02616;
+	exchangeability_(0,10)=0.12405;
+	exchangeability_(10,0)=0.12405;
+	exchangeability_(9,11)=0.16166;
+	exchangeability_(11,9)=0.16166;
+	exchangeability_(8,14)=0.42821;
+	exchangeability_(14,8)=0.42821;
+	exchangeability_(2,8)=6.30804;
+	exchangeability_(8,2)=6.30804;
+	exchangeability_(4,6)=0.02406;
+	exchangeability_(6,4)=0.02406;
+	exchangeability_(8,13)=0.67565;
+	exchangeability_(13,8)=0.67565;
+	exchangeability_(5,7)=0.33014;
+	exchangeability_(7,5)=0.33014;
+	exchangeability_(1,7)=0.53925;
+	exchangeability_(7,1)=0.53925;
+	exchangeability_(4,15)=5.11199;
+	exchangeability_(15,4)=5.11199;
+	exchangeability_(1,14)=0.35642;
+	exchangeability_(14,1)=0.35642;
+	exchangeability_(1,18)=0.31204;
+	exchangeability_(18,1)=0.31204;
+	exchangeability_(11,18)=0.28074;
+	exchangeability_(18,11)=0.28074;
+	exchangeability_(0,5)=0.54314;
+	exchangeability_(5,0)=0.54314;
+	exchangeability_(2,9)=0.16264;
+	exchangeability_(9,2)=0.16264;
+	exchangeability_(7,18)=0.0355;
+	exchangeability_(18,7)=0.0355;
+	exchangeability_(7,14)=0.17909;
+	exchangeability_(14,7)=0.17909;
+	exchangeability_(3,19)=0.05864;
+	exchangeability_(19,3)=0.05864;
+	exchangeability_(5,13)=0.09195;
+	exchangeability_(13,5)=0.09195;
+	exchangeability_(15,19)=0.07988;
+	exchangeability_(19,15)=0.07988;
+	exchangeability_(11,17)=0.11578;
+	exchangeability_(17,11)=0.11578;
+	exchangeability_(7,13)=0.03443;
+	exchangeability_(13,7)=0.03443;
+	exchangeability_(0,2)=0.20133;
+	exchangeability_(2,0)=0.20133;
+	exchangeability_(9,12)=2.81717;
+	exchangeability_(12,9)=2.81717;
+	exchangeability_(3,12)=0.05718;
+	exchangeability_(12,3)=0.05718;
+	exchangeability_(8,19)=0.08523;
+	exchangeability_(19,8)=0.08523;
+	exchangeability_(0,14)=0.98662;
+	exchangeability_(14,0)=0.98662;
+	exchangeability_(5,17)=0.29773;
+	exchangeability_(17,5)=0.29773;
+	exchangeability_(4,10)=0.44924;
+	exchangeability_(10,4)=0.44924;
+	exchangeability_(10,15)=0.08961;
+	exchangeability_(15,10)=0.08961;
+	exchangeability_(14,17)=0.04713;
+	exchangeability_(17,14)=0.04713;
+	exchangeability_(16,18)=0.13305;
+	exchangeability_(18,16)=0.13305;
+	exchangeability_(1,9)=0.09924;
+	exchangeability_(9,1)=0.09924;
+	exchangeability_(4,5)=0.21679;
+	exchangeability_(5,4)=0.21679;
+	exchangeability_(9,10)=2.38376;
+	exchangeability_(10,9)=2.38376;
+	exchangeability_(11,14)=0.34722;
+	exchangeability_(14,11)=0.34722;
+	exchangeability_(8,17)=0.70874;
+	exchangeability_(17,8)=0.70874;
+	exchangeability_(0,15)=5.92559;
+	exchangeability_(15,0)=5.92559;
+	exchangeability_(2,11)=2.85191;
+	exchangeability_(11,2)=2.85191;
+	exchangeability_(10,14)=0.17078;
+	exchangeability_(14,10)=0.17078;
+	exchangeability_(13,16)=0.10312;
+	exchangeability_(16,13)=0.10312;
+	exchangeability_(7,19)=0.04401;
+	exchangeability_(19,7)=0.04401;
+	exchangeability_(3,16)=0.28964;
+	exchangeability_(16,3)=0.28964;
+	exchangeability_(7,12)=0.05449;
+	exchangeability_(12,7)=0.05449;
+	exchangeability_(15,16)=8.19053;
+	exchangeability_(16,15)=8.19053;
+	exchangeability_(14,15)=1.15111;
+	exchangeability_(15,14)=1.15111;
+	exchangeability_(3,11)=0.45994;
+	exchangeability_(11,3)=0.45994;
+	exchangeability_(6,7)=0.63667;
+	exchangeability_(7,6)=0.63667;
+	exchangeability_(8,16)=0.46749;
+	exchangeability_(16,8)=0.46749;
+	exchangeability_(0,1)=0.33865;
+	exchangeability_(1,0)=0.33865;
+	exchangeability_(5,9)=0.08274;
+	exchangeability_(9,5)=0.08274;
+	exchangeability_(12,18)=0.26454;
+	exchangeability_(18,12)=0.26454;
+	exchangeability_(6,16)=0.53989;
+	exchangeability_(16,6)=0.53989;
+	exchangeability_(1,11)=17.7818;
+	exchangeability_(11,1)=17.7818;
+	exchangeability_(2,14)=0.21452;
+	exchangeability_(14,2)=0.21452;
+	exchangeability_(0,4)=2.64024;
+	exchangeability_(4,0)=2.64024;
+	exchangeability_(1,16)=0.63071;
+	exchangeability_(16,1)=0.63071;
+	exchangeability_(6,13)=0.02276;
+	exchangeability_(13,6)=0.02276;
+	exchangeability_(18,19)=0.10838;
+	exchangeability_(19,18)=0.10838;
+	exchangeability_(5,8)=8.67549;
+	exchangeability_(8,5)=8.67549;
+	exchangeability_(16,19)=1.59256;
+	exchangeability_(19,16)=1.59256;
+	exchangeability_(7,16)=0.09743;
+	exchangeability_(16,7)=0.09743;
+	exchangeability_(8,11)=1.24789;
+	exchangeability_(11,8)=1.24789;
+	exchangeability_(3,17)=0.08581;
+	exchangeability_(17,3)=0.08581;
+	exchangeability_(6,17)=0.15588;
+	exchangeability_(17,6)=0.15588;
+	exchangeability_(2,3)=6.50518;
+	exchangeability_(3,2)=6.50518;
+	exchangeability_(3,9)=0.02082;
+	exchangeability_(9,3)=0.02082;
+	exchangeability_(0,16)=1.9585;
+	exchangeability_(16,0)=1.9585;
+	exchangeability_(5,11)=6.81541;
+	exchangeability_(11,5)=6.81541;
+	exchangeability_(4,8)=0.46988;
+	exchangeability_(8,4)=0.46988;
+	exchangeability_(16,17)=0.09705;
+	exchangeability_(17,16)=0.09705;
+	exchangeability_(5,19)=0.20395;
+	exchangeability_(19,5)=0.20395;
+	exchangeability_(1,3)=0.24754;
+	exchangeability_(3,1)=0.24754;
+	exchangeability_(4,19)=1.57506;
+	exchangeability_(19,4)=1.57506;
+	exchangeability_(6,19)=0.23941;
+	exchangeability_(19,6)=0.23941;
+	exchangeability_(1,12)=0.44877;
+	exchangeability_(12,1)=0.44877;
+	exchangeability_(0,6)=0.74848;
+	exchangeability_(6,0)=0.74848;
+	exchangeability_(2,6)=0.80476;
+	exchangeability_(6,2)=0.80476;
+	exchangeability_(1,19)=0.14009;
+	exchangeability_(19,1)=0.14009;
+	exchangeability_(0,17)=0.06836;
+	exchangeability_(17,0)=0.06836;
+	exchangeability_(2,17)=0.10907;
+	exchangeability_(17,2)=0.10907;
+	exchangeability_(7,15)=2.27947;
+	exchangeability_(15,7)=2.27947;
+	exchangeability_(3,14)=0.24613;
+	exchangeability_(14,3)=0.24613;
+	exchangeability_(8,9)=0.07582;
+	exchangeability_(9,8)=0.07582;
+	exchangeability_(3,18)=0.20261;
+	exchangeability_(18,3)=0.20261;
+	exchangeability_(0,3)=0.28386;
+	exchangeability_(3,0)=0.28386;
+	exchangeability_(2,13)=0.09894;
+	exchangeability_(13,2)=0.09894;
+	exchangeability_(0,19)=1.38775;
+	exchangeability_(19,0)=1.38775;
+	exchangeability_(5,12)=2.08941;
+	exchangeability_(12,5)=2.08941;
+	exchangeability_(4,13)=0.66252;
+	exchangeability_(13,4)=0.66252;
+	exchangeability_(10,12)=4.75968;
+	exchangeability_(12,10)=4.75968;
+	exchangeability_(5,18)=0.29354;
+	exchangeability_(18,5)=0.29354;
+	exchangeability_(14,16)=0.60128;
+	exchangeability_(16,14)=0.60128;
+	exchangeability_(1,13)=0.05553;
+	exchangeability_(13,1)=0.05553;
+	exchangeability_(4,16)=2.28414;
+	exchangeability_(16,4)=2.28414;
+	exchangeability_(6,14)=0.29508;
+	exchangeability_(14,6)=0.29508;
+	exchangeability_(11,15)=0.92535;
+	exchangeability_(15,11)=0.92535;
+	exchangeability_(0,7)=2.70046;
+	exchangeability_(7,0)=2.70046;
+	exchangeability_(2,7)=0.81074;
+	exchangeability_(7,2)=0.81074;
+	exchangeability_(8,18)=4.93833;
+	exchangeability_(18,8)=4.93833;
+	exchangeability_(5,10)=0.64178;
+	exchangeability_(10,5)=0.64178;
+	exchangeability_(15,18)=0.2644;
+	exchangeability_(18,15)=0.2644;
+	exchangeability_(12,16)=1.34073;
+	exchangeability_(16,12)=1.34073;
+	exchangeability_(5,14)=0.65404;
+	exchangeability_(14,5)=0.65404;
+	exchangeability_(7,8)=0.18374;
+	exchangeability_(8,7)=0.18374;
+	exchangeability_(15,17)=0.20908;
+	exchangeability_(17,15)=0.20908;
+	exchangeability_(3,7)=0.81073;
+	exchangeability_(7,3)=0.81073;
+	exchangeability_(6,15)=0.73746;
+	exchangeability_(15,6)=0.73746;
+	exchangeability_(12,13)=1.29687;
+	exchangeability_(13,12)=1.29687;
+	exchangeability_(13,14)=0.05723;
+	exchangeability_(14,13)=0.05723;
+	exchangeability_(3,10)=0.01753;
+	exchangeability_(10,3)=0.01753;
+	exchangeability_(0,13)=0.09399;
+	exchangeability_(13,0)=0.09399;
+	exchangeability_(6,12)=0.29138;
+	exchangeability_(12,6)=0.29138;
+	exchangeability_(4,12)=0.816;
+	exchangeability_(12,4)=0.816;
+	exchangeability_(9,14)=0.03767;
+	exchangeability_(14,9)=0.03767;
+	exchangeability_(10,11)=0.21976;
+	exchangeability_(11,10)=0.21976;
+	exchangeability_(12,17)=0.4775;
+	exchangeability_(17,12)=0.4775;
+	exchangeability_(2,19)=0.11218;
+	exchangeability_(19,2)=0.11218;
+	exchangeability_(8,10)=0.27702;
+	exchangeability_(10,8)=0.27702;
+	exchangeability_(1,8)=3.17522;
+	exchangeability_(8,1)=3.17522;
+	exchangeability_(1,5)=4.57031;
+	exchangeability_(5,1)=4.57031;
+	exchangeability_(2,5)=2.43964;
+	exchangeability_(5,2)=2.43964;
+	exchangeability_(0,18)=0.08477;
+	exchangeability_(18,0)=0.08477;
+	exchangeability_(13,18)=8.14291;
+	exchangeability_(18,13)=8.14291;
+	exchangeability_(6,10)=0.07339;
+	exchangeability_(10,6)=0.07339;
+	exchangeability_(9,15)=0.05106;
+	exchangeability_(15,9)=0.05106;
+	exchangeability_(2,15)=4.72542;
+	exchangeability_(15,2)=4.72542;
+	exchangeability_(7,17)=0.15742;
+	exchangeability_(17,7)=0.15742;
+	exchangeability_(2,16)=2.00759;
+	exchangeability_(16,2)=2.00759;
+	exchangeability_(12,19)=1.03358;
+	exchangeability_(19,12)=1.03358;
+	exchangeability_(8,12)=0.30745;
+	exchangeability_(12,8)=0.30745;
+	exchangeability_(3,6)=10.0303;
+	exchangeability_(6,3)=10.0303;
+	exchangeability_(4,11)=0.11755;
+	exchangeability_(11,4)=0.11755;
+	exchangeability_(4,18)=0.78816;
+	exchangeability_(18,4)=0.78816;
+	exchangeability_(0,9)=0.04421;
+	exchangeability_(9,0)=0.04421;
+	exchangeability_(4,14)=0.16423;
+	exchangeability_(14,4)=0.16423;
+	exchangeability_(1,15)=0.97999;
+	exchangeability_(15,1)=0.97999;
+	exchangeability_(2,4)=1.35332;
+	exchangeability_(4,2)=1.35332;
+	exchangeability_(11,13)=0.07792;
+	exchangeability_(13,11)=0.07792;
+	exchangeability_(11,12)=1.0824;
+	exchangeability_(12,11)=1.0824;
+	exchangeability_(10,13)=1.67237;
+	exchangeability_(13,10)=1.67237;
+	exchangeability_(12,14)=0.07409;
+	exchangeability_(14,12)=0.07409;
+	exchangeability_(7,10)=0.01775;
+	exchangeability_(10,7)=0.01775;
+	exchangeability_(0,8)=0.23769;
+	exchangeability_(8,0)=0.23769;
+	exchangeability_(3,4)=0.312;
+	exchangeability_(4,3)=0.312;
+	exchangeability_(3,8)=1.54;
+	exchangeability_(8,3)=1.54;
+	exchangeability_(2,10)=0.08824;
+	exchangeability_(10,2)=0.08824;
+	exchangeability_(17,18)=2.90567;
+	exchangeability_(18,17)=2.90567;
+	exchangeability_(10,18)=0.18009;
+	exchangeability_(18,10)=0.18009;
+	exchangeability_(6,9)=0.03058;
+	exchangeability_(9,6)=0.03058;
+	exchangeability_(4,9)=0.16699;
+	exchangeability_(9,4)=0.16699;
+	exchangeability_(14,19)=0.21348;
+	exchangeability_(19,14)=0.21348;
+	exchangeability_(9,16)=0.64404;
+	exchangeability_(16,9)=0.64404;
+	exchangeability_(12,15)=0.27537;
+	exchangeability_(15,12)=0.27537;
+	exchangeability_(1,4)=0.90473;
+	exchangeability_(4,1)=0.90473;
+	exchangeability_(4,17)=0.45788;
+	exchangeability_(17,4)=0.45788;
+	exchangeability_(0,11)=0.43372;
+	exchangeability_(11,0)=0.43372;
+	exchangeability_(9,13)=0.52142;
+	exchangeability_(13,9)=0.52142;
+	exchangeability_(1,10)=0.31416;
+	exchangeability_(10,1)=0.31416;
+	exchangeability_(11,19)=0.24434;
+	exchangeability_(19,11)=0.24434;
+	exchangeability_(2,12)=0.38096;
+	exchangeability_(12,2)=0.38096;
+	exchangeability_(10,19)=1.03594;
+	exchangeability_(19,10)=1.03594;
+	exchangeability_(6,8)=0.75068;
+	exchangeability_(8,6)=0.75068;
+	exchangeability_(9,17)=0.05413;
+	exchangeability_(17,9)=0.05413;
+	exchangeability_(7,11)=0.48465;
+	exchangeability_(11,7)=0.48465;
+	exchangeability_(3,15)=1.15899;
+	exchangeability_(15,3)=1.15899;
+	exchangeability_(13,19)=0.27801;
+	exchangeability_(19,13)=0.27801;
+	exchangeability_(14,18)=0.05931;
+	exchangeability_(18,14)=0.05931;
+	exchangeability_(6,18)=0.13731;
+	exchangeability_(18,6)=0.13731;
+	exchangeability_(5,16)=0.78782;
+	exchangeability_(16,5)=0.78782;
+	exchangeability_(5,15)=1.12093;
+	exchangeability_(15,5)=1.12093;
+}
+
+
+if (getName()=="Exposed"){
+	exchangeability_(0,0)=-21.9536;
+	exchangeability_(4,4)=-33.8123;
+	exchangeability_(6,6)=-10.7974;
+	exchangeability_(3,3)=-11.8785;
+	exchangeability_(7,7)=-9.5925;
+	exchangeability_(13,13)=-46.7517;
+	exchangeability_(9,9)=-50.381;
+	exchangeability_(8,8)=-30.851;
+	exchangeability_(11,11)=-14.8177;
+	exchangeability_(12,12)=-44.8231;
+	exchangeability_(10,10)=-39.8124;
+	exchangeability_(2,2)=-24.5525;
+	exchangeability_(5,5)=-21.4404;
+	exchangeability_(14,14)=-5.83255;
+	exchangeability_(15,15)=-32.6349;
+	exchangeability_(1,1)=-16.1588;
+	exchangeability_(16,16)=-28.3658;
+	exchangeability_(17,17)=-17.3251;
+	exchangeability_(19,19)=-46.1496;
+	exchangeability_(18,18)=-44.8633;
+}
+
+
+if (getName()=="Buried"){
+	exchangeability_(0,0)=-19.2989;
+	exchangeability_(4,4)=-19.2161;
+	exchangeability_(6,6)=-28.5891;
+	exchangeability_(3,3)=-23.0351;
+	exchangeability_(7,7)=-10.1023;
+	exchangeability_(13,13)=-16.5494;
+	exchangeability_(9,9)=-13.8881;
+	exchangeability_(8,8)=-31.4387;
+	exchangeability_(11,11)=-38.5327;
+	exchangeability_(12,12)=-18.3651;
+	exchangeability_(10,10)=-13.0925;
+	exchangeability_(2,2)=-30.7712;
+	exchangeability_(5,5)=-39.207;
+	exchangeability_(14,14)=-6.28364;
+	exchangeability_(15,15)=-34.4369;
+	exchangeability_(1,1)=-33.5785;
+	exchangeability_(16,16)=-23.3701;
+	exchangeability_(17,17)=-9.55039;
+	exchangeability_(19,19)=-14.9409;
+	exchangeability_(18,18)=-19.8482;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_EX2FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__LLG08_EX2FrequenciesCode
new file mode 100644
index 0000000..ecaa422
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_EX2FrequenciesCode
@@ -0,0 +1,48 @@
+if (getName()=="Exposed"){
+	freq_[0] = 0.088367;
+	freq_[4] = 0.004517;
+	freq_[6] = 0.128039;
+	freq_[3] = 0.087976;
+	freq_[7] = 0.056993;
+	freq_[13] = 0.016158;
+	freq_[9] = 0.025277;
+	freq_[8] = 0.024856;
+	freq_[11] = 0.094638;
+	freq_[12] = 0.012338;
+	freq_[10] = 0.045202;
+	freq_[2] = 0.047163;
+	freq_[5] = 0.058526;
+	freq_[14] = 0.060124;
+	freq_[15] = 0.055346;
+	freq_[1] = 0.078147;
+	freq_[16] = 0.05129;
+	freq_[17] = 0.006771;
+	freq_[19] = 0.036718;
+	freq_[18] = 0.021554;
+}
+
+
+if (getName()=="Buried"){
+	freq_[0] = 0.123119;
+	freq_[4] = 0.018712;
+	freq_[6] = 0.018723;
+	freq_[3] = 0.018583;
+	freq_[7] = 0.050388;
+	freq_[13] = 0.057019;
+	freq_[9] = 0.119697;
+	freq_[8] = 0.016402;
+	freq_[11] = 0.012776;
+	freq_[12] = 0.035838;
+	freq_[10] = 0.161398;
+	freq_[2] = 0.019852;
+	freq_[5] = 0.017275;
+	freq_[14] = 0.030913;
+	freq_[15] = 0.043472;
+	freq_[1] = 0.019475;
+	freq_[16] = 0.049935;
+	freq_[17] = 0.0126;
+	freq_[19] = 0.133894;
+	freq_[18] = 0.039929;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_EX2RatesProps b/src/Bpp/Phyl/Model/Protein/__LLG08_EX2RatesProps
new file mode 100644
index 0000000..102e03a
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_EX2RatesProps
@@ -0,0 +1,12 @@
+if (getName()=="Buried"){
+	rate_ = 0.556689;
+	proportion_ = 0.448;
+}
+
+
+if (getName()=="Exposed"){
+	rate_ = 1.359789;
+	proportion_ = 0.552;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_EX3ExchangeabilityCode b/src/Bpp/Phyl/Model/Protein/__LLG08_EX3ExchangeabilityCode
new file mode 100644
index 0000000..9997e85
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_EX3ExchangeabilityCode
@@ -0,0 +1,1224 @@
+if (getName()=="Buried"){
+	exchangeability_(10,17)=0.37729;
+	exchangeability_(17,10)=0.37729;
+	exchangeability_(6,11)=4.17612;
+	exchangeability_(11,6)=4.17612;
+	exchangeability_(4,7)=0.70721;
+	exchangeability_(7,4)=0.70721;
+	exchangeability_(17,19)=0.07836;
+	exchangeability_(19,17)=0.07836;
+	exchangeability_(9,19)=5.97331;
+	exchangeability_(19,9)=5.97331;
+	exchangeability_(5,6)=10.1234;
+	exchangeability_(6,5)=10.1234;
+	exchangeability_(1,6)=1.09082;
+	exchangeability_(6,1)=1.09082;
+	exchangeability_(0,12)=0.46057;
+	exchangeability_(12,0)=0.46057;
+	exchangeability_(1,2)=1.08742;
+	exchangeability_(2,1)=1.08742;
+	exchangeability_(11,16)=1.40726;
+	exchangeability_(16,11)=1.40726;
+	exchangeability_(1,17)=0.85533;
+	exchangeability_(17,1)=0.85533;
+	exchangeability_(8,15)=0.92439;
+	exchangeability_(15,8)=0.92439;
+	exchangeability_(13,17)=2.3436;
+	exchangeability_(17,13)=2.3436;
+	exchangeability_(10,16)=0.19892;
+	exchangeability_(16,10)=0.19892;
+	exchangeability_(13,15)=0.26062;
+	exchangeability_(15,13)=0.26062;
+	exchangeability_(9,18)=0.09208;
+	exchangeability_(18,9)=0.09208;
+	exchangeability_(2,18)=0.65574;
+	exchangeability_(18,2)=0.65574;
+	exchangeability_(7,9)=0.00452;
+	exchangeability_(9,7)=0.00452;
+	exchangeability_(3,5)=0.77324;
+	exchangeability_(5,3)=0.77324;
+	exchangeability_(3,13)=0.02791;
+	exchangeability_(13,3)=0.02791;
+	exchangeability_(0,10)=0.11985;
+	exchangeability_(10,0)=0.11985;
+	exchangeability_(9,11)=0.16328;
+	exchangeability_(11,9)=0.16328;
+	exchangeability_(8,14)=0.4832;
+	exchangeability_(14,8)=0.4832;
+	exchangeability_(2,8)=7.10838;
+	exchangeability_(8,2)=7.10838;
+	exchangeability_(4,6)=0.02102;
+	exchangeability_(6,4)=0.02102;
+	exchangeability_(8,13)=0.69115;
+	exchangeability_(13,8)=0.69115;
+	exchangeability_(5,7)=0.35186;
+	exchangeability_(7,5)=0.35186;
+	exchangeability_(1,7)=0.59501;
+	exchangeability_(7,1)=0.59501;
+	exchangeability_(4,15)=5.23601;
+	exchangeability_(15,4)=5.23601;
+	exchangeability_(1,14)=0.4199;
+	exchangeability_(14,1)=0.4199;
+	exchangeability_(1,18)=0.34149;
+	exchangeability_(18,1)=0.34149;
+	exchangeability_(11,18)=0.31113;
+	exchangeability_(18,11)=0.31113;
+	exchangeability_(0,5)=0.51061;
+	exchangeability_(5,0)=0.51061;
+	exchangeability_(2,9)=0.16874;
+	exchangeability_(9,2)=0.16874;
+	exchangeability_(7,18)=0.04026;
+	exchangeability_(18,7)=0.04026;
+	exchangeability_(7,14)=0.19245;
+	exchangeability_(14,7)=0.19245;
+	exchangeability_(3,19)=0.06285;
+	exchangeability_(19,3)=0.06285;
+	exchangeability_(5,13)=0.09486;
+	exchangeability_(13,5)=0.09486;
+	exchangeability_(15,19)=0.08345;
+	exchangeability_(19,15)=0.08345;
+	exchangeability_(11,17)=0.13795;
+	exchangeability_(17,11)=0.13795;
+	exchangeability_(7,13)=0.03403;
+	exchangeability_(13,7)=0.03403;
+	exchangeability_(0,2)=0.217;
+	exchangeability_(2,0)=0.217;
+	exchangeability_(9,12)=2.60947;
+	exchangeability_(12,9)=2.60947;
+	exchangeability_(3,12)=0.05915;
+	exchangeability_(12,3)=0.05915;
+	exchangeability_(8,19)=0.09057;
+	exchangeability_(19,8)=0.09057;
+	exchangeability_(0,14)=0.99337;
+	exchangeability_(14,0)=0.99337;
+	exchangeability_(5,17)=0.32937;
+	exchangeability_(17,5)=0.32937;
+	exchangeability_(4,10)=0.42268;
+	exchangeability_(10,4)=0.42268;
+	exchangeability_(10,15)=0.08425;
+	exchangeability_(15,10)=0.08425;
+	exchangeability_(14,17)=0.05865;
+	exchangeability_(17,14)=0.05865;
+	exchangeability_(16,18)=0.12804;
+	exchangeability_(18,16)=0.12804;
+	exchangeability_(1,9)=0.10294;
+	exchangeability_(9,1)=0.10294;
+	exchangeability_(4,5)=0.22022;
+	exchangeability_(5,4)=0.22022;
+	exchangeability_(9,10)=2.22536;
+	exchangeability_(10,9)=2.22536;
+	exchangeability_(11,14)=0.377;
+	exchangeability_(14,11)=0.377;
+	exchangeability_(8,17)=0.74587;
+	exchangeability_(17,8)=0.74587;
+	exchangeability_(0,15)=6.10841;
+	exchangeability_(15,0)=6.10841;
+	exchangeability_(2,11)=3.19482;
+	exchangeability_(11,2)=3.19482;
+	exchangeability_(10,14)=0.1704;
+	exchangeability_(14,10)=0.1704;
+	exchangeability_(13,16)=0.09695;
+	exchangeability_(16,13)=0.09695;
+	exchangeability_(7,19)=0.04366;
+	exchangeability_(19,7)=0.04366;
+	exchangeability_(3,16)=0.3123;
+	exchangeability_(16,3)=0.3123;
+	exchangeability_(7,12)=0.05319;
+	exchangeability_(12,7)=0.05319;
+	exchangeability_(15,16)=8.52725;
+	exchangeability_(16,15)=8.52725;
+	exchangeability_(14,15)=1.20845;
+	exchangeability_(15,14)=1.20845;
+	exchangeability_(3,11)=0.56814;
+	exchangeability_(11,3)=0.56814;
+	exchangeability_(6,7)=0.71397;
+	exchangeability_(7,6)=0.71397;
+	exchangeability_(8,16)=0.481;
+	exchangeability_(16,8)=0.481;
+	exchangeability_(0,1)=0.3526;
+	exchangeability_(1,0)=0.3526;
+	exchangeability_(5,9)=0.08788;
+	exchangeability_(9,5)=0.08788;
+	exchangeability_(12,18)=0.24984;
+	exchangeability_(18,12)=0.24984;
+	exchangeability_(6,16)=0.5514;
+	exchangeability_(16,6)=0.5514;
+	exchangeability_(1,11)=20.7669;
+	exchangeability_(11,1)=20.7669;
+	exchangeability_(2,14)=0.21711;
+	exchangeability_(14,2)=0.21711;
+	exchangeability_(0,4)=2.61081;
+	exchangeability_(4,0)=2.61081;
+	exchangeability_(1,16)=0.68726;
+	exchangeability_(16,1)=0.68726;
+	exchangeability_(6,13)=0.02328;
+	exchangeability_(13,6)=0.02328;
+	exchangeability_(18,19)=0.10529;
+	exchangeability_(19,18)=0.10529;
+	exchangeability_(5,8)=10.2465;
+	exchangeability_(8,5)=10.2465;
+	exchangeability_(16,19)=1.54491;
+	exchangeability_(19,16)=1.54491;
+	exchangeability_(7,16)=0.10141;
+	exchangeability_(16,7)=0.10141;
+	exchangeability_(8,11)=1.41539;
+	exchangeability_(11,8)=1.41539;
+	exchangeability_(3,17)=0.09977;
+	exchangeability_(17,3)=0.09977;
+	exchangeability_(6,17)=0.13673;
+	exchangeability_(17,6)=0.13673;
+	exchangeability_(2,3)=7.79709;
+	exchangeability_(3,2)=7.79709;
+	exchangeability_(3,9)=0.02421;
+	exchangeability_(9,3)=0.02421;
+	exchangeability_(0,16)=1.99285;
+	exchangeability_(16,0)=1.99285;
+	exchangeability_(5,11)=7.47895;
+	exchangeability_(11,5)=7.47895;
+	exchangeability_(4,8)=0.48111;
+	exchangeability_(8,4)=0.48111;
+	exchangeability_(16,17)=0.08595;
+	exchangeability_(17,16)=0.08595;
+	exchangeability_(5,19)=0.19408;
+	exchangeability_(19,5)=0.19408;
+	exchangeability_(1,3)=0.32346;
+	exchangeability_(3,1)=0.32346;
+	exchangeability_(4,19)=1.48108;
+	exchangeability_(19,4)=1.48108;
+	exchangeability_(6,19)=0.22539;
+	exchangeability_(19,6)=0.22539;
+	exchangeability_(1,12)=0.45821;
+	exchangeability_(12,1)=0.45821;
+	exchangeability_(0,6)=0.75373;
+	exchangeability_(6,0)=0.75373;
+	exchangeability_(2,6)=0.95682;
+	exchangeability_(6,2)=0.95682;
+	exchangeability_(1,19)=0.14492;
+	exchangeability_(19,1)=0.14492;
+	exchangeability_(0,17)=0.06316;
+	exchangeability_(17,0)=0.06316;
+	exchangeability_(2,17)=0.13401;
+	exchangeability_(17,2)=0.13401;
+	exchangeability_(7,15)=2.40407;
+	exchangeability_(15,7)=2.40407;
+	exchangeability_(3,14)=0.27353;
+	exchangeability_(14,3)=0.27353;
+	exchangeability_(8,9)=0.07998;
+	exchangeability_(9,8)=0.07998;
+	exchangeability_(3,18)=0.24126;
+	exchangeability_(18,3)=0.24126;
+	exchangeability_(0,3)=0.29244;
+	exchangeability_(3,0)=0.29244;
+	exchangeability_(2,13)=0.10472;
+	exchangeability_(13,2)=0.10472;
+	exchangeability_(0,19)=1.33972;
+	exchangeability_(19,0)=1.33972;
+	exchangeability_(5,12)=2.13426;
+	exchangeability_(12,5)=2.13426;
+	exchangeability_(4,13)=0.63009;
+	exchangeability_(13,4)=0.63009;
+	exchangeability_(10,12)=4.47696;
+	exchangeability_(12,10)=4.47696;
+	exchangeability_(5,18)=0.3021;
+	exchangeability_(18,5)=0.3021;
+	exchangeability_(14,16)=0.64825;
+	exchangeability_(16,14)=0.64825;
+	exchangeability_(1,13)=0.0567;
+	exchangeability_(13,1)=0.0567;
+	exchangeability_(4,16)=2.27651;
+	exchangeability_(16,4)=2.27651;
+	exchangeability_(6,14)=0.31115;
+	exchangeability_(14,6)=0.31115;
+	exchangeability_(11,15)=0.924;
+	exchangeability_(15,11)=0.924;
+	exchangeability_(0,7)=2.83806;
+	exchangeability_(7,0)=2.83806;
+	exchangeability_(2,7)=0.88497;
+	exchangeability_(7,2)=0.88497;
+	exchangeability_(8,18)=5.22609;
+	exchangeability_(18,8)=5.22609;
+	exchangeability_(5,10)=0.64806;
+	exchangeability_(10,5)=0.64806;
+	exchangeability_(15,18)=0.26799;
+	exchangeability_(18,15)=0.26799;
+	exchangeability_(12,16)=1.29263;
+	exchangeability_(16,12)=1.29263;
+	exchangeability_(5,14)=0.72953;
+	exchangeability_(14,5)=0.72953;
+	exchangeability_(7,8)=0.21931;
+	exchangeability_(8,7)=0.21931;
+	exchangeability_(15,17)=0.21141;
+	exchangeability_(17,15)=0.21141;
+	exchangeability_(3,7)=0.9223;
+	exchangeability_(7,3)=0.9223;
+	exchangeability_(6,15)=0.76381;
+	exchangeability_(15,6)=0.76381;
+	exchangeability_(12,13)=1.22653;
+	exchangeability_(13,12)=1.22653;
+	exchangeability_(13,14)=0.05722;
+	exchangeability_(14,13)=0.05722;
+	exchangeability_(3,10)=0.0188;
+	exchangeability_(10,3)=0.0188;
+	exchangeability_(0,13)=0.08941;
+	exchangeability_(13,0)=0.08941;
+	exchangeability_(6,12)=0.31312;
+	exchangeability_(12,6)=0.31312;
+	exchangeability_(4,12)=0.76511;
+	exchangeability_(12,4)=0.76511;
+	exchangeability_(9,14)=0.04;
+	exchangeability_(14,9)=0.04;
+	exchangeability_(10,11)=0.20761;
+	exchangeability_(11,10)=0.20761;
+	exchangeability_(12,17)=0.46339;
+	exchangeability_(17,12)=0.46339;
+	exchangeability_(2,19)=0.12508;
+	exchangeability_(19,2)=0.12508;
+	exchangeability_(8,10)=0.2822;
+	exchangeability_(10,8)=0.2822;
+	exchangeability_(1,8)=3.62558;
+	exchangeability_(8,1)=3.62558;
+	exchangeability_(1,5)=5.12875;
+	exchangeability_(5,1)=5.12875;
+	exchangeability_(2,5)=2.81107;
+	exchangeability_(5,2)=2.81107;
+	exchangeability_(0,18)=0.07806;
+	exchangeability_(18,0)=0.07806;
+	exchangeability_(13,18)=8.14165;
+	exchangeability_(18,13)=8.14165;
+	exchangeability_(6,10)=0.07503;
+	exchangeability_(10,6)=0.07503;
+	exchangeability_(9,15)=0.04888;
+	exchangeability_(15,9)=0.04888;
+	exchangeability_(2,15)=5.18256;
+	exchangeability_(15,2)=5.18256;
+	exchangeability_(7,17)=0.16999;
+	exchangeability_(17,7)=0.16999;
+	exchangeability_(2,16)=2.18109;
+	exchangeability_(16,2)=2.18109;
+	exchangeability_(12,19)=0.96462;
+	exchangeability_(19,12)=0.96462;
+	exchangeability_(8,12)=0.34047;
+	exchangeability_(12,8)=0.34047;
+	exchangeability_(3,6)=12.0123;
+	exchangeability_(6,3)=12.0123;
+	exchangeability_(4,11)=0.13278;
+	exchangeability_(11,4)=0.13278;
+	exchangeability_(4,18)=0.76274;
+	exchangeability_(18,4)=0.76274;
+	exchangeability_(0,9)=0.0515;
+	exchangeability_(9,0)=0.0515;
+	exchangeability_(4,14)=0.18123;
+	exchangeability_(14,4)=0.18123;
+	exchangeability_(1,15)=1.06601;
+	exchangeability_(15,1)=1.06601;
+	exchangeability_(2,4)=1.46033;
+	exchangeability_(4,2)=1.46033;
+	exchangeability_(11,13)=0.07787;
+	exchangeability_(13,11)=0.07787;
+	exchangeability_(11,12)=1.01467;
+	exchangeability_(12,11)=1.01467;
+	exchangeability_(10,13)=1.60662;
+	exchangeability_(13,10)=1.60662;
+	exchangeability_(12,14)=0.075;
+	exchangeability_(14,12)=0.075;
+	exchangeability_(7,10)=0.01632;
+	exchangeability_(10,7)=0.01632;
+	exchangeability_(0,8)=0.23968;
+	exchangeability_(8,0)=0.23968;
+	exchangeability_(3,4)=0.3444;
+	exchangeability_(4,3)=0.3444;
+	exchangeability_(3,8)=1.82624;
+	exchangeability_(8,3)=1.82624;
+	exchangeability_(2,10)=0.09198;
+	exchangeability_(10,2)=0.09198;
+	exchangeability_(17,18)=3.04742;
+	exchangeability_(18,17)=3.04742;
+	exchangeability_(10,18)=0.18029;
+	exchangeability_(18,10)=0.18029;
+	exchangeability_(6,9)=0.03697;
+	exchangeability_(9,6)=0.03697;
+	exchangeability_(4,9)=0.16279;
+	exchangeability_(9,4)=0.16279;
+	exchangeability_(14,19)=0.20745;
+	exchangeability_(19,14)=0.20745;
+	exchangeability_(9,16)=0.61033;
+	exchangeability_(16,9)=0.61033;
+	exchangeability_(12,15)=0.26034;
+	exchangeability_(15,12)=0.26034;
+	exchangeability_(1,4)=0.91364;
+	exchangeability_(4,1)=0.91364;
+	exchangeability_(4,17)=0.46845;
+	exchangeability_(17,4)=0.46845;
+	exchangeability_(0,11)=0.44318;
+	exchangeability_(11,0)=0.44318;
+	exchangeability_(9,13)=0.49118;
+	exchangeability_(13,9)=0.49118;
+	exchangeability_(1,10)=0.31615;
+	exchangeability_(10,1)=0.31615;
+	exchangeability_(11,19)=0.22225;
+	exchangeability_(19,11)=0.22225;
+	exchangeability_(2,12)=0.39861;
+	exchangeability_(12,2)=0.39861;
+	exchangeability_(10,19)=0.99389;
+	exchangeability_(19,10)=0.99389;
+	exchangeability_(6,8)=0.83985;
+	exchangeability_(8,6)=0.83985;
+	exchangeability_(9,17)=0.05671;
+	exchangeability_(17,9)=0.05671;
+	exchangeability_(7,11)=0.55152;
+	exchangeability_(11,7)=0.55152;
+	exchangeability_(3,15)=1.2164;
+	exchangeability_(15,3)=1.2164;
+	exchangeability_(13,19)=0.26205;
+	exchangeability_(19,13)=0.26205;
+	exchangeability_(14,18)=0.06281;
+	exchangeability_(18,14)=0.06281;
+	exchangeability_(6,18)=0.14249;
+	exchangeability_(18,6)=0.14249;
+	exchangeability_(5,16)=0.82988;
+	exchangeability_(16,5)=0.82988;
+	exchangeability_(5,15)=1.15909;
+	exchangeability_(15,5)=1.15909;
+}
+
+
+if (getName()=="Intermediate"){
+	exchangeability_(10,17)=0.67791;
+	exchangeability_(17,10)=0.67791;
+	exchangeability_(6,11)=0.7924;
+	exchangeability_(11,6)=0.7924;
+	exchangeability_(4,7)=0.86714;
+	exchangeability_(7,4)=0.86714;
+	exchangeability_(17,19)=0.17576;
+	exchangeability_(19,17)=0.17576;
+	exchangeability_(9,19)=15.5327;
+	exchangeability_(19,9)=15.5327;
+	exchangeability_(5,6)=3.11324;
+	exchangeability_(6,5)=3.11324;
+	exchangeability_(1,6)=0.2159;
+	exchangeability_(6,1)=0.2159;
+	exchangeability_(0,12)=0.94996;
+	exchangeability_(12,0)=0.94996;
+	exchangeability_(1,2)=0.53679;
+	exchangeability_(2,1)=0.53679;
+	exchangeability_(11,16)=1.07188;
+	exchangeability_(16,11)=1.07188;
+	exchangeability_(1,17)=0.3786;
+	exchangeability_(17,1)=0.3786;
+	exchangeability_(8,15)=0.93963;
+	exchangeability_(15,8)=0.93963;
+	exchangeability_(13,17)=3.50239;
+	exchangeability_(17,13)=3.50239;
+	exchangeability_(10,16)=0.39532;
+	exchangeability_(16,10)=0.39532;
+	exchangeability_(13,15)=0.54776;
+	exchangeability_(15,13)=0.54776;
+	exchangeability_(9,18)=0.29921;
+	exchangeability_(18,9)=0.29921;
+	exchangeability_(2,18)=0.53465;
+	exchangeability_(18,2)=0.53465;
+	exchangeability_(7,9)=0.01318;
+	exchangeability_(9,7)=0.01318;
+	exchangeability_(3,5)=0.50809;
+	exchangeability_(5,3)=0.50809;
+	exchangeability_(3,13)=0.02861;
+	exchangeability_(13,3)=0.02861;
+	exchangeability_(0,10)=0.34503;
+	exchangeability_(10,0)=0.34503;
+	exchangeability_(9,11)=0.30184;
+	exchangeability_(11,9)=0.30184;
+	exchangeability_(8,14)=0.3005;
+	exchangeability_(14,8)=0.3005;
+	exchangeability_(2,8)=5.00374;
+	exchangeability_(8,2)=5.00374;
+	exchangeability_(4,6)=0.04686;
+	exchangeability_(6,4)=0.04686;
+	exchangeability_(8,13)=1.5411;
+	exchangeability_(13,8)=1.5411;
+	exchangeability_(5,7)=0.34922;
+	exchangeability_(7,5)=0.34922;
+	exchangeability_(1,7)=0.39005;
+	exchangeability_(7,1)=0.39005;
+	exchangeability_(4,15)=5.24937;
+	exchangeability_(15,4)=5.24937;
+	exchangeability_(1,14)=0.17017;
+	exchangeability_(14,1)=0.17017;
+	exchangeability_(1,18)=0.14938;
+	exchangeability_(18,1)=0.14938;
+	exchangeability_(11,18)=0.09087;
+	exchangeability_(18,11)=0.09087;
+	exchangeability_(0,5)=1.10197;
+	exchangeability_(5,0)=1.10197;
+	exchangeability_(2,9)=0.29582;
+	exchangeability_(9,2)=0.29582;
+	exchangeability_(7,18)=0.03191;
+	exchangeability_(18,7)=0.03191;
+	exchangeability_(7,14)=0.1861;
+	exchangeability_(14,7)=0.1861;
+	exchangeability_(3,19)=0.0665;
+	exchangeability_(19,3)=0.0665;
+	exchangeability_(5,13)=0.07787;
+	exchangeability_(13,5)=0.07787;
+	exchangeability_(15,19)=0.19702;
+	exchangeability_(19,15)=0.19702;
+	exchangeability_(11,17)=0.06205;
+	exchangeability_(17,11)=0.06205;
+	exchangeability_(7,13)=0.06539;
+	exchangeability_(13,7)=0.06539;
+	exchangeability_(0,2)=0.46692;
+	exchangeability_(2,0)=0.46692;
+	exchangeability_(9,12)=6.2595;
+	exchangeability_(12,9)=6.2595;
+	exchangeability_(3,12)=0.09101;
+	exchangeability_(12,3)=0.09101;
+	exchangeability_(8,19)=0.22435;
+	exchangeability_(19,8)=0.22435;
+	exchangeability_(0,14)=1.33472;
+	exchangeability_(14,0)=1.33472;
+	exchangeability_(5,17)=0.17453;
+	exchangeability_(17,5)=0.17453;
+	exchangeability_(4,10)=1.10757;
+	exchangeability_(10,4)=1.10757;
+	exchangeability_(10,15)=0.27512;
+	exchangeability_(15,10)=0.27512;
+	exchangeability_(14,17)=0.04695;
+	exchangeability_(17,14)=0.04695;
+	exchangeability_(16,18)=0.1752;
+	exchangeability_(18,16)=0.1752;
+	exchangeability_(1,9)=0.18032;
+	exchangeability_(9,1)=0.18032;
+	exchangeability_(4,5)=0.39335;
+	exchangeability_(5,4)=0.39335;
+	exchangeability_(9,10)=5.43989;
+	exchangeability_(10,9)=5.43989;
+	exchangeability_(11,14)=0.16253;
+	exchangeability_(14,11)=0.16253;
+	exchangeability_(8,17)=0.82252;
+	exchangeability_(17,8)=0.82252;
+	exchangeability_(0,15)=5.31695;
+	exchangeability_(15,0)=5.31695;
+	exchangeability_(2,11)=1.52432;
+	exchangeability_(11,2)=1.52432;
+	exchangeability_(10,14)=0.26596;
+	exchangeability_(14,10)=0.26596;
+	exchangeability_(13,16)=0.18398;
+	exchangeability_(16,13)=0.18398;
+	exchangeability_(7,19)=0.10881;
+	exchangeability_(19,7)=0.10881;
+	exchangeability_(3,16)=0.38304;
+	exchangeability_(16,3)=0.38304;
+	exchangeability_(7,12)=0.1403;
+	exchangeability_(12,7)=0.1403;
+	exchangeability_(15,16)=7.24385;
+	exchangeability_(16,15)=7.24385;
+	exchangeability_(14,15)=1.18778;
+	exchangeability_(15,14)=1.18778;
+	exchangeability_(3,11)=0.12199;
+	exchangeability_(11,3)=0.12199;
+	exchangeability_(6,7)=0.40641;
+	exchangeability_(7,6)=0.40641;
+	exchangeability_(8,16)=0.46734;
+	exchangeability_(16,8)=0.46734;
+	exchangeability_(0,1)=0.48924;
+	exchangeability_(1,0)=0.48924;
+	exchangeability_(5,9)=0.1795;
+	exchangeability_(9,5)=0.1795;
+	exchangeability_(12,18)=0.49269;
+	exchangeability_(18,12)=0.49269;
+	exchangeability_(6,16)=0.53102;
+	exchangeability_(16,6)=0.53102;
+	exchangeability_(1,11)=4.32293;
+	exchangeability_(11,1)=4.32293;
+	exchangeability_(2,14)=0.09938;
+	exchangeability_(14,2)=0.09938;
+	exchangeability_(0,4)=2.43055;
+	exchangeability_(4,0)=2.43055;
+	exchangeability_(1,16)=0.53503;
+	exchangeability_(16,1)=0.53503;
+	exchangeability_(6,13)=0.02575;
+	exchangeability_(13,6)=0.02575;
+	exchangeability_(18,19)=0.27664;
+	exchangeability_(19,18)=0.27664;
+	exchangeability_(5,8)=3.5678;
+	exchangeability_(8,5)=3.5678;
+	exchangeability_(16,19)=2.50705;
+	exchangeability_(19,16)=2.50705;
+	exchangeability_(7,16)=0.1801;
+	exchangeability_(16,7)=0.1801;
+	exchangeability_(8,11)=0.59151;
+	exchangeability_(11,8)=0.59151;
+	exchangeability_(3,17)=0.04839;
+	exchangeability_(17,3)=0.04839;
+	exchangeability_(6,17)=0.06378;
+	exchangeability_(17,6)=0.06378;
+	exchangeability_(2,3)=4.60344;
+	exchangeability_(3,2)=4.60344;
+	exchangeability_(3,9)=0.01325;
+	exchangeability_(9,3)=0.01325;
+	exchangeability_(0,16)=1.96381;
+	exchangeability_(16,0)=1.96381;
+	exchangeability_(5,11)=2.67448;
+	exchangeability_(11,5)=2.67448;
+	exchangeability_(4,8)=1.63009;
+	exchangeability_(8,4)=1.63009;
+	exchangeability_(16,17)=0.1071;
+	exchangeability_(17,16)=0.1071;
+	exchangeability_(5,19)=0.39345;
+	exchangeability_(19,5)=0.39345;
+	exchangeability_(1,3)=0.06947;
+	exchangeability_(3,1)=0.06947;
+	exchangeability_(4,19)=3.1128;
+	exchangeability_(19,4)=3.1128;
+	exchangeability_(6,19)=0.44447;
+	exchangeability_(19,6)=0.44447;
+	exchangeability_(1,12)=0.4727;
+	exchangeability_(12,1)=0.4727;
+	exchangeability_(0,6)=1.22778;
+	exchangeability_(6,0)=1.22778;
+	exchangeability_(2,6)=0.34554;
+	exchangeability_(6,2)=0.34554;
+	exchangeability_(1,19)=0.22036;
+	exchangeability_(19,1)=0.22036;
+	exchangeability_(0,17)=0.14569;
+	exchangeability_(17,0)=0.14569;
+	exchangeability_(2,17)=0.0466;
+	exchangeability_(17,2)=0.0466;
+	exchangeability_(7,15)=2.36619;
+	exchangeability_(15,7)=2.36619;
+	exchangeability_(3,14)=0.21187;
+	exchangeability_(14,3)=0.21187;
+	exchangeability_(8,9)=0.20921;
+	exchangeability_(9,8)=0.20921;
+	exchangeability_(3,18)=0.106;
+	exchangeability_(18,3)=0.106;
+	exchangeability_(0,3)=0.60191;
+	exchangeability_(3,0)=0.60191;
+	exchangeability_(2,13)=0.16181;
+	exchangeability_(13,2)=0.16181;
+	exchangeability_(0,19)=2.2275;
+	exchangeability_(19,0)=2.2275;
+	exchangeability_(5,12)=1.90588;
+	exchangeability_(12,5)=1.90588;
+	exchangeability_(4,13)=2.06548;
+	exchangeability_(13,4)=2.06548;
+	exchangeability_(10,12)=9.39108;
+	exchangeability_(12,10)=9.39108;
+	exchangeability_(5,18)=0.15015;
+	exchangeability_(18,5)=0.15015;
+	exchangeability_(14,16)=0.40037;
+	exchangeability_(16,14)=0.40037;
+	exchangeability_(1,13)=0.06982;
+	exchangeability_(13,1)=0.06982;
+	exchangeability_(4,16)=2.01244;
+	exchangeability_(16,4)=2.01244;
+	exchangeability_(6,14)=0.15544;
+	exchangeability_(14,6)=0.15544;
+	exchangeability_(11,15)=0.53277;
+	exchangeability_(15,11)=0.53277;
+	exchangeability_(0,7)=1.87307;
+	exchangeability_(7,0)=1.87307;
+	exchangeability_(2,7)=1.52829;
+	exchangeability_(7,2)=1.52829;
+	exchangeability_(8,18)=6.19889;
+	exchangeability_(18,8)=6.19889;
+	exchangeability_(5,10)=1.02775;
+	exchangeability_(10,5)=1.02775;
+	exchangeability_(15,18)=0.32829;
+	exchangeability_(18,15)=0.32829;
+	exchangeability_(12,16)=2.34027;
+	exchangeability_(16,12)=2.34027;
+	exchangeability_(5,14)=0.3495;
+	exchangeability_(14,5)=0.3495;
+	exchangeability_(7,8)=0.31538;
+	exchangeability_(8,7)=0.31538;
+	exchangeability_(15,17)=0.2905;
+	exchangeability_(17,15)=0.2905;
+	exchangeability_(3,7)=0.94197;
+	exchangeability_(7,3)=0.94197;
+	exchangeability_(6,15)=0.43879;
+	exchangeability_(15,6)=0.43879;
+	exchangeability_(12,13)=2.2431;
+	exchangeability_(13,12)=2.2431;
+	exchangeability_(13,14)=0.08375;
+	exchangeability_(14,13)=0.08375;
+	exchangeability_(3,10)=0.02439;
+	exchangeability_(10,3)=0.02439;
+	exchangeability_(0,13)=0.24727;
+	exchangeability_(13,0)=0.24727;
+	exchangeability_(6,12)=0.24208;
+	exchangeability_(12,6)=0.24208;
+	exchangeability_(4,12)=1.2833;
+	exchangeability_(12,4)=1.2833;
+	exchangeability_(9,14)=0.06563;
+	exchangeability_(14,9)=0.06563;
+	exchangeability_(10,11)=0.29495;
+	exchangeability_(11,10)=0.29495;
+	exchangeability_(12,17)=0.7964;
+	exchangeability_(17,12)=0.7964;
+	exchangeability_(2,19)=0.15032;
+	exchangeability_(19,2)=0.15032;
+	exchangeability_(8,10)=0.59298;
+	exchangeability_(10,8)=0.59298;
+	exchangeability_(1,8)=1.93092;
+	exchangeability_(8,1)=1.93092;
+	exchangeability_(1,5)=2.08136;
+	exchangeability_(5,1)=2.08136;
+	exchangeability_(2,5)=1.29912;
+	exchangeability_(5,2)=1.29912;
+	exchangeability_(0,18)=0.19576;
+	exchangeability_(18,0)=0.19576;
+	exchangeability_(13,18)=15.0391;
+	exchangeability_(18,13)=15.0391;
+	exchangeability_(6,10)=0.12381;
+	exchangeability_(10,6)=0.12381;
+	exchangeability_(9,15)=0.13882;
+	exchangeability_(15,9)=0.13882;
+	exchangeability_(2,15)=4.52619;
+	exchangeability_(15,2)=4.52619;
+	exchangeability_(7,17)=0.16884;
+	exchangeability_(17,7)=0.16884;
+	exchangeability_(2,16)=2.03458;
+	exchangeability_(16,2)=2.03458;
+	exchangeability_(12,19)=2.65834;
+	exchangeability_(19,12)=2.65834;
+	exchangeability_(8,12)=0.37846;
+	exchangeability_(12,8)=0.37846;
+	exchangeability_(3,6)=3.57938;
+	exchangeability_(6,3)=3.57938;
+	exchangeability_(4,11)=0.18161;
+	exchangeability_(11,4)=0.18161;
+	exchangeability_(4,18)=2.4462;
+	exchangeability_(18,4)=2.4462;
+	exchangeability_(0,9)=0.15872;
+	exchangeability_(9,0)=0.15872;
+	exchangeability_(4,14)=0.16319;
+	exchangeability_(14,4)=0.16319;
+	exchangeability_(1,15)=0.69904;
+	exchangeability_(15,1)=0.69904;
+	exchangeability_(2,4)=0.99722;
+	exchangeability_(4,2)=0.99722;
+	exchangeability_(11,13)=0.04869;
+	exchangeability_(13,11)=0.04869;
+	exchangeability_(11,12)=1.07451;
+	exchangeability_(12,11)=1.07451;
+	exchangeability_(10,13)=3.01572;
+	exchangeability_(13,10)=3.01572;
+	exchangeability_(12,14)=0.08868;
+	exchangeability_(14,12)=0.08868;
+	exchangeability_(7,10)=0.04855;
+	exchangeability_(10,7)=0.04855;
+	exchangeability_(0,8)=0.519;
+	exchangeability_(8,0)=0.519;
+	exchangeability_(3,4)=0.16643;
+	exchangeability_(4,3)=0.16643;
+	exchangeability_(3,8)=0.78189;
+	exchangeability_(8,3)=0.78189;
+	exchangeability_(2,10)=0.13877;
+	exchangeability_(10,2)=0.13877;
+	exchangeability_(17,18)=3.12585;
+	exchangeability_(18,17)=3.12585;
+	exchangeability_(10,18)=0.41315;
+	exchangeability_(18,10)=0.41315;
+	exchangeability_(6,9)=0.09083;
+	exchangeability_(9,6)=0.09083;
+	exchangeability_(4,9)=0.64279;
+	exchangeability_(9,4)=0.64279;
+	exchangeability_(14,19)=0.32225;
+	exchangeability_(19,14)=0.32225;
+	exchangeability_(9,16)=1.86194;
+	exchangeability_(16,9)=1.86194;
+	exchangeability_(12,15)=0.52151;
+	exchangeability_(15,12)=0.52151;
+	exchangeability_(1,4)=1.80741;
+	exchangeability_(4,1)=1.80741;
+	exchangeability_(4,17)=1.07415;
+	exchangeability_(17,4)=1.07415;
+	exchangeability_(0,11)=0.61018;
+	exchangeability_(11,0)=0.61018;
+	exchangeability_(9,13)=1.30648;
+	exchangeability_(13,9)=1.30648;
+	exchangeability_(1,10)=0.50329;
+	exchangeability_(10,1)=0.50329;
+	exchangeability_(11,19)=0.30228;
+	exchangeability_(19,11)=0.30228;
+	exchangeability_(2,12)=0.50271;
+	exchangeability_(12,2)=0.50271;
+	exchangeability_(10,19)=2.15264;
+	exchangeability_(19,10)=2.15264;
+	exchangeability_(6,8)=0.3249;
+	exchangeability_(8,6)=0.3249;
+	exchangeability_(9,17)=0.11064;
+	exchangeability_(17,9)=0.11064;
+	exchangeability_(7,11)=0.27677;
+	exchangeability_(11,7)=0.27677;
+	exchangeability_(3,15)=1.14365;
+	exchangeability_(15,3)=1.14365;
+	exchangeability_(13,19)=0.73805;
+	exchangeability_(19,13)=0.73805;
+	exchangeability_(14,18)=0.04476;
+	exchangeability_(18,14)=0.04476;
+	exchangeability_(6,18)=0.07197;
+	exchangeability_(18,6)=0.07197;
+	exchangeability_(5,16)=0.89115;
+	exchangeability_(16,5)=0.89115;
+	exchangeability_(5,15)=0.9707;
+	exchangeability_(15,5)=0.9707;
+}
+
+
+if (getName()=="HExposed"){
+	exchangeability_(10,17)=3.29015;
+	exchangeability_(17,10)=3.29015;
+	exchangeability_(6,11)=0.62329;
+	exchangeability_(11,6)=0.62329;
+	exchangeability_(4,7)=1.33636;
+	exchangeability_(7,4)=1.33636;
+	exchangeability_(17,19)=0.45688;
+	exchangeability_(19,17)=0.45688;
+	exchangeability_(9,19)=46.0747;
+	exchangeability_(19,9)=46.0747;
+	exchangeability_(5,6)=2.0983;
+	exchangeability_(6,5)=2.0983;
+	exchangeability_(1,6)=0.11116;
+	exchangeability_(6,1)=0.11116;
+	exchangeability_(0,12)=1.33841;
+	exchangeability_(12,0)=1.33841;
+	exchangeability_(1,2)=0.50896;
+	exchangeability_(2,1)=0.50896;
+	exchangeability_(11,16)=1.26831;
+	exchangeability_(16,11)=1.26831;
+	exchangeability_(1,17)=1.02183;
+	exchangeability_(17,1)=1.02183;
+	exchangeability_(8,15)=1.1441;
+	exchangeability_(15,8)=1.1441;
+	exchangeability_(13,17)=13.0569;
+	exchangeability_(17,13)=13.0569;
+	exchangeability_(10,16)=0.83874;
+	exchangeability_(16,10)=0.83874;
+	exchangeability_(13,15)=1.16759;
+	exchangeability_(15,13)=1.16759;
+	exchangeability_(9,18)=1.29221;
+	exchangeability_(18,9)=1.29221;
+	exchangeability_(2,18)=1.11576;
+	exchangeability_(18,2)=1.11576;
+	exchangeability_(7,9)=0.01569;
+	exchangeability_(9,7)=0.01569;
+	exchangeability_(3,5)=0.33312;
+	exchangeability_(5,3)=0.33312;
+	exchangeability_(3,13)=0.04485;
+	exchangeability_(13,3)=0.04485;
+	exchangeability_(0,10)=0.71509;
+	exchangeability_(10,0)=0.71509;
+	exchangeability_(9,11)=0.56978;
+	exchangeability_(11,9)=0.56978;
+	exchangeability_(8,14)=0.37526;
+	exchangeability_(14,8)=0.37526;
+	exchangeability_(2,8)=5.39249;
+	exchangeability_(8,2)=5.39249;
+	exchangeability_(4,6)=0.05865;
+	exchangeability_(6,4)=0.05865;
+	exchangeability_(8,13)=3.49431;
+	exchangeability_(13,8)=3.49431;
+	exchangeability_(5,7)=0.32236;
+	exchangeability_(7,5)=0.32236;
+	exchangeability_(1,7)=0.39378;
+	exchangeability_(7,1)=0.39378;
+	exchangeability_(4,15)=6.49913;
+	exchangeability_(15,4)=6.49913;
+	exchangeability_(1,14)=0.16846;
+	exchangeability_(14,1)=0.16846;
+	exchangeability_(1,18)=0.42487;
+	exchangeability_(18,1)=0.42487;
+	exchangeability_(11,18)=0.10403;
+	exchangeability_(18,11)=0.10403;
+	exchangeability_(0,5)=1.40248;
+	exchangeability_(5,0)=1.40248;
+	exchangeability_(2,9)=0.53511;
+	exchangeability_(9,2)=0.53511;
+	exchangeability_(7,18)=0.10772;
+	exchangeability_(18,7)=0.10772;
+	exchangeability_(7,14)=0.12029;
+	exchangeability_(14,7)=0.12029;
+	exchangeability_(3,19)=0.12554;
+	exchangeability_(19,3)=0.12554;
+	exchangeability_(5,13)=0.12091;
+	exchangeability_(13,5)=0.12091;
+	exchangeability_(15,19)=0.56457;
+	exchangeability_(19,15)=0.56457;
+	exchangeability_(11,17)=0.06465;
+	exchangeability_(17,11)=0.06465;
+	exchangeability_(7,13)=0.19467;
+	exchangeability_(13,7)=0.19467;
+	exchangeability_(0,2)=0.46702;
+	exchangeability_(2,0)=0.46702;
+	exchangeability_(9,12)=19.6054;
+	exchangeability_(12,9)=19.6054;
+	exchangeability_(3,12)=0.05431;
+	exchangeability_(12,3)=0.05431;
+	exchangeability_(8,19)=0.53368;
+	exchangeability_(19,8)=0.53368;
+	exchangeability_(0,14)=1.08502;
+	exchangeability_(14,0)=1.08502;
+	exchangeability_(5,17)=0.53058;
+	exchangeability_(17,5)=0.53058;
+	exchangeability_(4,10)=3.52093;
+	exchangeability_(10,4)=3.52093;
+	exchangeability_(10,15)=0.87883;
+	exchangeability_(15,10)=0.87883;
+	exchangeability_(14,17)=0.05671;
+	exchangeability_(17,14)=0.05671;
+	exchangeability_(16,18)=0.39679;
+	exchangeability_(18,16)=0.39679;
+	exchangeability_(1,9)=0.40754;
+	exchangeability_(9,1)=0.40754;
+	exchangeability_(4,5)=0.78937;
+	exchangeability_(5,4)=0.78937;
+	exchangeability_(9,10)=18.8303;
+	exchangeability_(10,9)=18.8303;
+	exchangeability_(11,14)=0.19075;
+	exchangeability_(14,11)=0.19075;
+	exchangeability_(8,17)=1.32415;
+	exchangeability_(17,8)=1.32415;
+	exchangeability_(0,15)=4.09002;
+	exchangeability_(15,0)=4.09002;
+	exchangeability_(2,11)=1.74765;
+	exchangeability_(11,2)=1.74765;
+	exchangeability_(10,14)=0.70549;
+	exchangeability_(14,10)=0.70549;
+	exchangeability_(13,16)=0.38176;
+	exchangeability_(16,13)=0.38176;
+	exchangeability_(7,19)=0.21576;
+	exchangeability_(19,7)=0.21576;
+	exchangeability_(3,16)=0.38525;
+	exchangeability_(16,3)=0.38525;
+	exchangeability_(7,12)=0.22876;
+	exchangeability_(12,7)=0.22876;
+	exchangeability_(15,16)=7.67728;
+	exchangeability_(16,15)=7.67728;
+	exchangeability_(14,15)=1.19572;
+	exchangeability_(15,14)=1.19572;
+	exchangeability_(3,11)=0.08368;
+	exchangeability_(11,3)=0.08368;
+	exchangeability_(6,7)=0.25236;
+	exchangeability_(7,6)=0.25236;
+	exchangeability_(8,16)=0.79611;
+	exchangeability_(16,8)=0.79611;
+	exchangeability_(0,1)=0.5575;
+	exchangeability_(1,0)=0.5575;
+	exchangeability_(5,9)=0.42762;
+	exchangeability_(9,5)=0.42762;
+	exchangeability_(12,18)=2.06374;
+	exchangeability_(18,12)=2.06374;
+	exchangeability_(6,16)=0.53217;
+	exchangeability_(16,6)=0.53217;
+	exchangeability_(1,11)=3.72863;
+	exchangeability_(11,1)=3.72863;
+	exchangeability_(2,14)=0.04115;
+	exchangeability_(14,2)=0.04115;
+	exchangeability_(0,4)=1.33258;
+	exchangeability_(4,0)=1.33258;
+	exchangeability_(1,16)=0.65002;
+	exchangeability_(16,1)=0.65002;
+	exchangeability_(6,13)=0.04218;
+	exchangeability_(13,6)=0.04218;
+	exchangeability_(18,19)=0.67081;
+	exchangeability_(19,18)=0.67081;
+	exchangeability_(5,8)=4.51767;
+	exchangeability_(8,5)=4.51767;
+	exchangeability_(16,19)=4.51986;
+	exchangeability_(19,16)=4.51986;
+	exchangeability_(7,16)=0.18706;
+	exchangeability_(16,7)=0.18706;
+	exchangeability_(8,11)=0.69497;
+	exchangeability_(11,8)=0.69497;
+	exchangeability_(3,17)=0.06518;
+	exchangeability_(17,3)=0.06518;
+	exchangeability_(6,17)=0.07752;
+	exchangeability_(17,6)=0.07752;
+	exchangeability_(2,3)=3.38672;
+	exchangeability_(3,2)=3.38672;
+	exchangeability_(3,9)=0.05403;
+	exchangeability_(9,3)=0.05403;
+	exchangeability_(0,16)=2.3184;
+	exchangeability_(16,0)=2.3184;
+	exchangeability_(5,11)=2.47721;
+	exchangeability_(11,5)=2.47721;
+	exchangeability_(4,8)=3.82756;
+	exchangeability_(8,4)=3.82756;
+	exchangeability_(16,17)=0.40842;
+	exchangeability_(17,16)=0.40842;
+	exchangeability_(5,19)=0.86879;
+	exchangeability_(19,5)=0.86879;
+	exchangeability_(1,3)=0.04404;
+	exchangeability_(3,1)=0.04404;
+	exchangeability_(4,19)=5.3017;
+	exchangeability_(19,4)=5.3017;
+	exchangeability_(6,19)=0.83951;
+	exchangeability_(19,6)=0.83951;
+	exchangeability_(1,12)=1.26183;
+	exchangeability_(12,1)=1.26183;
+	exchangeability_(0,6)=1.25919;
+	exchangeability_(6,0)=1.25919;
+	exchangeability_(2,6)=0.24584;
+	exchangeability_(6,2)=0.24584;
+	exchangeability_(1,19)=0.54401;
+	exchangeability_(19,1)=0.54401;
+	exchangeability_(0,17)=0.13437;
+	exchangeability_(17,0)=0.13437;
+	exchangeability_(2,17)=0.15129;
+	exchangeability_(17,2)=0.15129;
+	exchangeability_(7,15)=1.73372;
+	exchangeability_(15,7)=1.73372;
+	exchangeability_(3,14)=0.20376;
+	exchangeability_(14,3)=0.20376;
+	exchangeability_(8,9)=0.65898;
+	exchangeability_(9,8)=0.65898;
+	exchangeability_(3,18)=0.26888;
+	exchangeability_(18,3)=0.26888;
+	exchangeability_(0,3)=0.66046;
+	exchangeability_(3,0)=0.66046;
+	exchangeability_(2,13)=0.2638;
+	exchangeability_(13,2)=0.2638;
+	exchangeability_(0,19)=3.11267;
+	exchangeability_(19,0)=3.11267;
+	exchangeability_(5,12)=2.38372;
+	exchangeability_(12,5)=2.38372;
+	exchangeability_(4,13)=5.26647;
+	exchangeability_(13,4)=5.26647;
+	exchangeability_(10,12)=31.4312;
+	exchangeability_(12,10)=31.4312;
+	exchangeability_(5,18)=0.25557;
+	exchangeability_(18,5)=0.25557;
+	exchangeability_(14,16)=0.41994;
+	exchangeability_(16,14)=0.41994;
+	exchangeability_(1,13)=0.19013;
+	exchangeability_(13,1)=0.19013;
+	exchangeability_(4,16)=1.88308;
+	exchangeability_(16,4)=1.88308;
+	exchangeability_(6,14)=0.21819;
+	exchangeability_(14,6)=0.21819;
+	exchangeability_(11,15)=0.6315;
+	exchangeability_(15,11)=0.6315;
+	exchangeability_(0,7)=0.93453;
+	exchangeability_(7,0)=0.93453;
+	exchangeability_(2,7)=2.19637;
+	exchangeability_(7,2)=2.19637;
+	exchangeability_(8,18)=14.436;
+	exchangeability_(18,8)=14.436;
+	exchangeability_(5,10)=2.36665;
+	exchangeability_(10,5)=2.36665;
+	exchangeability_(15,18)=0.75636;
+	exchangeability_(18,15)=0.75636;
+	exchangeability_(12,16)=4.44576;
+	exchangeability_(16,12)=4.44576;
+	exchangeability_(5,14)=0.35342;
+	exchangeability_(14,5)=0.35342;
+	exchangeability_(7,8)=0.6346;
+	exchangeability_(8,7)=0.6346;
+	exchangeability_(15,17)=0.53491;
+	exchangeability_(17,15)=0.53491;
+	exchangeability_(3,7)=0.86825;
+	exchangeability_(7,3)=0.86825;
+	exchangeability_(6,15)=0.33692;
+	exchangeability_(15,6)=0.33692;
+	exchangeability_(12,13)=6.23784;
+	exchangeability_(13,12)=6.23784;
+	exchangeability_(13,14)=0.10882;
+	exchangeability_(14,13)=0.10882;
+	exchangeability_(3,10)=0.03516;
+	exchangeability_(10,3)=0.03516;
+	exchangeability_(0,13)=0.29552;
+	exchangeability_(13,0)=0.29552;
+	exchangeability_(6,12)=0.21994;
+	exchangeability_(12,6)=0.21994;
+	exchangeability_(4,12)=3.9187;
+	exchangeability_(12,4)=3.9187;
+	exchangeability_(9,14)=0.11687;
+	exchangeability_(14,9)=0.11687;
+	exchangeability_(10,11)=0.49314;
+	exchangeability_(11,10)=0.49314;
+	exchangeability_(12,17)=4.41103;
+	exchangeability_(17,12)=4.41103;
+	exchangeability_(2,19)=0.21441;
+	exchangeability_(19,2)=0.21441;
+	exchangeability_(8,10)=1.77938;
+	exchangeability_(10,8)=1.77938;
+	exchangeability_(1,8)=3.15742;
+	exchangeability_(8,1)=3.15742;
+	exchangeability_(1,5)=2.1561;
+	exchangeability_(5,1)=2.1561;
+	exchangeability_(2,5)=1.2974;
+	exchangeability_(5,2)=1.2974;
+	exchangeability_(0,18)=0.21299;
+	exchangeability_(18,0)=0.21299;
+	exchangeability_(13,18)=49.7608;
+	exchangeability_(18,13)=49.7608;
+	exchangeability_(6,10)=0.17239;
+	exchangeability_(10,6)=0.17239;
+	exchangeability_(9,15)=0.41399;
+	exchangeability_(15,9)=0.41399;
+	exchangeability_(2,15)=4.33561;
+	exchangeability_(15,2)=4.33561;
+	exchangeability_(7,17)=0.39656;
+	exchangeability_(17,7)=0.39656;
+	exchangeability_(2,16)=2.35107;
+	exchangeability_(16,2)=2.35107;
+	exchangeability_(12,19)=9.15191;
+	exchangeability_(19,12)=9.15191;
+	exchangeability_(8,12)=0.86779;
+	exchangeability_(12,8)=0.86779;
+	exchangeability_(3,6)=2.70795;
+	exchangeability_(6,3)=2.70795;
+	exchangeability_(4,11)=0.1004;
+	exchangeability_(11,4)=0.1004;
+	exchangeability_(4,18)=8.87404;
+	exchangeability_(18,4)=8.87404;
+	exchangeability_(0,9)=0.27972;
+	exchangeability_(9,0)=0.27972;
+	exchangeability_(4,14)=0.18517;
+	exchangeability_(14,4)=0.18517;
+	exchangeability_(1,15)=0.8528;
+	exchangeability_(15,1)=0.8528;
+	exchangeability_(2,4)=1.44049;
+	exchangeability_(4,2)=1.44049;
+	exchangeability_(11,13)=0.04436;
+	exchangeability_(13,11)=0.04436;
+	exchangeability_(11,12)=1.08906;
+	exchangeability_(12,11)=1.08906;
+	exchangeability_(10,13)=11.5272;
+	exchangeability_(13,10)=11.5272;
+	exchangeability_(12,14)=0.13908;
+	exchangeability_(14,12)=0.13908;
+	exchangeability_(7,10)=0.10009;
+	exchangeability_(10,7)=0.10009;
+	exchangeability_(0,8)=0.51893;
+	exchangeability_(8,0)=0.51893;
+	exchangeability_(3,4)=0.18589;
+	exchangeability_(4,3)=0.18589;
+	exchangeability_(3,8)=0.74801;
+	exchangeability_(8,3)=0.74801;
+	exchangeability_(2,10)=0.27088;
+	exchangeability_(10,2)=0.27088;
+	exchangeability_(17,18)=12.0323;
+	exchangeability_(18,17)=12.0323;
+	exchangeability_(10,18)=1.4918;
+	exchangeability_(18,10)=1.4918;
+	exchangeability_(6,9)=0.1482;
+	exchangeability_(9,6)=0.1482;
+	exchangeability_(4,9)=3.34509;
+	exchangeability_(9,4)=3.34509;
+	exchangeability_(14,19)=0.52321;
+	exchangeability_(19,14)=0.52321;
+	exchangeability_(9,16)=4.82576;
+	exchangeability_(16,9)=4.82576;
+	exchangeability_(12,15)=0.73042;
+	exchangeability_(15,12)=0.73042;
+	exchangeability_(1,4)=3.66749;
+	exchangeability_(4,1)=3.66749;
+	exchangeability_(4,17)=3.71654;
+	exchangeability_(17,4)=3.71654;
+	exchangeability_(0,11)=0.69453;
+	exchangeability_(11,0)=0.69453;
+	exchangeability_(9,13)=5.82579;
+	exchangeability_(13,9)=5.82579;
+	exchangeability_(1,10)=1.18239;
+	exchangeability_(10,1)=1.18239;
+	exchangeability_(11,19)=0.55725;
+	exchangeability_(19,11)=0.55725;
+	exchangeability_(2,12)=0.81822;
+	exchangeability_(12,2)=0.81822;
+	exchangeability_(10,19)=7.30106;
+	exchangeability_(19,10)=7.30106;
+	exchangeability_(6,8)=0.28417;
+	exchangeability_(8,6)=0.28417;
+	exchangeability_(9,17)=0.44343;
+	exchangeability_(17,9)=0.44343;
+	exchangeability_(7,11)=0.28098;
+	exchangeability_(11,7)=0.28098;
+	exchangeability_(3,15)=0.82919;
+	exchangeability_(15,3)=0.82919;
+	exchangeability_(13,19)=2.63477;
+	exchangeability_(19,13)=2.63477;
+	exchangeability_(14,18)=0.05762;
+	exchangeability_(18,14)=0.05762;
+	exchangeability_(6,18)=0.12587;
+	exchangeability_(18,6)=0.12587;
+	exchangeability_(5,16)=1.16788;
+	exchangeability_(16,5)=1.16788;
+	exchangeability_(5,15)=1.09545;
+	exchangeability_(15,5)=1.09545;
+}
+
+
+if (getName()=="Buried"){
+	exchangeability_(0,0)=-19.555;
+	exchangeability_(4,4)=-19.2782;
+	exchangeability_(6,6)=-33.2674;
+	exchangeability_(3,3)=-27.1958;
+	exchangeability_(7,7)=-10.8441;
+	exchangeability_(13,13)=-16.3164;
+	exchangeability_(9,9)=-13.0301;
+	exchangeability_(8,8)=-35.3469;
+	exchangeability_(11,11)=-43.5708;
+	exchangeability_(12,12)=-17.6161;
+	exchangeability_(10,10)=-12.5127;
+	exchangeability_(2,2)=-34.7775;
+	exchangeability_(5,5)=-44.1537;
+	exchangeability_(14,14)=-6.7067;
+	exchangeability_(15,15)=-35.9374;
+	exchangeability_(1,1)=-38.3331;
+	exchangeability_(16,16)=-23.9542;
+	exchangeability_(17,17)=-9.86341;
+	exchangeability_(19,19)=-14.1429;
+	exchangeability_(18,18)=-20.3768;
+}
+
+
+if (getName()=="Intermediate"){
+	exchangeability_(0,0)=-22.206;
+	exchangeability_(4,4)=-27.6779;
+	exchangeability_(6,6)=-12.2404;
+	exchangeability_(3,3)=-13.4913;
+	exchangeability_(7,7)=-10.2577;
+	exchangeability_(13,13)=-30.9922;
+	exchangeability_(9,9)=-33.1003;
+	exchangeability_(8,8)=-26.3402;
+	exchangeability_(11,11)=-15.0386;
+	exchangeability_(12,12)=-31.8325;
+	exchangeability_(10,10)=-26.2339;
+	exchangeability_(2,2)=-24.7962;
+	exchangeability_(5,5)=-21.2091;
+	exchangeability_(14,14)=-5.63953;
+	exchangeability_(15,15)=-32.9139;
+	exchangeability_(1,1)=-15.2228;
+	exchangeability_(16,16)=-25.2855;
+	exchangeability_(17,17)=-11.8186;
+	exchangeability_(19,19)=-31.8113;
+	exchangeability_(18,18)=-30.1707;
+}
+
+
+if (getName()=="HExposed"){
+	exchangeability_(0,0)=-21.4094;
+	exchangeability_(4,4)=-55.2496;
+	exchangeability_(6,6)=-10.3538;
+	exchangeability_(3,3)=-11.0843;
+	exchangeability_(7,7)=-10.5199;
+	exchangeability_(13,13)=-100.659;
+	exchangeability_(9,9)=-103.87;
+	exchangeability_(8,8)=-45.1856;
+	exchangeability_(11,11)=-15.4442;
+	exchangeability_(12,12)=-90.3971;
+	exchangeability_(10,10)=-86.9308;
+	exchangeability_(2,2)=-26.7802;
+	exchangeability_(5,5)=-24.9646;
+	exchangeability_(14,14)=-6.26493;
+	exchangeability_(15,15)=-35.4681;
+	exchangeability_(1,1)=-21.029;
+	exchangeability_(16,16)=-35.4537;
+	exchangeability_(17,17)=-42.1734;
+	exchangeability_(19,19)=-84.2111;
+	exchangeability_(18,18)=-94.4482;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_EX3FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__LLG08_EX3FrequenciesCode
new file mode 100644
index 0000000..ffd4aac
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_EX3FrequenciesCode
@@ -0,0 +1,72 @@
+if (getName()=="Buried"){
+	freq_[0] = 0.123992;
+	freq_[4] = 0.019325;
+	freq_[6] = 0.01594;
+	freq_[3] = 0.015785;
+	freq_[7] = 0.049573;
+	freq_[13] = 0.058363;
+	freq_[9] = 0.126555;
+	freq_[8] = 0.01454;
+	freq_[11] = 0.011084;
+	freq_[12] = 0.037436;
+	freq_[10] = 0.167605;
+	freq_[2] = 0.017595;
+	freq_[5] = 0.015552;
+	freq_[14] = 0.028848;
+	freq_[15] = 0.042324;
+	freq_[1] = 0.016529;
+	freq_[16] = 0.049206;
+	freq_[17] = 0.011962;
+	freq_[19] = 0.139953;
+	freq_[18] = 0.037833;
+}
+
+
+if (getName()=="Intermediate"){
+	freq_[0] = 0.086346;
+	freq_[4] = 0.006655;
+	freq_[6] = 0.09211;
+	freq_[3] = 0.064441;
+	freq_[7] = 0.048527;
+	freq_[13] = 0.025901;
+	freq_[9] = 0.040497;
+	freq_[8] = 0.028831;
+	freq_[11] = 0.079687;
+	freq_[12] = 0.018007;
+	freq_[10] = 0.071679;
+	freq_[2] = 0.041727;
+	freq_[5] = 0.052795;
+	freq_[14] = 0.052632;
+	freq_[15] = 0.052778;
+	freq_[1] = 0.080808;
+	freq_[16] = 0.056138;
+	freq_[17] = 0.010733;
+	freq_[19] = 0.054964;
+	freq_[18] = 0.034744;
+}
+
+
+if (getName()=="HExposed"){
+	freq_[0] = 0.094155;
+	freq_[4] = 0.002213;
+	freq_[6] = 0.165272;
+	freq_[3] = 0.112406;
+	freq_[7] = 0.062302;
+	freq_[13] = 0.006873;
+	freq_[9] = 0.011154;
+	freq_[8] = 0.019853;
+	freq_[11] = 0.10886;
+	freq_[12] = 0.006503;
+	freq_[10] = 0.019829;
+	freq_[2] = 0.0522;
+	freq_[5] = 0.062733;
+	freq_[14] = 0.070091;
+	freq_[15] = 0.057931;
+	freq_[1] = 0.070537;
+	freq_[16] = 0.046183;
+	freq_[17] = 0.002449;
+	freq_[19] = 0.019827;
+	freq_[18] = 0.008629;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_EX3RatesProps b/src/Bpp/Phyl/Model/Protein/__LLG08_EX3RatesProps
new file mode 100644
index 0000000..5846243
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_EX3RatesProps
@@ -0,0 +1,18 @@
+if (getName()=="Buried"){
+	rate_ = 0.5343125;
+	proportion_ = 0.4156;
+}
+
+
+if (getName()=="Intermediate"){
+	rate_ = 1.0464125;
+	proportion_ = 0.3888;
+}
+
+
+if (getName()=="HExposed"){
+	rate_ = 1.8972125;
+	proportion_ = 0.1956;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_UL2ExchangeabilityCode b/src/Bpp/Phyl/Model/Protein/__LLG08_UL2ExchangeabilityCode
new file mode 100644
index 0000000..9bc3404
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_UL2ExchangeabilityCode
@@ -0,0 +1,816 @@
+if (getName()=="M2"){
+	exchangeability_(10,17)=0.31286;
+	exchangeability_(17,10)=0.31286;
+	exchangeability_(6,11)=0.92316;
+	exchangeability_(11,6)=0.92316;
+	exchangeability_(4,7)=1.47057;
+	exchangeability_(7,4)=1.47057;
+	exchangeability_(17,19)=0.07284;
+	exchangeability_(19,17)=0.07284;
+	exchangeability_(9,19)=7.00692;
+	exchangeability_(19,9)=7.00692;
+	exchangeability_(5,6)=6.56836;
+	exchangeability_(6,5)=6.56836;
+	exchangeability_(1,6)=0.74553;
+	exchangeability_(6,1)=0.74553;
+	exchangeability_(0,12)=0.47232;
+	exchangeability_(12,0)=0.47232;
+	exchangeability_(1,2)=0.69873;
+	exchangeability_(2,1)=0.69873;
+	exchangeability_(11,16)=0.62125;
+	exchangeability_(16,11)=0.62125;
+	exchangeability_(1,17)=0.28348;
+	exchangeability_(17,1)=0.28348;
+	exchangeability_(8,15)=0.64518;
+	exchangeability_(15,8)=0.64518;
+	exchangeability_(13,17)=2.09384;
+	exchangeability_(17,13)=2.09384;
+	exchangeability_(10,16)=0.26725;
+	exchangeability_(16,10)=0.26725;
+	exchangeability_(13,15)=0.27955;
+	exchangeability_(15,13)=0.27955;
+	exchangeability_(9,18)=0.07787;
+	exchangeability_(18,9)=0.07787;
+	exchangeability_(2,18)=0.51408;
+	exchangeability_(18,2)=0.51408;
+	exchangeability_(7,9)=0.00879;
+	exchangeability_(9,7)=0.00879;
+	exchangeability_(3,5)=0.42989;
+	exchangeability_(5,3)=0.42989;
+	exchangeability_(3,13)=0.03835;
+	exchangeability_(13,3)=0.03835;
+	exchangeability_(0,10)=0.11336;
+	exchangeability_(10,0)=0.11336;
+	exchangeability_(9,11)=0.08905;
+	exchangeability_(11,9)=0.08905;
+	exchangeability_(8,14)=0.24398;
+	exchangeability_(14,8)=0.24398;
+	exchangeability_(2,8)=6.35003;
+	exchangeability_(8,2)=6.35003;
+	exchangeability_(4,6)=0.0813;
+	exchangeability_(6,4)=0.0813;
+	exchangeability_(8,13)=0.68532;
+	exchangeability_(13,8)=0.68532;
+	exchangeability_(5,7)=0.33875;
+	exchangeability_(7,5)=0.33875;
+	exchangeability_(1,7)=0.3087;
+	exchangeability_(7,1)=0.3087;
+	exchangeability_(4,15)=6.38021;
+	exchangeability_(15,4)=6.38021;
+	exchangeability_(1,14)=0.14251;
+	exchangeability_(14,1)=0.14251;
+	exchangeability_(1,18)=0.15759;
+	exchangeability_(18,1)=0.15759;
+	exchangeability_(11,18)=0.0707;
+	exchangeability_(18,11)=0.0707;
+	exchangeability_(0,5)=0.28025;
+	exchangeability_(5,0)=0.28025;
+	exchangeability_(2,9)=0.18586;
+	exchangeability_(9,2)=0.18586;
+	exchangeability_(7,18)=0.02347;
+	exchangeability_(18,7)=0.02347;
+	exchangeability_(7,14)=0.19769;
+	exchangeability_(14,7)=0.19769;
+	exchangeability_(3,19)=0.06963;
+	exchangeability_(19,3)=0.06963;
+	exchangeability_(5,13)=0.11131;
+	exchangeability_(13,5)=0.11131;
+	exchangeability_(15,19)=0.08623;
+	exchangeability_(19,15)=0.08623;
+	exchangeability_(11,17)=0.0279;
+	exchangeability_(17,11)=0.0279;
+	exchangeability_(7,13)=0.05721;
+	exchangeability_(13,7)=0.05721;
+	exchangeability_(0,2)=0.19295;
+	exchangeability_(2,0)=0.19295;
+	exchangeability_(9,12)=2.97658;
+	exchangeability_(12,9)=2.97658;
+	exchangeability_(3,12)=0.06092;
+	exchangeability_(12,3)=0.06092;
+	exchangeability_(8,19)=0.0577;
+	exchangeability_(19,8)=0.0577;
+	exchangeability_(0,14)=1.17228;
+	exchangeability_(14,0)=1.17228;
+	exchangeability_(5,17)=0.34603;
+	exchangeability_(17,5)=0.34603;
+	exchangeability_(4,10)=0.41485;
+	exchangeability_(10,4)=0.41485;
+	exchangeability_(10,15)=0.09031;
+	exchangeability_(15,10)=0.09031;
+	exchangeability_(14,17)=0.12577;
+	exchangeability_(17,14)=0.12577;
+	exchangeability_(16,18)=0.13355;
+	exchangeability_(18,16)=0.13355;
+	exchangeability_(1,9)=0.05205;
+	exchangeability_(9,1)=0.05205;
+	exchangeability_(4,5)=0.27528;
+	exchangeability_(5,4)=0.27528;
+	exchangeability_(9,10)=2.45114;
+	exchangeability_(10,9)=2.45114;
+	exchangeability_(11,14)=0.09057;
+	exchangeability_(14,11)=0.09057;
+	exchangeability_(8,17)=0.58241;
+	exchangeability_(17,8)=0.58241;
+	exchangeability_(0,15)=9.87276;
+	exchangeability_(15,0)=9.87276;
+	exchangeability_(2,11)=0.8474;
+	exchangeability_(11,2)=0.8474;
+	exchangeability_(10,14)=0.33664;
+	exchangeability_(14,10)=0.33664;
+	exchangeability_(13,16)=0.13775;
+	exchangeability_(16,13)=0.13775;
+	exchangeability_(7,19)=0.06777;
+	exchangeability_(19,7)=0.06777;
+	exchangeability_(3,16)=0.19016;
+	exchangeability_(16,3)=0.19016;
+	exchangeability_(7,12)=0.10385;
+	exchangeability_(12,7)=0.10385;
+	exchangeability_(15,16)=4.44974;
+	exchangeability_(16,15)=4.44974;
+	exchangeability_(14,15)=0.62304;
+	exchangeability_(15,14)=0.62304;
+	exchangeability_(3,11)=0.0625;
+	exchangeability_(11,3)=0.0625;
+	exchangeability_(6,7)=0.5212;
+	exchangeability_(7,6)=0.5212;
+	exchangeability_(8,16)=0.2276;
+	exchangeability_(16,8)=0.2276;
+	exchangeability_(0,1)=0.11595;
+	exchangeability_(1,0)=0.11595;
+	exchangeability_(5,9)=0.11556;
+	exchangeability_(9,5)=0.11556;
+	exchangeability_(12,18)=0.15423;
+	exchangeability_(18,12)=0.15423;
+	exchangeability_(6,16)=0.81303;
+	exchangeability_(16,6)=0.81303;
+	exchangeability_(1,11)=14.9049;
+	exchangeability_(11,1)=14.9049;
+	exchangeability_(2,14)=0.11887;
+	exchangeability_(14,2)=0.11887;
+	exchangeability_(0,4)=2.5945;
+	exchangeability_(4,0)=2.5945;
+	exchangeability_(1,16)=0.44627;
+	exchangeability_(16,1)=0.44627;
+	exchangeability_(6,13)=0.02964;
+	exchangeability_(13,6)=0.02964;
+	exchangeability_(18,19)=0.07198;
+	exchangeability_(19,18)=0.07198;
+	exchangeability_(5,8)=6.67394;
+	exchangeability_(8,5)=6.67394;
+	exchangeability_(16,19)=1.95721;
+	exchangeability_(19,16)=1.95721;
+	exchangeability_(7,16)=0.07281;
+	exchangeability_(16,7)=0.07281;
+	exchangeability_(8,11)=0.27735;
+	exchangeability_(11,8)=0.27735;
+	exchangeability_(3,17)=0.0346;
+	exchangeability_(17,3)=0.0346;
+	exchangeability_(6,17)=0.15619;
+	exchangeability_(17,6)=0.15619;
+	exchangeability_(2,3)=5.17021;
+	exchangeability_(3,2)=5.17021;
+	exchangeability_(3,9)=0.02316;
+	exchangeability_(9,3)=0.02316;
+	exchangeability_(0,16)=2.8212;
+	exchangeability_(16,0)=2.8212;
+	exchangeability_(5,11)=2.96204;
+	exchangeability_(11,5)=2.96204;
+	exchangeability_(4,8)=0.37043;
+	exchangeability_(8,4)=0.37043;
+	exchangeability_(16,17)=0.06502;
+	exchangeability_(17,16)=0.06502;
+	exchangeability_(5,19)=0.24391;
+	exchangeability_(19,5)=0.24391;
+	exchangeability_(1,3)=0.15502;
+	exchangeability_(3,1)=0.15502;
+	exchangeability_(4,19)=1.55466;
+	exchangeability_(19,4)=1.55466;
+	exchangeability_(6,19)=0.37318;
+	exchangeability_(19,6)=0.37318;
+	exchangeability_(1,12)=0.20473;
+	exchangeability_(12,1)=0.20473;
+	exchangeability_(0,6)=0.29564;
+	exchangeability_(6,0)=0.29564;
+	exchangeability_(2,6)=0.47031;
+	exchangeability_(6,2)=0.47031;
+	exchangeability_(1,19)=0.09241;
+	exchangeability_(19,1)=0.09241;
+	exchangeability_(0,17)=0.04695;
+	exchangeability_(17,0)=0.04695;
+	exchangeability_(2,17)=0.07209;
+	exchangeability_(17,2)=0.07209;
+	exchangeability_(7,15)=4.41498;
+	exchangeability_(15,7)=4.41498;
+	exchangeability_(3,14)=0.07071;
+	exchangeability_(14,3)=0.07071;
+	exchangeability_(8,9)=0.06495;
+	exchangeability_(9,8)=0.06495;
+	exchangeability_(3,18)=0.13187;
+	exchangeability_(18,3)=0.13187;
+	exchangeability_(0,3)=0.09498;
+	exchangeability_(3,0)=0.09498;
+	exchangeability_(2,13)=0.12016;
+	exchangeability_(13,2)=0.12016;
+	exchangeability_(0,19)=1.43017;
+	exchangeability_(19,0)=1.43017;
+	exchangeability_(5,12)=2.0146;
+	exchangeability_(12,5)=2.0146;
+	exchangeability_(4,13)=0.71931;
+	exchangeability_(13,4)=0.71931;
+	exchangeability_(10,12)=5.00052;
+	exchangeability_(12,10)=5.00052;
+	exchangeability_(5,18)=0.25408;
+	exchangeability_(18,5)=0.25408;
+	exchangeability_(14,16)=1.14069;
+	exchangeability_(16,14)=1.14069;
+	exchangeability_(1,13)=0.06539;
+	exchangeability_(13,1)=0.06539;
+	exchangeability_(4,16)=2.88312;
+	exchangeability_(16,4)=2.88312;
+	exchangeability_(6,14)=0.14524;
+	exchangeability_(14,6)=0.14524;
+	exchangeability_(11,15)=0.35218;
+	exchangeability_(15,11)=0.35218;
+	exchangeability_(0,7)=6.48722;
+	exchangeability_(7,0)=6.48722;
+	exchangeability_(2,7)=0.46941;
+	exchangeability_(7,2)=0.46941;
+	exchangeability_(8,18)=4.27815;
+	exchangeability_(18,8)=4.27815;
+	exchangeability_(5,10)=0.61336;
+	exchangeability_(10,5)=0.61336;
+	exchangeability_(15,18)=0.21511;
+	exchangeability_(18,15)=0.21511;
+	exchangeability_(12,16)=1.5905;
+	exchangeability_(16,12)=1.5905;
+	exchangeability_(5,14)=0.33265;
+	exchangeability_(14,5)=0.33265;
+	exchangeability_(7,8)=0.0938;
+	exchangeability_(8,7)=0.0938;
+	exchangeability_(15,17)=0.14255;
+	exchangeability_(17,15)=0.14255;
+	exchangeability_(3,7)=0.3984;
+	exchangeability_(7,3)=0.3984;
+	exchangeability_(6,15)=0.61319;
+	exchangeability_(15,6)=0.61319;
+	exchangeability_(12,13)=1.25059;
+	exchangeability_(13,12)=1.25059;
+	exchangeability_(13,14)=0.10451;
+	exchangeability_(14,13)=0.10451;
+	exchangeability_(3,10)=0.0198;
+	exchangeability_(10,3)=0.0198;
+	exchangeability_(0,13)=0.09495;
+	exchangeability_(13,0)=0.09495;
+	exchangeability_(6,12)=0.31715;
+	exchangeability_(12,6)=0.31715;
+	exchangeability_(4,12)=0.71577;
+	exchangeability_(12,4)=0.71577;
+	exchangeability_(9,14)=0.0813;
+	exchangeability_(14,9)=0.0813;
+	exchangeability_(10,11)=0.09627;
+	exchangeability_(11,10)=0.09627;
+	exchangeability_(12,17)=0.37493;
+	exchangeability_(17,12)=0.37493;
+	exchangeability_(2,19)=0.12394;
+	exchangeability_(19,2)=0.12394;
+	exchangeability_(8,10)=0.20224;
+	exchangeability_(10,8)=0.20224;
+	exchangeability_(1,8)=1.2757;
+	exchangeability_(8,1)=1.2757;
+	exchangeability_(1,5)=3.0922;
+	exchangeability_(5,1)=3.0922;
+	exchangeability_(2,5)=1.57271;
+	exchangeability_(5,2)=1.57271;
+	exchangeability_(0,18)=0.06699;
+	exchangeability_(18,0)=0.06699;
+	exchangeability_(13,18)=7.27947;
+	exchangeability_(18,13)=7.27947;
+	exchangeability_(6,10)=0.09789;
+	exchangeability_(10,6)=0.09789;
+	exchangeability_(9,15)=0.06575;
+	exchangeability_(15,9)=0.06575;
+	exchangeability_(2,15)=3.06384;
+	exchangeability_(15,2)=3.06384;
+	exchangeability_(7,17)=0.11459;
+	exchangeability_(17,7)=0.11459;
+	exchangeability_(2,16)=1.36615;
+	exchangeability_(16,2)=1.36615;
+	exchangeability_(12,19)=1.13063;
+	exchangeability_(19,12)=1.13063;
+	exchangeability_(8,12)=0.19202;
+	exchangeability_(12,8)=0.19202;
+	exchangeability_(3,6)=1.53799;
+	exchangeability_(6,3)=1.53799;
+	exchangeability_(4,11)=0.0715;
+	exchangeability_(11,4)=0.0715;
+	exchangeability_(4,18)=0.62652;
+	exchangeability_(18,4)=0.62652;
+	exchangeability_(0,9)=0.04236;
+	exchangeability_(9,0)=0.04236;
+	exchangeability_(4,14)=0.29943;
+	exchangeability_(14,4)=0.29943;
+	exchangeability_(1,15)=0.72036;
+	exchangeability_(15,1)=0.72036;
+	exchangeability_(2,4)=1.13098;
+	exchangeability_(4,2)=1.13098;
+	exchangeability_(11,13)=0.02991;
+	exchangeability_(13,11)=0.02991;
+	exchangeability_(11,12)=0.45471;
+	exchangeability_(12,11)=0.45471;
+	exchangeability_(10,13)=1.61505;
+	exchangeability_(13,10)=1.61505;
+	exchangeability_(12,14)=0.17632;
+	exchangeability_(14,12)=0.17632;
+	exchangeability_(7,10)=0.02832;
+	exchangeability_(10,7)=0.02832;
+	exchangeability_(0,8)=0.12391;
+	exchangeability_(8,0)=0.12391;
+	exchangeability_(3,4)=0.17832;
+	exchangeability_(4,3)=0.17832;
+	exchangeability_(3,8)=1.01748;
+	exchangeability_(8,3)=1.01748;
+	exchangeability_(2,10)=0.0969;
+	exchangeability_(10,2)=0.0969;
+	exchangeability_(17,18)=2.23128;
+	exchangeability_(18,17)=2.23128;
+	exchangeability_(10,18)=0.10931;
+	exchangeability_(18,10)=0.10931;
+	exchangeability_(6,9)=0.08837;
+	exchangeability_(9,6)=0.08837;
+	exchangeability_(4,9)=0.15123;
+	exchangeability_(9,4)=0.15123;
+	exchangeability_(14,19)=0.45871;
+	exchangeability_(19,14)=0.45871;
+	exchangeability_(9,16)=0.8208;
+	exchangeability_(16,9)=0.8208;
+	exchangeability_(12,15)=0.34588;
+	exchangeability_(15,12)=0.34588;
+	exchangeability_(1,4)=0.45611;
+	exchangeability_(4,1)=0.45611;
+	exchangeability_(4,17)=0.37173;
+	exchangeability_(17,4)=0.37173;
+	exchangeability_(0,11)=0.06696;
+	exchangeability_(11,0)=0.06696;
+	exchangeability_(9,13)=0.50729;
+	exchangeability_(13,9)=0.50729;
+	exchangeability_(1,10)=0.18534;
+	exchangeability_(10,1)=0.18534;
+	exchangeability_(11,19)=0.08122;
+	exchangeability_(19,11)=0.08122;
+	exchangeability_(2,12)=0.38496;
+	exchangeability_(12,2)=0.38496;
+	exchangeability_(10,19)=1.05776;
+	exchangeability_(19,10)=1.05776;
+	exchangeability_(6,8)=0.51475;
+	exchangeability_(8,6)=0.51475;
+	exchangeability_(9,17)=0.04382;
+	exchangeability_(17,9)=0.04382;
+	exchangeability_(7,11)=0.1038;
+	exchangeability_(11,7)=0.1038;
+	exchangeability_(3,15)=0.78854;
+	exchangeability_(15,3)=0.78854;
+	exchangeability_(13,19)=0.28261;
+	exchangeability_(19,13)=0.28261;
+	exchangeability_(14,18)=0.07652;
+	exchangeability_(18,14)=0.07652;
+	exchangeability_(6,18)=0.11888;
+	exchangeability_(18,6)=0.11888;
+	exchangeability_(5,16)=0.91372;
+	exchangeability_(16,5)=0.91372;
+	exchangeability_(5,15)=1.17536;
+	exchangeability_(15,5)=1.17536;
+}
+
+
+if (getName()=="M1"){
+	exchangeability_(10,17)=2.26293;
+	exchangeability_(17,10)=2.26293;
+	exchangeability_(6,11)=0.75029;
+	exchangeability_(11,6)=0.75029;
+	exchangeability_(4,7)=1.16523;
+	exchangeability_(7,4)=1.16523;
+	exchangeability_(17,19)=0.41303;
+	exchangeability_(19,17)=0.41303;
+	exchangeability_(9,19)=22.2657;
+	exchangeability_(19,9)=22.2657;
+	exchangeability_(5,6)=2.38374;
+	exchangeability_(6,5)=2.38374;
+	exchangeability_(1,6)=0.11475;
+	exchangeability_(6,1)=0.11475;
+	exchangeability_(0,12)=1.50823;
+	exchangeability_(12,0)=1.50823;
+	exchangeability_(1,2)=0.52385;
+	exchangeability_(2,1)=0.52385;
+	exchangeability_(11,16)=1.17823;
+	exchangeability_(16,11)=1.17823;
+	exchangeability_(1,17)=1.09469;
+	exchangeability_(17,1)=1.09469;
+	exchangeability_(8,15)=1.2781;
+	exchangeability_(15,8)=1.2781;
+	exchangeability_(13,17)=5.67264;
+	exchangeability_(17,13)=5.67264;
+	exchangeability_(10,16)=0.68532;
+	exchangeability_(16,10)=0.68532;
+	exchangeability_(13,15)=1.89114;
+	exchangeability_(15,13)=1.89114;
+	exchangeability_(9,18)=1.35426;
+	exchangeability_(18,9)=1.35426;
+	exchangeability_(2,18)=1.0053;
+	exchangeability_(18,2)=1.0053;
+	exchangeability_(7,9)=0.02665;
+	exchangeability_(9,7)=0.02665;
+	exchangeability_(3,5)=0.35526;
+	exchangeability_(5,3)=0.35526;
+	exchangeability_(3,13)=0.03938;
+	exchangeability_(13,3)=0.03938;
+	exchangeability_(0,10)=0.79159;
+	exchangeability_(10,0)=0.79159;
+	exchangeability_(9,11)=0.83342;
+	exchangeability_(11,9)=0.83342;
+	exchangeability_(8,14)=0.40887;
+	exchangeability_(14,8)=0.40887;
+	exchangeability_(2,8)=5.14046;
+	exchangeability_(8,2)=5.14046;
+	exchangeability_(4,6)=0.09048;
+	exchangeability_(6,4)=0.09048;
+	exchangeability_(8,13)=4.06556;
+	exchangeability_(13,8)=4.06556;
+	exchangeability_(5,7)=0.26136;
+	exchangeability_(7,5)=0.26136;
+	exchangeability_(1,7)=0.33714;
+	exchangeability_(7,1)=0.33714;
+	exchangeability_(4,15)=10.6759;
+	exchangeability_(15,4)=10.6759;
+	exchangeability_(1,14)=0.15837;
+	exchangeability_(14,1)=0.15837;
+	exchangeability_(1,18)=0.43976;
+	exchangeability_(18,1)=0.43976;
+	exchangeability_(11,18)=0.17781;
+	exchangeability_(18,11)=0.17781;
+	exchangeability_(0,5)=1.4535;
+	exchangeability_(5,0)=1.4535;
+	exchangeability_(2,9)=0.55725;
+	exchangeability_(9,2)=0.55725;
+	exchangeability_(7,18)=0.11222;
+	exchangeability_(18,7)=0.11222;
+	exchangeability_(7,14)=0.11868;
+	exchangeability_(14,7)=0.11868;
+	exchangeability_(3,19)=0.08828;
+	exchangeability_(19,3)=0.08828;
+	exchangeability_(5,13)=0.1593;
+	exchangeability_(13,5)=0.1593;
+	exchangeability_(15,19)=0.39684;
+	exchangeability_(19,15)=0.39684;
+	exchangeability_(11,17)=0.10917;
+	exchangeability_(17,11)=0.10917;
+	exchangeability_(7,13)=0.20995;
+	exchangeability_(13,7)=0.20995;
+	exchangeability_(0,2)=0.57443;
+	exchangeability_(2,0)=0.57443;
+	exchangeability_(9,12)=11.1651;
+	exchangeability_(12,9)=11.1651;
+	exchangeability_(3,12)=0.09454;
+	exchangeability_(12,3)=0.09454;
+	exchangeability_(8,19)=0.53086;
+	exchangeability_(19,8)=0.53086;
+	exchangeability_(0,14)=1.25653;
+	exchangeability_(14,0)=1.25653;
+	exchangeability_(5,17)=0.25664;
+	exchangeability_(17,5)=0.25664;
+	exchangeability_(4,10)=4.41464;
+	exchangeability_(10,4)=4.41464;
+	exchangeability_(10,15)=0.68782;
+	exchangeability_(15,10)=0.68782;
+	exchangeability_(14,17)=0.01473;
+	exchangeability_(17,14)=0.01473;
+	exchangeability_(16,18)=0.40308;
+	exchangeability_(18,16)=0.40308;
+	exchangeability_(1,9)=0.73328;
+	exchangeability_(9,1)=0.73328;
+	exchangeability_(4,5)=1.16738;
+	exchangeability_(5,4)=1.16738;
+	exchangeability_(9,10)=7.6743;
+	exchangeability_(10,9)=7.6743;
+	exchangeability_(11,14)=0.18297;
+	exchangeability_(14,11)=0.18297;
+	exchangeability_(8,17)=1.39779;
+	exchangeability_(17,8)=1.39779;
+	exchangeability_(0,15)=3.39029;
+	exchangeability_(15,0)=3.39029;
+	exchangeability_(2,11)=1.94502;
+	exchangeability_(11,2)=1.94502;
+	exchangeability_(10,14)=0.31971;
+	exchangeability_(14,10)=0.31971;
+	exchangeability_(13,16)=0.46665;
+	exchangeability_(16,13)=0.46665;
+	exchangeability_(7,19)=0.16459;
+	exchangeability_(19,7)=0.16459;
+	exchangeability_(3,16)=0.32987;
+	exchangeability_(16,3)=0.32987;
+	exchangeability_(7,12)=0.18286;
+	exchangeability_(12,7)=0.18286;
+	exchangeability_(15,16)=9.44195;
+	exchangeability_(16,15)=9.44195;
+	exchangeability_(14,15)=1.19001;
+	exchangeability_(15,14)=1.19001;
+	exchangeability_(3,11)=0.09409;
+	exchangeability_(11,3)=0.09409;
+	exchangeability_(6,7)=0.24232;
+	exchangeability_(7,6)=0.24232;
+	exchangeability_(8,16)=0.82216;
+	exchangeability_(16,8)=0.82216;
+	exchangeability_(0,1)=0.66769;
+	exchangeability_(1,0)=0.66769;
+	exchangeability_(5,9)=0.52535;
+	exchangeability_(9,5)=0.52535;
+	exchangeability_(12,18)=2.52069;
+	exchangeability_(18,12)=2.52069;
+	exchangeability_(6,16)=0.41585;
+	exchangeability_(16,6)=0.41585;
+	exchangeability_(1,11)=2.71722;
+	exchangeability_(11,1)=2.71722;
+	exchangeability_(2,14)=0.05431;
+	exchangeability_(14,2)=0.05431;
+	exchangeability_(0,4)=1.432;
+	exchangeability_(4,0)=1.432;
+	exchangeability_(1,16)=0.57038;
+	exchangeability_(16,1)=0.57038;
+	exchangeability_(6,13)=0.07666;
+	exchangeability_(13,6)=0.07666;
+	exchangeability_(18,19)=1.13665;
+	exchangeability_(19,18)=1.13665;
+	exchangeability_(5,8)=4.18684;
+	exchangeability_(8,5)=4.18684;
+	exchangeability_(16,19)=3.50436;
+	exchangeability_(19,16)=3.50436;
+	exchangeability_(7,16)=0.13995;
+	exchangeability_(16,7)=0.13995;
+	exchangeability_(8,11)=0.91513;
+	exchangeability_(11,8)=0.91513;
+	exchangeability_(3,17)=0.10173;
+	exchangeability_(17,3)=0.10173;
+	exchangeability_(6,17)=0.06673;
+	exchangeability_(17,6)=0.06673;
+	exchangeability_(2,3)=3.86671;
+	exchangeability_(3,2)=3.86671;
+	exchangeability_(3,9)=0.03351;
+	exchangeability_(9,3)=0.03351;
+	exchangeability_(0,16)=1.76592;
+	exchangeability_(16,0)=1.76592;
+	exchangeability_(5,11)=2.78692;
+	exchangeability_(11,5)=2.78692;
+	exchangeability_(4,8)=5.81398;
+	exchangeability_(8,4)=5.81398;
+	exchangeability_(16,17)=0.34259;
+	exchangeability_(17,16)=0.34259;
+	exchangeability_(5,19)=0.62964;
+	exchangeability_(19,5)=0.62964;
+	exchangeability_(1,3)=0.04021;
+	exchangeability_(3,1)=0.04021;
+	exchangeability_(4,19)=6.11474;
+	exchangeability_(19,4)=6.11474;
+	exchangeability_(6,19)=0.61844;
+	exchangeability_(19,6)=0.61844;
+	exchangeability_(1,12)=1.0412;
+	exchangeability_(12,1)=1.0412;
+	exchangeability_(0,6)=1.4209;
+	exchangeability_(6,0)=1.4209;
+	exchangeability_(2,6)=0.26427;
+	exchangeability_(6,2)=0.26427;
+	exchangeability_(1,19)=0.46387;
+	exchangeability_(19,1)=0.46387;
+	exchangeability_(0,17)=0.33625;
+	exchangeability_(17,0)=0.33625;
+	exchangeability_(2,17)=0.09987;
+	exchangeability_(17,2)=0.09987;
+	exchangeability_(7,15)=1.59368;
+	exchangeability_(15,7)=1.59368;
+	exchangeability_(3,14)=0.18527;
+	exchangeability_(14,3)=0.18527;
+	exchangeability_(8,9)=0.7412;
+	exchangeability_(9,8)=0.7412;
+	exchangeability_(3,18)=0.25214;
+	exchangeability_(18,3)=0.25214;
+	exchangeability_(0,3)=0.74214;
+	exchangeability_(3,0)=0.74214;
+	exchangeability_(2,13)=0.31924;
+	exchangeability_(13,2)=0.31924;
+	exchangeability_(0,19)=3.07198;
+	exchangeability_(19,0)=3.07198;
+	exchangeability_(5,12)=2.44356;
+	exchangeability_(12,5)=2.44356;
+	exchangeability_(4,13)=5.87703;
+	exchangeability_(13,4)=5.87703;
+	exchangeability_(10,12)=15.5726;
+	exchangeability_(12,10)=15.5726;
+	exchangeability_(5,18)=0.23854;
+	exchangeability_(18,5)=0.23854;
+	exchangeability_(14,16)=0.2596;
+	exchangeability_(16,14)=0.2596;
+	exchangeability_(1,13)=0.22241;
+	exchangeability_(13,1)=0.22241;
+	exchangeability_(4,16)=2.03998;
+	exchangeability_(16,4)=2.03998;
+	exchangeability_(6,14)=0.16296;
+	exchangeability_(14,6)=0.16296;
+	exchangeability_(11,15)=0.55672;
+	exchangeability_(15,11)=0.55672;
+	exchangeability_(0,7)=0.70189;
+	exchangeability_(7,0)=0.70189;
+	exchangeability_(2,7)=1.63841;
+	exchangeability_(7,2)=1.63841;
+	exchangeability_(8,18)=11.7578;
+	exchangeability_(18,8)=11.7578;
+	exchangeability_(5,10)=1.98928;
+	exchangeability_(10,5)=1.98928;
+	exchangeability_(15,18)=0.9187;
+	exchangeability_(18,15)=0.9187;
+	exchangeability_(12,16)=3.74567;
+	exchangeability_(16,12)=3.74567;
+	exchangeability_(5,14)=0.33411;
+	exchangeability_(14,5)=0.33411;
+	exchangeability_(7,8)=0.49478;
+	exchangeability_(8,7)=0.49478;
+	exchangeability_(15,17)=0.70987;
+	exchangeability_(17,15)=0.70987;
+	exchangeability_(3,7)=0.71331;
+	exchangeability_(7,3)=0.71331;
+	exchangeability_(6,15)=0.32812;
+	exchangeability_(15,6)=0.32812;
+	exchangeability_(12,13)=4.75393;
+	exchangeability_(13,12)=4.75393;
+	exchangeability_(13,14)=0.12256;
+	exchangeability_(14,13)=0.12256;
+	exchangeability_(3,10)=0.02846;
+	exchangeability_(10,3)=0.02846;
+	exchangeability_(0,13)=0.63403;
+	exchangeability_(13,0)=0.63403;
+	exchangeability_(6,12)=0.24461;
+	exchangeability_(12,6)=0.24461;
+	exchangeability_(4,12)=5.01577;
+	exchangeability_(12,4)=5.01577;
+	exchangeability_(9,14)=0.04377;
+	exchangeability_(14,9)=0.04377;
+	exchangeability_(10,11)=0.51969;
+	exchangeability_(11,10)=0.51969;
+	exchangeability_(12,17)=3.13662;
+	exchangeability_(17,12)=3.13662;
+	exchangeability_(2,19)=0.17154;
+	exchangeability_(19,2)=0.17154;
+	exchangeability_(8,10)=1.52271;
+	exchangeability_(10,8)=1.52271;
+	exchangeability_(1,8)=3.26951;
+	exchangeability_(8,1)=3.26951;
+	exchangeability_(1,5)=2.15316;
+	exchangeability_(5,1)=2.15316;
+	exchangeability_(2,5)=1.32389;
+	exchangeability_(5,2)=1.32389;
+	exchangeability_(0,18)=0.40741;
+	exchangeability_(18,0)=0.40741;
+	exchangeability_(13,18)=31.1708;
+	exchangeability_(18,13)=31.1708;
+	exchangeability_(6,10)=0.1732;
+	exchangeability_(10,6)=0.1732;
+	exchangeability_(9,15)=0.42617;
+	exchangeability_(15,9)=0.42617;
+	exchangeability_(2,15)=4.7877;
+	exchangeability_(15,2)=4.7877;
+	exchangeability_(7,17)=0.4282;
+	exchangeability_(17,7)=0.4282;
+	exchangeability_(2,16)=2.24491;
+	exchangeability_(16,2)=2.24491;
+	exchangeability_(12,19)=4.84074;
+	exchangeability_(19,12)=4.84074;
+	exchangeability_(8,12)=0.72007;
+	exchangeability_(12,8)=0.72007;
+	exchangeability_(3,6)=3.05244;
+	exchangeability_(6,3)=3.05244;
+	exchangeability_(4,11)=0.28044;
+	exchangeability_(11,4)=0.28044;
+	exchangeability_(4,18)=14.6187;
+	exchangeability_(18,4)=14.6187;
+	exchangeability_(0,9)=0.38525;
+	exchangeability_(9,0)=0.38525;
+	exchangeability_(4,14)=0.16104;
+	exchangeability_(14,4)=0.16104;
+	exchangeability_(1,15)=0.71726;
+	exchangeability_(15,1)=0.71726;
+	exchangeability_(2,4)=2.29386;
+	exchangeability_(4,2)=2.29386;
+	exchangeability_(11,13)=0.10255;
+	exchangeability_(13,11)=0.10255;
+	exchangeability_(11,12)=1.40892;
+	exchangeability_(12,11)=1.40892;
+	exchangeability_(10,13)=4.99643;
+	exchangeability_(13,10)=4.99643;
+	exchangeability_(12,14)=0.04785;
+	exchangeability_(14,12)=0.04785;
+	exchangeability_(7,10)=0.08171;
+	exchangeability_(10,7)=0.08171;
+	exchangeability_(0,8)=0.82317;
+	exchangeability_(8,0)=0.82317;
+	exchangeability_(3,4)=0.4908;
+	exchangeability_(4,3)=0.4908;
+	exchangeability_(3,8)=0.85128;
+	exchangeability_(8,3)=0.85128;
+	exchangeability_(2,10)=0.19621;
+	exchangeability_(10,2)=0.19621;
+	exchangeability_(17,18)=6.19857;
+	exchangeability_(18,17)=6.19857;
+	exchangeability_(10,18)=2.11359;
+	exchangeability_(18,10)=2.11359;
+	exchangeability_(6,9)=0.196;
+	exchangeability_(9,6)=0.196;
+	exchangeability_(4,9)=3.33316;
+	exchangeability_(9,4)=3.33316;
+	exchangeability_(14,19)=0.23243;
+	exchangeability_(19,14)=0.23243;
+	exchangeability_(9,16)=4.77994;
+	exchangeability_(16,9)=4.77994;
+	exchangeability_(12,15)=0.78722;
+	exchangeability_(15,12)=0.78722;
+	exchangeability_(1,4)=6.28849;
+	exchangeability_(4,1)=6.28849;
+	exchangeability_(4,17)=6.89787;
+	exchangeability_(17,4)=6.89787;
+	exchangeability_(0,11)=0.89026;
+	exchangeability_(11,0)=0.89026;
+	exchangeability_(9,13)=2.71558;
+	exchangeability_(13,9)=2.71558;
+	exchangeability_(1,10)=1.17988;
+	exchangeability_(10,1)=1.17988;
+	exchangeability_(11,19)=0.52984;
+	exchangeability_(19,11)=0.52984;
+	exchangeability_(2,12)=0.67054;
+	exchangeability_(12,2)=0.67054;
+	exchangeability_(10,19)=3.46086;
+	exchangeability_(19,10)=3.46086;
+	exchangeability_(6,8)=0.33235;
+	exchangeability_(8,6)=0.33235;
+	exchangeability_(9,17)=0.43544;
+	exchangeability_(17,9)=0.43544;
+	exchangeability_(7,11)=0.2539;
+	exchangeability_(11,7)=0.2539;
+	exchangeability_(3,15)=0.85805;
+	exchangeability_(15,3)=0.85805;
+	exchangeability_(13,19)=1.97326;
+	exchangeability_(19,13)=1.97326;
+	exchangeability_(14,18)=0.06297;
+	exchangeability_(18,14)=0.06297;
+	exchangeability_(6,18)=0.15359;
+	exchangeability_(18,6)=0.15359;
+	exchangeability_(5,16)=0.89561;
+	exchangeability_(16,5)=0.89561;
+	exchangeability_(5,15)=0.91728;
+	exchangeability_(15,5)=0.91728;
+}
+
+
+if (getName()=="M2"){
+	exchangeability_(0,0)=-26.3857;
+	exchangeability_(4,4)=-20.7458;
+	exchangeability_(6,6)=-14.411;
+	exchangeability_(3,3)=-10.4725;
+	exchangeability_(7,7)=-15.2813;
+	exchangeability_(13,13)=-15.5022;
+	exchangeability_(9,9)=-14.8529;
+	exchangeability_(8,8)=-23.8769;
+	exchangeability_(11,11)=-22.1334;
+	exchangeability_(12,12)=-17.9212;
+	exchangeability_(10,10)=-13.1092;
+	exchangeability_(2,2)=-22.9496;
+	exchangeability_(5,5)=-28.314;
+	exchangeability_(14,14)=-5.93743;
+	exchangeability_(15,15)=-34.3248;
+	exchangeability_(1,1)=-24.103;
+	exchangeability_(16,16)=-20.9178;
+	exchangeability_(17,17)=-7.49888;
+	exchangeability_(19,19)=-16.2195;
+	exchangeability_(18,18)=-16.5917;
+}
+
+
+if (getName()=="M1"){
+	exchangeability_(0,0)=-22.2535;
+	exchangeability_(4,4)=-78.1715;
+	exchangeability_(6,6)=-11.0877;
+	exchangeability_(3,3)=-12.2175;
+	exchangeability_(7,7)=-8.86683;
+	exchangeability_(13,13)=-65.4691;
+	exchangeability_(9,9)=-58.2253;
+	exchangeability_(8,8)=-45.0726;
+	exchangeability_(11,11)=-16.2326;
+	exchangeability_(12,12)=-59.9007;
+	exchangeability_(10,10)=-48.6709;
+	exchangeability_(2,2)=-27.6778;
+	exchangeability_(5,5)=-24.4614;
+	exchangeability_(14,14)=-5.31674;
+	exchangeability_(15,15)=-41.5528;
+	exchangeability_(1,1)=-22.7331;
+	exchangeability_(16,16)=-34.032;
+	exchangeability_(17,17)=-29.9754;
+	exchangeability_(19,19)=-50.6077;
+	exchangeability_(18,18)=-75.0426;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_UL2FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__LLG08_UL2FrequenciesCode
new file mode 100644
index 0000000..7e5289e
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_UL2FrequenciesCode
@@ -0,0 +1,48 @@
+if (getName()=="M1"){
+	freq_[0] = 0.089881;
+	freq_[4] = 0.002738;
+	freq_[6] = 0.141888;
+	freq_[3] = 0.098515;
+	freq_[7] = 0.072057;
+	freq_[13] = 0.007332;
+	freq_[9] = 0.014026;
+	freq_[8] = 0.021442;
+	freq_[11] = 0.092541;
+	freq_[12] = 0.009278;
+	freq_[10] = 0.030606;
+	freq_[2] = 0.049615;
+	freq_[5] = 0.06222;
+	freq_[14] = 0.07083;
+	freq_[15] = 0.061715;
+	freq_[1] = 0.077329;
+	freq_[16] = 0.055118;
+	freq_[17] = 0.003619;
+	freq_[19] = 0.027701;
+	freq_[18] = 0.011549;
+}
+
+
+if (getName()=="M2"){
+	freq_[0] = 0.107894;
+	freq_[4] = 0.017151;
+	freq_[6] = 0.021895;
+	freq_[3] = 0.021606;
+	freq_[7] = 0.025694;
+	freq_[13] = 0.060355;
+	freq_[9] = 0.11429;
+	freq_[8] = 0.024783;
+	freq_[11] = 0.040631;
+	freq_[12] = 0.035007;
+	freq_[10] = 0.158544;
+	freq_[2] = 0.022494;
+	freq_[5] = 0.020637;
+	freq_[14] = 0.022624;
+	freq_[15] = 0.032806;
+	freq_[1] = 0.035779;
+	freq_[16] = 0.041926;
+	freq_[17] = 0.015774;
+	freq_[19] = 0.125827;
+	freq_[18] = 0.054283;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_UL2RatesProps b/src/Bpp/Phyl/Model/Protein/__LLG08_UL2RatesProps
new file mode 100644
index 0000000..0fd55f8
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_UL2RatesProps
@@ -0,0 +1,12 @@
+if (getName()=="M1"){
+	rate_ = 1.446612;
+	proportion_ = 0.4883;
+}
+
+
+if (getName()=="M2"){
+	rate_ = 0.573812;
+	proportion_ = 0.5117;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_UL3ExchangeabilityCode b/src/Bpp/Phyl/Model/Protein/__LLG08_UL3ExchangeabilityCode
new file mode 100644
index 0000000..face731
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_UL3ExchangeabilityCode
@@ -0,0 +1,1223 @@
+if (getName()=="Q2"){
+	exchangeability_(10,17)=1.8494;
+	exchangeability_(17,10)=1.8494;
+	exchangeability_(6,11)=2.7441;
+	exchangeability_(11,6)=2.7441;
+	exchangeability_(4,7)=1.41842;
+	exchangeability_(7,4)=1.41842;
+	exchangeability_(17,19)=0.84428;
+	exchangeability_(19,17)=0.84428;
+	exchangeability_(9,19)=9.13094;
+	exchangeability_(19,9)=9.13094;
+	exchangeability_(5,6)=6.86001;
+	exchangeability_(6,5)=6.86001;
+	exchangeability_(1,6)=0.35906;
+	exchangeability_(6,1)=0.35906;
+	exchangeability_(0,12)=0.47588;
+	exchangeability_(12,0)=0.47588;
+	exchangeability_(1,2)=0.86045;
+	exchangeability_(2,1)=0.86045;
+	exchangeability_(11,16)=2.02094;
+	exchangeability_(16,11)=2.02094;
+	exchangeability_(1,17)=1.18071;
+	exchangeability_(17,1)=1.18071;
+	exchangeability_(8,15)=1.78662;
+	exchangeability_(15,8)=1.78662;
+	exchangeability_(13,17)=2.47349;
+	exchangeability_(17,13)=2.47349;
+	exchangeability_(10,16)=0.19981;
+	exchangeability_(16,10)=0.19981;
+	exchangeability_(13,15)=0.19909;
+	exchangeability_(15,13)=0.19909;
+	exchangeability_(9,18)=0.57181;
+	exchangeability_(18,9)=0.57181;
+	exchangeability_(2,18)=0.19691;
+	exchangeability_(18,2)=0.19691;
+	exchangeability_(7,9)=0.00249;
+	exchangeability_(9,7)=0.00249;
+	exchangeability_(3,5)=0.79047;
+	exchangeability_(5,3)=0.79047;
+	exchangeability_(3,13)=0.00059;
+	exchangeability_(13,3)=0.00059;
+	exchangeability_(0,10)=0.15094;
+	exchangeability_(10,0)=0.15094;
+	exchangeability_(9,11)=0.04238;
+	exchangeability_(11,9)=0.04238;
+	exchangeability_(8,14)=0.61088;
+	exchangeability_(14,8)=0.61088;
+	exchangeability_(2,8)=8.96563;
+	exchangeability_(8,2)=8.96563;
+	exchangeability_(4,6)=0.12103;
+	exchangeability_(6,4)=0.12103;
+	exchangeability_(8,13)=0.42484;
+	exchangeability_(13,8)=0.42484;
+	exchangeability_(5,7)=0.79604;
+	exchangeability_(7,5)=0.79604;
+	exchangeability_(1,7)=1.05423;
+	exchangeability_(7,1)=1.05423;
+	exchangeability_(4,15)=5.48201;
+	exchangeability_(15,4)=5.48201;
+	exchangeability_(1,14)=1.05131;
+	exchangeability_(14,1)=1.05131;
+	exchangeability_(1,18)=0.47514;
+	exchangeability_(18,1)=0.47514;
+	exchangeability_(11,18)=0.00667;
+	exchangeability_(18,11)=0.00667;
+	exchangeability_(0,5)=3.4257;
+	exchangeability_(5,0)=3.4257;
+	exchangeability_(2,9)=0.01469;
+	exchangeability_(9,2)=0.01469;
+	exchangeability_(7,18)=0.05949;
+	exchangeability_(18,7)=0.05949;
+	exchangeability_(7,14)=0.02332;
+	exchangeability_(14,7)=0.02332;
+	exchangeability_(3,19)=0.00985;
+	exchangeability_(19,3)=0.00985;
+	exchangeability_(5,13)=0.06419;
+	exchangeability_(13,5)=0.06419;
+	exchangeability_(15,19)=0.0428;
+	exchangeability_(19,15)=0.0428;
+	exchangeability_(11,17)=0.00143;
+	exchangeability_(17,11)=0.00143;
+	exchangeability_(7,13)=0.01559;
+	exchangeability_(13,7)=0.01559;
+	exchangeability_(0,2)=0.18431;
+	exchangeability_(2,0)=0.18431;
+	exchangeability_(9,12)=5.75246;
+	exchangeability_(12,9)=5.75246;
+	exchangeability_(3,12)=0.00149;
+	exchangeability_(12,3)=0.00149;
+	exchangeability_(8,19)=0.10542;
+	exchangeability_(19,8)=0.10542;
+	exchangeability_(0,14)=5.43325;
+	exchangeability_(14,0)=5.43325;
+	exchangeability_(5,17)=0.14651;
+	exchangeability_(17,5)=0.14651;
+	exchangeability_(4,10)=1.90354;
+	exchangeability_(10,4)=1.90354;
+	exchangeability_(10,15)=0.06609;
+	exchangeability_(15,10)=0.06609;
+	exchangeability_(14,17)=0.0164;
+	exchangeability_(17,14)=0.0164;
+	exchangeability_(16,18)=0.44179;
+	exchangeability_(18,16)=0.44179;
+	exchangeability_(1,9)=0.02343;
+	exchangeability_(9,1)=0.02343;
+	exchangeability_(4,5)=0.79477;
+	exchangeability_(5,4)=0.79477;
+	exchangeability_(9,10)=5.06621;
+	exchangeability_(10,9)=5.06621;
+	exchangeability_(11,14)=0.60417;
+	exchangeability_(14,11)=0.60417;
+	exchangeability_(8,17)=0.49773;
+	exchangeability_(17,8)=0.49773;
+	exchangeability_(0,15)=6.26711;
+	exchangeability_(15,0)=6.26711;
+	exchangeability_(2,11)=3.64181;
+	exchangeability_(11,2)=3.64181;
+	exchangeability_(10,14)=0.03771;
+	exchangeability_(14,10)=0.03771;
+	exchangeability_(13,16)=0.15076;
+	exchangeability_(16,13)=0.15076;
+	exchangeability_(7,19)=0.12039;
+	exchangeability_(19,7)=0.12039;
+	exchangeability_(3,16)=1.56191;
+	exchangeability_(16,3)=1.56191;
+	exchangeability_(7,12)=0.02422;
+	exchangeability_(12,7)=0.02422;
+	exchangeability_(15,16)=9.88247;
+	exchangeability_(16,15)=9.88247;
+	exchangeability_(14,15)=1.72304;
+	exchangeability_(15,14)=1.72304;
+	exchangeability_(3,11)=0.2783;
+	exchangeability_(11,3)=0.2783;
+	exchangeability_(6,7)=0.64325;
+	exchangeability_(7,6)=0.64325;
+	exchangeability_(8,16)=1.19222;
+	exchangeability_(16,8)=1.19222;
+	exchangeability_(0,1)=1.70948;
+	exchangeability_(1,0)=1.70948;
+	exchangeability_(5,9)=0.00872;
+	exchangeability_(9,5)=0.00872;
+	exchangeability_(12,18)=0.46769;
+	exchangeability_(18,12)=0.46769;
+	exchangeability_(6,16)=1.21053;
+	exchangeability_(16,6)=1.21053;
+	exchangeability_(1,11)=12.9817;
+	exchangeability_(11,1)=12.9817;
+	exchangeability_(2,14)=0.01261;
+	exchangeability_(14,2)=0.01261;
+	exchangeability_(0,4)=4.55449;
+	exchangeability_(4,0)=4.55449;
+	exchangeability_(1,16)=1.82897;
+	exchangeability_(16,1)=1.82897;
+	exchangeability_(6,13)=0.00687;
+	exchangeability_(13,6)=0.00687;
+	exchangeability_(18,19)=2.32768;
+	exchangeability_(19,18)=2.32768;
+	exchangeability_(5,8)=11.0583;
+	exchangeability_(8,5)=11.0583;
+	exchangeability_(16,19)=3.28417;
+	exchangeability_(19,16)=3.28417;
+	exchangeability_(7,16)=0.21798;
+	exchangeability_(16,7)=0.21798;
+	exchangeability_(8,11)=1.68649;
+	exchangeability_(11,8)=1.68649;
+	exchangeability_(3,17)=0.01722;
+	exchangeability_(17,3)=0.01722;
+	exchangeability_(6,17)=0.06852;
+	exchangeability_(17,6)=0.06852;
+	exchangeability_(2,3)=4.47138;
+	exchangeability_(3,2)=4.47138;
+	exchangeability_(3,9)=0.0022;
+	exchangeability_(9,3)=0.0022;
+	exchangeability_(0,16)=6.38946;
+	exchangeability_(16,0)=6.38946;
+	exchangeability_(5,11)=7.67761;
+	exchangeability_(11,5)=7.67761;
+	exchangeability_(4,8)=2.03335;
+	exchangeability_(8,4)=2.03335;
+	exchangeability_(16,17)=0.19029;
+	exchangeability_(17,16)=0.19029;
+	exchangeability_(5,19)=0.29617;
+	exchangeability_(19,5)=0.29617;
+	exchangeability_(1,3)=0.18207;
+	exchangeability_(3,1)=0.18207;
+	exchangeability_(4,19)=5.74324;
+	exchangeability_(19,4)=5.74324;
+	exchangeability_(6,19)=0.41347;
+	exchangeability_(19,6)=0.41347;
+	exchangeability_(1,12)=0.36458;
+	exchangeability_(12,1)=0.36458;
+	exchangeability_(0,6)=4.27884;
+	exchangeability_(6,0)=4.27884;
+	exchangeability_(2,6)=0.58503;
+	exchangeability_(6,2)=0.58503;
+	exchangeability_(1,19)=0.29856;
+	exchangeability_(19,1)=0.29856;
+	exchangeability_(0,17)=0.28169;
+	exchangeability_(17,0)=0.28169;
+	exchangeability_(2,17)=1e-05;
+	exchangeability_(17,2)=1e-05;
+	exchangeability_(7,15)=0.94372;
+	exchangeability_(15,7)=0.94372;
+	exchangeability_(3,14)=0.02727;
+	exchangeability_(14,3)=0.02727;
+	exchangeability_(8,9)=0.04673;
+	exchangeability_(9,8)=0.04673;
+	exchangeability_(3,18)=0.06762;
+	exchangeability_(18,3)=0.06762;
+	exchangeability_(0,3)=0.66085;
+	exchangeability_(3,0)=0.66085;
+	exchangeability_(2,13)=0.0065;
+	exchangeability_(13,2)=0.0065;
+	exchangeability_(0,19)=11.333;
+	exchangeability_(19,0)=11.333;
+	exchangeability_(5,12)=0.75473;
+	exchangeability_(12,5)=0.75473;
+	exchangeability_(4,13)=5.3977;
+	exchangeability_(13,4)=5.3977;
+	exchangeability_(10,12)=12.0198;
+	exchangeability_(12,10)=12.0198;
+	exchangeability_(5,18)=0.57634;
+	exchangeability_(18,5)=0.57634;
+	exchangeability_(14,16)=1.72757;
+	exchangeability_(16,14)=1.72757;
+	exchangeability_(1,13)=0.05125;
+	exchangeability_(13,1)=0.05125;
+	exchangeability_(4,16)=2.08363;
+	exchangeability_(16,4)=2.08363;
+	exchangeability_(6,14)=0.84943;
+	exchangeability_(14,6)=0.84943;
+	exchangeability_(11,15)=0.81389;
+	exchangeability_(15,11)=0.81389;
+	exchangeability_(0,7)=0.62571;
+	exchangeability_(7,0)=0.62571;
+	exchangeability_(2,7)=1.22244;
+	exchangeability_(7,2)=1.22244;
+	exchangeability_(8,18)=4.52551;
+	exchangeability_(18,8)=4.52551;
+	exchangeability_(5,10)=0.38441;
+	exchangeability_(10,5)=0.38441;
+	exchangeability_(15,18)=0.39439;
+	exchangeability_(18,15)=0.39439;
+	exchangeability_(12,16)=1.2381;
+	exchangeability_(16,12)=1.2381;
+	exchangeability_(5,14)=1.76579;
+	exchangeability_(14,5)=1.76579;
+	exchangeability_(7,8)=0.5232;
+	exchangeability_(8,7)=0.5232;
+	exchangeability_(15,17)=0.28855;
+	exchangeability_(17,15)=0.28855;
+	exchangeability_(3,7)=0.49237;
+	exchangeability_(7,3)=0.49237;
+	exchangeability_(6,15)=0.59589;
+	exchangeability_(15,6)=0.59589;
+	exchangeability_(12,13)=1.77906;
+	exchangeability_(13,12)=1.77906;
+	exchangeability_(13,14)=0.0032;
+	exchangeability_(14,13)=0.0032;
+	exchangeability_(3,10)=0.00021;
+	exchangeability_(10,3)=0.00021;
+	exchangeability_(0,13)=0.14213;
+	exchangeability_(13,0)=0.14213;
+	exchangeability_(6,12)=0.04104;
+	exchangeability_(12,6)=0.04104;
+	exchangeability_(4,12)=3.89083;
+	exchangeability_(12,4)=3.89083;
+	exchangeability_(9,14)=0.00018;
+	exchangeability_(14,9)=0.00018;
+	exchangeability_(10,11)=0.02386;
+	exchangeability_(11,10)=0.02386;
+	exchangeability_(12,17)=1.39485;
+	exchangeability_(17,12)=1.39485;
+	exchangeability_(2,19)=0.05367;
+	exchangeability_(19,2)=0.05367;
+	exchangeability_(8,10)=0.21072;
+	exchangeability_(10,8)=0.21072;
+	exchangeability_(1,8)=6.3962;
+	exchangeability_(8,1)=6.3962;
+	exchangeability_(1,5)=6.09236;
+	exchangeability_(5,1)=6.09236;
+	exchangeability_(2,5)=2.86839;
+	exchangeability_(5,2)=2.86839;
+	exchangeability_(0,18)=0.30264;
+	exchangeability_(18,0)=0.30264;
+	exchangeability_(13,18)=8.10789;
+	exchangeability_(18,13)=8.10789;
+	exchangeability_(6,10)=0.01513;
+	exchangeability_(10,6)=0.01513;
+	exchangeability_(9,15)=0.04338;
+	exchangeability_(15,9)=0.04338;
+	exchangeability_(2,15)=5.98604;
+	exchangeability_(15,2)=5.98604;
+	exchangeability_(7,17)=0.22242;
+	exchangeability_(17,7)=0.22242;
+	exchangeability_(2,16)=2.0446;
+	exchangeability_(16,2)=2.0446;
+	exchangeability_(12,19)=4.41798;
+	exchangeability_(19,12)=4.41798;
+	exchangeability_(8,12)=0.23696;
+	exchangeability_(12,8)=0.23696;
+	exchangeability_(3,6)=4.17614;
+	exchangeability_(6,3)=4.17614;
+	exchangeability_(4,11)=0.0366;
+	exchangeability_(11,4)=0.0366;
+	exchangeability_(4,18)=6.35546;
+	exchangeability_(18,4)=6.35546;
+	exchangeability_(0,9)=0.02455;
+	exchangeability_(9,0)=0.02455;
+	exchangeability_(4,14)=0.63518;
+	exchangeability_(14,4)=0.63518;
+	exchangeability_(1,15)=1.75001;
+	exchangeability_(15,1)=1.75001;
+	exchangeability_(2,4)=1.80107;
+	exchangeability_(4,2)=1.80107;
+	exchangeability_(11,13)=0.02142;
+	exchangeability_(13,11)=0.02142;
+	exchangeability_(11,12)=0.2299;
+	exchangeability_(12,11)=0.2299;
+	exchangeability_(10,13)=5.45828;
+	exchangeability_(13,10)=5.45828;
+	exchangeability_(12,14)=0.00142;
+	exchangeability_(14,12)=0.00142;
+	exchangeability_(7,10)=0.01025;
+	exchangeability_(10,7)=0.01025;
+	exchangeability_(0,8)=1.08912;
+	exchangeability_(8,0)=1.08912;
+	exchangeability_(3,4)=1.06873;
+	exchangeability_(4,3)=1.06873;
+	exchangeability_(3,8)=1.91525;
+	exchangeability_(8,3)=1.91525;
+	exchangeability_(2,10)=0.00251;
+	exchangeability_(10,2)=0.00251;
+	exchangeability_(17,18)=4.06783;
+	exchangeability_(18,17)=4.06783;
+	exchangeability_(10,18)=1.19458;
+	exchangeability_(18,10)=1.19458;
+	exchangeability_(6,9)=0.00836;
+	exchangeability_(9,6)=0.00836;
+	exchangeability_(4,9)=0.62882;
+	exchangeability_(9,4)=0.62882;
+	exchangeability_(14,19)=0.49298;
+	exchangeability_(19,14)=0.49298;
+	exchangeability_(9,16)=0.51545;
+	exchangeability_(16,9)=0.51545;
+	exchangeability_(12,15)=0.05356;
+	exchangeability_(15,12)=0.05356;
+	exchangeability_(1,4)=2.84344;
+	exchangeability_(4,1)=2.84344;
+	exchangeability_(4,17)=3.69642;
+	exchangeability_(17,4)=3.69642;
+	exchangeability_(0,11)=1.75131;
+	exchangeability_(11,0)=1.75131;
+	exchangeability_(9,13)=1.00534;
+	exchangeability_(13,9)=1.00534;
+	exchangeability_(1,10)=0.14052;
+	exchangeability_(10,1)=0.14052;
+	exchangeability_(11,19)=0.16529;
+	exchangeability_(19,11)=0.16529;
+	exchangeability_(2,12)=0.06314;
+	exchangeability_(12,2)=0.06314;
+	exchangeability_(10,19)=2.67496;
+	exchangeability_(19,10)=2.67496;
+	exchangeability_(6,8)=0.76816;
+	exchangeability_(8,6)=0.76816;
+	exchangeability_(9,17)=0.19983;
+	exchangeability_(17,9)=0.19983;
+	exchangeability_(7,11)=0.61273;
+	exchangeability_(11,7)=0.61273;
+	exchangeability_(3,15)=1.41195;
+	exchangeability_(15,3)=1.41195;
+	exchangeability_(13,19)=1.81116;
+	exchangeability_(19,13)=1.81116;
+	exchangeability_(14,18)=0.02456;
+	exchangeability_(18,14)=0.02456;
+	exchangeability_(6,18)=0.23283;
+	exchangeability_(18,6)=0.23283;
+	exchangeability_(5,16)=2.07012;
+	exchangeability_(16,5)=2.07012;
+	exchangeability_(5,15)=1.92397;
+	exchangeability_(15,5)=1.92397;
+}
+
+
+if (getName()=="Q3"){
+	exchangeability_(10,17)=0.12735;
+	exchangeability_(17,10)=0.12735;
+	exchangeability_(6,11)=0.64999;
+	exchangeability_(11,6)=0.64999;
+	exchangeability_(4,7)=0.89112;
+	exchangeability_(7,4)=0.89112;
+	exchangeability_(17,19)=0.06015;
+	exchangeability_(19,17)=0.06015;
+	exchangeability_(9,19)=8.41592;
+	exchangeability_(19,9)=8.41592;
+	exchangeability_(5,6)=4.706;
+	exchangeability_(6,5)=4.706;
+	exchangeability_(1,6)=0.45384;
+	exchangeability_(6,1)=0.45384;
+	exchangeability_(0,12)=0.59973;
+	exchangeability_(12,0)=0.59973;
+	exchangeability_(1,2)=0.52868;
+	exchangeability_(2,1)=0.52868;
+	exchangeability_(11,16)=0.46108;
+	exchangeability_(16,11)=0.46108;
+	exchangeability_(1,17)=0.37874;
+	exchangeability_(17,1)=0.37874;
+	exchangeability_(8,15)=0.72003;
+	exchangeability_(15,8)=0.72003;
+	exchangeability_(13,17)=3.07724;
+	exchangeability_(17,13)=3.07724;
+	exchangeability_(10,16)=0.38167;
+	exchangeability_(16,10)=0.38167;
+	exchangeability_(13,15)=0.78872;
+	exchangeability_(15,13)=0.78872;
+	exchangeability_(9,18)=0.09463;
+	exchangeability_(18,9)=0.09463;
+	exchangeability_(2,18)=1.45328;
+	exchangeability_(18,2)=1.45328;
+	exchangeability_(7,9)=0.00394;
+	exchangeability_(9,7)=0.00394;
+	exchangeability_(3,5)=0.41758;
+	exchangeability_(5,3)=0.41758;
+	exchangeability_(3,13)=0.08928;
+	exchangeability_(13,3)=0.08928;
+	exchangeability_(0,10)=0.14642;
+	exchangeability_(10,0)=0.14642;
+	exchangeability_(9,11)=0.09486;
+	exchangeability_(11,9)=0.09486;
+	exchangeability_(8,14)=0.3861;
+	exchangeability_(14,8)=0.3861;
+	exchangeability_(2,8)=5.52381;
+	exchangeability_(8,2)=5.52381;
+	exchangeability_(4,6)=0.0458;
+	exchangeability_(6,4)=0.0458;
+	exchangeability_(8,13)=1.50809;
+	exchangeability_(13,8)=1.50809;
+	exchangeability_(5,7)=0.14845;
+	exchangeability_(7,5)=0.14845;
+	exchangeability_(1,7)=0.17442;
+	exchangeability_(7,1)=0.17442;
+	exchangeability_(4,15)=5.60173;
+	exchangeability_(15,4)=5.60173;
+	exchangeability_(1,14)=0.22555;
+	exchangeability_(14,1)=0.22555;
+	exchangeability_(1,18)=0.36679;
+	exchangeability_(18,1)=0.36679;
+	exchangeability_(11,18)=0.14872;
+	exchangeability_(18,11)=0.14872;
+	exchangeability_(0,5)=0.16902;
+	exchangeability_(5,0)=0.16902;
+	exchangeability_(2,9)=0.22244;
+	exchangeability_(9,2)=0.22244;
+	exchangeability_(7,18)=0.05594;
+	exchangeability_(18,7)=0.05594;
+	exchangeability_(7,14)=0.16642;
+	exchangeability_(14,7)=0.16642;
+	exchangeability_(3,19)=0.08422;
+	exchangeability_(19,3)=0.08422;
+	exchangeability_(5,13)=0.26091;
+	exchangeability_(13,5)=0.26091;
+	exchangeability_(15,19)=0.09441;
+	exchangeability_(19,15)=0.09441;
+	exchangeability_(11,17)=0.02778;
+	exchangeability_(17,11)=0.02778;
+	exchangeability_(7,13)=0.10188;
+	exchangeability_(13,7)=0.10188;
+	exchangeability_(0,2)=0.11895;
+	exchangeability_(2,0)=0.11895;
+	exchangeability_(9,12)=3.02011;
+	exchangeability_(12,9)=3.02011;
+	exchangeability_(3,12)=0.0594;
+	exchangeability_(12,3)=0.0594;
+	exchangeability_(8,19)=0.03877;
+	exchangeability_(19,8)=0.03877;
+	exchangeability_(0,14)=0.37813;
+	exchangeability_(14,0)=0.37813;
+	exchangeability_(5,17)=0.27791;
+	exchangeability_(17,5)=0.27791;
+	exchangeability_(4,10)=0.44843;
+	exchangeability_(10,4)=0.44843;
+	exchangeability_(10,15)=0.12178;
+	exchangeability_(15,10)=0.12178;
+	exchangeability_(14,17)=0.1633;
+	exchangeability_(17,14)=0.1633;
+	exchangeability_(16,18)=0.24783;
+	exchangeability_(18,16)=0.24783;
+	exchangeability_(1,9)=0.06517;
+	exchangeability_(9,1)=0.06517;
+	exchangeability_(4,5)=0.17049;
+	exchangeability_(5,4)=0.17049;
+	exchangeability_(9,10)=2.38709;
+	exchangeability_(10,9)=2.38709;
+	exchangeability_(11,14)=0.18272;
+	exchangeability_(14,11)=0.18272;
+	exchangeability_(8,17)=0.42038;
+	exchangeability_(17,8)=0.42038;
+	exchangeability_(0,15)=8.34009;
+	exchangeability_(15,0)=8.34009;
+	exchangeability_(2,11)=0.78376;
+	exchangeability_(11,2)=0.78376;
+	exchangeability_(10,14)=0.75359;
+	exchangeability_(14,10)=0.75359;
+	exchangeability_(13,16)=0.25512;
+	exchangeability_(16,13)=0.25512;
+	exchangeability_(7,19)=0.04751;
+	exchangeability_(19,7)=0.04751;
+	exchangeability_(3,16)=0.09312;
+	exchangeability_(16,3)=0.09312;
+	exchangeability_(7,12)=0.08921;
+	exchangeability_(12,7)=0.08921;
+	exchangeability_(15,16)=3.45089;
+	exchangeability_(16,15)=3.45089;
+	exchangeability_(14,15)=0.89078;
+	exchangeability_(15,14)=0.89078;
+	exchangeability_(3,11)=0.04984;
+	exchangeability_(11,3)=0.04984;
+	exchangeability_(6,7)=0.19521;
+	exchangeability_(7,6)=0.19521;
+	exchangeability_(8,16)=0.21105;
+	exchangeability_(16,8)=0.21105;
+	exchangeability_(0,1)=0.06362;
+	exchangeability_(1,0)=0.06362;
+	exchangeability_(5,9)=0.12257;
+	exchangeability_(9,5)=0.12257;
+	exchangeability_(12,18)=0.36973;
+	exchangeability_(18,12)=0.36973;
+	exchangeability_(6,16)=0.59723;
+	exchangeability_(16,6)=0.59723;
+	exchangeability_(1,11)=11.0823;
+	exchangeability_(11,1)=11.0823;
+	exchangeability_(2,14)=0.18192;
+	exchangeability_(14,2)=0.18192;
+	exchangeability_(0,4)=2.01038;
+	exchangeability_(4,0)=2.01038;
+	exchangeability_(1,16)=0.35878;
+	exchangeability_(16,1)=0.35878;
+	exchangeability_(6,13)=0.10151;
+	exchangeability_(13,6)=0.10151;
+	exchangeability_(18,19)=0.07659;
+	exchangeability_(19,18)=0.07659;
+	exchangeability_(5,8)=4.73492;
+	exchangeability_(8,5)=4.73492;
+	exchangeability_(16,19)=1.48341;
+	exchangeability_(19,16)=1.48341;
+	exchangeability_(7,16)=0.01955;
+	exchangeability_(16,7)=0.01955;
+	exchangeability_(8,11)=0.27101;
+	exchangeability_(11,8)=0.27101;
+	exchangeability_(3,17)=0.0083;
+	exchangeability_(17,3)=0.0083;
+	exchangeability_(6,17)=0.12204;
+	exchangeability_(17,6)=0.12204;
+	exchangeability_(2,3)=12.0923;
+	exchangeability_(3,2)=12.0923;
+	exchangeability_(3,9)=0.02306;
+	exchangeability_(9,3)=0.02306;
+	exchangeability_(0,16)=1.93234;
+	exchangeability_(16,0)=1.93234;
+	exchangeability_(5,11)=1.82816;
+	exchangeability_(11,5)=1.82816;
+	exchangeability_(4,8)=0.21155;
+	exchangeability_(8,4)=0.21155;
+	exchangeability_(16,17)=0.06265;
+	exchangeability_(17,16)=0.06265;
+	exchangeability_(5,19)=0.17536;
+	exchangeability_(19,5)=0.17536;
+	exchangeability_(1,3)=0.14268;
+	exchangeability_(3,1)=0.14268;
+	exchangeability_(4,19)=1.28083;
+	exchangeability_(19,4)=1.28083;
+	exchangeability_(6,19)=0.34258;
+	exchangeability_(19,6)=0.34258;
+	exchangeability_(1,12)=0.23055;
+	exchangeability_(12,1)=0.23055;
+	exchangeability_(0,6)=0.17288;
+	exchangeability_(6,0)=0.17288;
+	exchangeability_(2,6)=0.45443;
+	exchangeability_(6,2)=0.45443;
+	exchangeability_(1,19)=0.06929;
+	exchangeability_(19,1)=0.06929;
+	exchangeability_(0,17)=0.03142;
+	exchangeability_(17,0)=0.03142;
+	exchangeability_(2,17)=0.08559;
+	exchangeability_(17,2)=0.08559;
+	exchangeability_(7,15)=2.53201;
+	exchangeability_(15,7)=2.53201;
+	exchangeability_(3,14)=0.03828;
+	exchangeability_(14,3)=0.03828;
+	exchangeability_(8,9)=0.06526;
+	exchangeability_(9,8)=0.06526;
+	exchangeability_(3,18)=0.40479;
+	exchangeability_(18,3)=0.40479;
+	exchangeability_(0,3)=0.0655;
+	exchangeability_(3,0)=0.0655;
+	exchangeability_(2,13)=0.40881;
+	exchangeability_(13,2)=0.40881;
+	exchangeability_(0,19)=1.10485;
+	exchangeability_(19,0)=1.10485;
+	exchangeability_(5,12)=2.76535;
+	exchangeability_(12,5)=2.76535;
+	exchangeability_(4,13)=0.72442;
+	exchangeability_(13,4)=0.72442;
+	exchangeability_(10,12)=2.80693;
+	exchangeability_(12,10)=2.80693;
+	exchangeability_(5,18)=0.47502;
+	exchangeability_(18,5)=0.47502;
+	exchangeability_(14,16)=0.60457;
+	exchangeability_(16,14)=0.60457;
+	exchangeability_(1,13)=0.14524;
+	exchangeability_(13,1)=0.14524;
+	exchangeability_(4,16)=2.02867;
+	exchangeability_(16,4)=2.02867;
+	exchangeability_(6,14)=0.15177;
+	exchangeability_(14,6)=0.15177;
+	exchangeability_(11,15)=0.2797;
+	exchangeability_(15,11)=0.2797;
+	exchangeability_(0,7)=5.25455;
+	exchangeability_(7,0)=5.25455;
+	exchangeability_(2,7)=0.36489;
+	exchangeability_(7,2)=0.36489;
+	exchangeability_(8,18)=7.3673;
+	exchangeability_(18,8)=7.3673;
+	exchangeability_(5,10)=0.79559;
+	exchangeability_(10,5)=0.79559;
+	exchangeability_(15,18)=0.6768;
+	exchangeability_(18,15)=0.6768;
+	exchangeability_(12,16)=2.13145;
+	exchangeability_(16,12)=2.13145;
+	exchangeability_(5,14)=0.5111;
+	exchangeability_(14,5)=0.5111;
+	exchangeability_(7,8)=0.09653;
+	exchangeability_(8,7)=0.09653;
+	exchangeability_(15,17)=0.17711;
+	exchangeability_(17,15)=0.17711;
+	exchangeability_(3,7)=0.19279;
+	exchangeability_(7,3)=0.19279;
+	exchangeability_(6,15)=0.41526;
+	exchangeability_(15,6)=0.41526;
+	exchangeability_(12,13)=1.88704;
+	exchangeability_(13,12)=1.88704;
+	exchangeability_(13,14)=0.3412;
+	exchangeability_(14,13)=0.3412;
+	exchangeability_(3,10)=0.02817;
+	exchangeability_(10,3)=0.02817;
+	exchangeability_(0,13)=0.14889;
+	exchangeability_(13,0)=0.14889;
+	exchangeability_(6,12)=0.39157;
+	exchangeability_(12,6)=0.39157;
+	exchangeability_(4,12)=0.69953;
+	exchangeability_(12,4)=0.69953;
+	exchangeability_(9,14)=0.18612;
+	exchangeability_(14,9)=0.18612;
+	exchangeability_(10,11)=0.1407;
+	exchangeability_(11,10)=0.1407;
+	exchangeability_(12,17)=0.1391;
+	exchangeability_(17,12)=0.1391;
+	exchangeability_(2,19)=0.11015;
+	exchangeability_(19,2)=0.11015;
+	exchangeability_(8,10)=0.24002;
+	exchangeability_(10,8)=0.24002;
+	exchangeability_(1,8)=1.25884;
+	exchangeability_(8,1)=1.25884;
+	exchangeability_(1,5)=2.02618;
+	exchangeability_(5,1)=2.02618;
+	exchangeability_(2,5)=1.25602;
+	exchangeability_(5,2)=1.25602;
+	exchangeability_(0,18)=0.10628;
+	exchangeability_(18,0)=0.10628;
+	exchangeability_(13,18)=5.25176;
+	exchangeability_(18,13)=5.25176;
+	exchangeability_(6,10)=0.14601;
+	exchangeability_(10,6)=0.14601;
+	exchangeability_(9,15)=0.06786;
+	exchangeability_(15,9)=0.06786;
+	exchangeability_(2,15)=3.01076;
+	exchangeability_(15,2)=3.01076;
+	exchangeability_(7,17)=0.05525;
+	exchangeability_(17,7)=0.05525;
+	exchangeability_(2,16)=1.069;
+	exchangeability_(16,2)=1.069;
+	exchangeability_(12,19)=1.53798;
+	exchangeability_(19,12)=1.53798;
+	exchangeability_(8,12)=0.20619;
+	exchangeability_(12,8)=0.20619;
+	exchangeability_(3,6)=1.88216;
+	exchangeability_(6,3)=1.88216;
+	exchangeability_(4,11)=0.03962;
+	exchangeability_(11,4)=0.03962;
+	exchangeability_(4,18)=0.75305;
+	exchangeability_(18,4)=0.75305;
+	exchangeability_(0,9)=0.03491;
+	exchangeability_(9,0)=0.03491;
+	exchangeability_(4,14)=0.14638;
+	exchangeability_(14,4)=0.14638;
+	exchangeability_(1,15)=0.49556;
+	exchangeability_(15,1)=0.49556;
+	exchangeability_(2,4)=1.12769;
+	exchangeability_(4,2)=1.12769;
+	exchangeability_(11,13)=0.06188;
+	exchangeability_(13,11)=0.06188;
+	exchangeability_(11,12)=0.51676;
+	exchangeability_(12,11)=0.51676;
+	exchangeability_(10,13)=0.70993;
+	exchangeability_(13,10)=0.70993;
+	exchangeability_(12,14)=0.42013;
+	exchangeability_(14,12)=0.42013;
+	exchangeability_(7,10)=0.01672;
+	exchangeability_(10,7)=0.01672;
+	exchangeability_(0,8)=0.09059;
+	exchangeability_(8,0)=0.09059;
+	exchangeability_(3,4)=0.01455;
+	exchangeability_(4,3)=0.01455;
+	exchangeability_(3,8)=0.31349;
+	exchangeability_(8,3)=0.31349;
+	exchangeability_(2,10)=0.13613;
+	exchangeability_(10,2)=0.13613;
+	exchangeability_(17,18)=2.9105;
+	exchangeability_(18,17)=2.9105;
+	exchangeability_(10,18)=0.12675;
+	exchangeability_(18,10)=0.12675;
+	exchangeability_(6,9)=0.07552;
+	exchangeability_(9,6)=0.07552;
+	exchangeability_(4,9)=0.13223;
+	exchangeability_(9,4)=0.13223;
+	exchangeability_(14,19)=0.30903;
+	exchangeability_(19,14)=0.30903;
+	exchangeability_(9,16)=0.87034;
+	exchangeability_(16,9)=0.87034;
+	exchangeability_(12,15)=0.62608;
+	exchangeability_(15,12)=0.62608;
+	exchangeability_(1,4)=0.30235;
+	exchangeability_(4,1)=0.30235;
+	exchangeability_(4,17)=0.27763;
+	exchangeability_(17,4)=0.27763;
+	exchangeability_(0,11)=0.04112;
+	exchangeability_(11,0)=0.04112;
+	exchangeability_(9,13)=0.69342;
+	exchangeability_(13,9)=0.69342;
+	exchangeability_(1,10)=0.219;
+	exchangeability_(10,1)=0.219;
+	exchangeability_(11,19)=0.05453;
+	exchangeability_(19,11)=0.05453;
+	exchangeability_(2,12)=0.59564;
+	exchangeability_(12,2)=0.59564;
+	exchangeability_(10,19)=1.57757;
+	exchangeability_(19,10)=1.57757;
+	exchangeability_(6,8)=0.46681;
+	exchangeability_(8,6)=0.46681;
+	exchangeability_(9,17)=0.02197;
+	exchangeability_(17,9)=0.02197;
+	exchangeability_(7,11)=0.0692;
+	exchangeability_(11,7)=0.0692;
+	exchangeability_(3,15)=0.46357;
+	exchangeability_(15,3)=0.46357;
+	exchangeability_(13,19)=0.40962;
+	exchangeability_(19,13)=0.40962;
+	exchangeability_(14,18)=0.23255;
+	exchangeability_(18,14)=0.23255;
+	exchangeability_(6,18)=0.27399;
+	exchangeability_(18,6)=0.27399;
+	exchangeability_(5,16)=0.63786;
+	exchangeability_(16,5)=0.63786;
+	exchangeability_(5,15)=0.98508;
+	exchangeability_(15,5)=0.98508;
+}
+
+
+if (getName()=="Q1"){
+	exchangeability_(10,17)=1.73819;
+	exchangeability_(17,10)=1.73819;
+	exchangeability_(6,11)=0.57918;
+	exchangeability_(11,6)=0.57918;
+	exchangeability_(4,7)=2.62791;
+	exchangeability_(7,4)=2.62791;
+	exchangeability_(17,19)=0.25217;
+	exchangeability_(19,17)=0.25217;
+	exchangeability_(9,19)=13.9066;
+	exchangeability_(19,9)=13.9066;
+	exchangeability_(5,6)=1.8853;
+	exchangeability_(6,5)=1.8853;
+	exchangeability_(1,6)=0.08492;
+	exchangeability_(6,1)=0.08492;
+	exchangeability_(0,12)=0.99008;
+	exchangeability_(12,0)=0.99008;
+	exchangeability_(1,2)=0.5834;
+	exchangeability_(2,1)=0.5834;
+	exchangeability_(11,16)=0.95394;
+	exchangeability_(16,11)=0.95394;
+	exchangeability_(1,17)=0.51475;
+	exchangeability_(17,1)=0.51475;
+	exchangeability_(8,15)=0.99721;
+	exchangeability_(15,8)=0.99721;
+	exchangeability_(13,17)=3.27585;
+	exchangeability_(17,13)=3.27585;
+	exchangeability_(10,16)=0.41235;
+	exchangeability_(16,10)=0.41235;
+	exchangeability_(13,15)=0.39286;
+	exchangeability_(15,13)=0.39286;
+	exchangeability_(9,18)=0.40482;
+	exchangeability_(18,9)=0.40482;
+	exchangeability_(2,18)=0.3262;
+	exchangeability_(18,2)=0.3262;
+	exchangeability_(7,9)=0.08333;
+	exchangeability_(9,7)=0.08333;
+	exchangeability_(3,5)=0.41732;
+	exchangeability_(5,3)=0.41732;
+	exchangeability_(3,13)=0.01836;
+	exchangeability_(13,3)=0.01836;
+	exchangeability_(0,10)=0.59399;
+	exchangeability_(10,0)=0.59399;
+	exchangeability_(9,11)=0.7019;
+	exchangeability_(11,9)=0.7019;
+	exchangeability_(8,14)=0.32969;
+	exchangeability_(14,8)=0.32969;
+	exchangeability_(2,8)=4.21419;
+	exchangeability_(8,2)=4.21419;
+	exchangeability_(4,6)=0.06307;
+	exchangeability_(6,4)=0.06307;
+	exchangeability_(8,13)=0.92196;
+	exchangeability_(13,8)=0.92196;
+	exchangeability_(5,7)=0.74377;
+	exchangeability_(7,5)=0.74377;
+	exchangeability_(1,7)=0.79706;
+	exchangeability_(7,1)=0.79706;
+	exchangeability_(4,15)=9.81701;
+	exchangeability_(15,4)=9.81701;
+	exchangeability_(1,14)=0.15005;
+	exchangeability_(14,1)=0.15005;
+	exchangeability_(1,18)=0.04695;
+	exchangeability_(18,1)=0.04695;
+	exchangeability_(11,18)=0.02989;
+	exchangeability_(18,11)=0.02989;
+	exchangeability_(0,5)=1.09597;
+	exchangeability_(5,0)=1.09597;
+	exchangeability_(2,9)=0.96544;
+	exchangeability_(9,2)=0.96544;
+	exchangeability_(7,18)=0.01662;
+	exchangeability_(18,7)=0.01662;
+	exchangeability_(7,14)=0.71504;
+	exchangeability_(14,7)=0.71504;
+	exchangeability_(3,19)=0.10149;
+	exchangeability_(19,3)=0.10149;
+	exchangeability_(5,13)=0.01242;
+	exchangeability_(13,5)=0.01242;
+	exchangeability_(15,19)=0.38952;
+	exchangeability_(19,15)=0.38952;
+	exchangeability_(11,17)=0.07021;
+	exchangeability_(17,11)=0.07021;
+	exchangeability_(7,13)=0.13578;
+	exchangeability_(13,7)=0.13578;
+	exchangeability_(0,2)=0.77435;
+	exchangeability_(2,0)=0.77435;
+	exchangeability_(9,12)=8.13899;
+	exchangeability_(12,9)=8.13899;
+	exchangeability_(3,12)=0.14346;
+	exchangeability_(12,3)=0.14346;
+	exchangeability_(8,19)=0.56802;
+	exchangeability_(19,8)=0.56802;
+	exchangeability_(0,14)=0.65501;
+	exchangeability_(14,0)=0.65501;
+	exchangeability_(5,17)=0.19995;
+	exchangeability_(17,5)=0.19995;
+	exchangeability_(4,10)=3.29024;
+	exchangeability_(10,4)=3.29024;
+	exchangeability_(10,15)=0.62568;
+	exchangeability_(15,10)=0.62568;
+	exchangeability_(14,17)=0.00758;
+	exchangeability_(17,14)=0.00758;
+	exchangeability_(16,18)=0.07011;
+	exchangeability_(18,16)=0.07011;
+	exchangeability_(1,9)=0.54374;
+	exchangeability_(9,1)=0.54374;
+	exchangeability_(4,5)=0.96703;
+	exchangeability_(5,4)=0.96703;
+	exchangeability_(9,10)=5.04243;
+	exchangeability_(10,9)=5.04243;
+	exchangeability_(11,14)=0.1878;
+	exchangeability_(14,11)=0.1878;
+	exchangeability_(8,17)=1.1166;
+	exchangeability_(17,8)=1.1166;
+	exchangeability_(0,15)=2.86333;
+	exchangeability_(15,0)=2.86333;
+	exchangeability_(2,11)=1.66258;
+	exchangeability_(11,2)=1.66258;
+	exchangeability_(10,14)=0.82709;
+	exchangeability_(14,10)=0.82709;
+	exchangeability_(13,16)=0.05412;
+	exchangeability_(16,13)=0.05412;
+	exchangeability_(7,19)=0.45994;
+	exchangeability_(19,7)=0.45994;
+	exchangeability_(3,16)=0.23787;
+	exchangeability_(16,3)=0.23787;
+	exchangeability_(7,12)=0.70698;
+	exchangeability_(12,7)=0.70698;
+	exchangeability_(15,16)=9.93497;
+	exchangeability_(16,15)=9.93497;
+	exchangeability_(14,15)=0.92915;
+	exchangeability_(15,14)=0.92915;
+	exchangeability_(3,11)=0.10619;
+	exchangeability_(11,3)=0.10619;
+	exchangeability_(6,7)=0.77236;
+	exchangeability_(7,6)=0.77236;
+	exchangeability_(8,16)=0.72813;
+	exchangeability_(16,8)=0.72813;
+	exchangeability_(0,1)=0.51487;
+	exchangeability_(1,0)=0.51487;
+	exchangeability_(5,9)=0.45245;
+	exchangeability_(9,5)=0.45245;
+	exchangeability_(12,18)=0.95644;
+	exchangeability_(18,12)=0.95644;
+	exchangeability_(6,16)=0.31914;
+	exchangeability_(16,6)=0.31914;
+	exchangeability_(1,11)=2.01294;
+	exchangeability_(11,1)=2.01294;
+	exchangeability_(2,14)=0.12039;
+	exchangeability_(14,2)=0.12039;
+	exchangeability_(0,4)=1.01982;
+	exchangeability_(4,0)=1.01982;
+	exchangeability_(1,16)=0.39243;
+	exchangeability_(16,1)=0.39243;
+	exchangeability_(6,13)=0.00932;
+	exchangeability_(13,6)=0.00932;
+	exchangeability_(18,19)=0.26852;
+	exchangeability_(19,18)=0.26852;
+	exchangeability_(5,8)=3.6646;
+	exchangeability_(8,5)=3.6646;
+	exchangeability_(16,19)=2.91545;
+	exchangeability_(19,16)=2.91545;
+	exchangeability_(7,16)=0.60789;
+	exchangeability_(16,7)=0.60789;
+	exchangeability_(8,11)=0.69629;
+	exchangeability_(11,8)=0.69629;
+	exchangeability_(3,17)=0.15748;
+	exchangeability_(17,3)=0.15748;
+	exchangeability_(6,17)=0.04569;
+	exchangeability_(17,6)=0.04569;
+	exchangeability_(2,3)=2.01123;
+	exchangeability_(3,2)=2.01123;
+	exchangeability_(3,9)=0.0625;
+	exchangeability_(9,3)=0.0625;
+	exchangeability_(0,16)=1.37394;
+	exchangeability_(16,0)=1.37394;
+	exchangeability_(5,11)=2.26883;
+	exchangeability_(11,5)=2.26883;
+	exchangeability_(4,8)=6.67353;
+	exchangeability_(8,4)=6.67353;
+	exchangeability_(16,17)=0.20572;
+	exchangeability_(17,16)=0.20572;
+	exchangeability_(5,19)=0.47302;
+	exchangeability_(19,5)=0.47302;
+	exchangeability_(1,3)=0.04614;
+	exchangeability_(3,1)=0.04614;
+	exchangeability_(4,19)=8.55353;
+	exchangeability_(19,4)=8.55353;
+	exchangeability_(6,19)=0.41091;
+	exchangeability_(19,6)=0.41091;
+	exchangeability_(1,12)=0.75411;
+	exchangeability_(12,1)=0.75411;
+	exchangeability_(0,6)=1.0546;
+	exchangeability_(6,0)=1.0546;
+	exchangeability_(2,6)=0.36838;
+	exchangeability_(6,2)=0.36838;
+	exchangeability_(1,19)=0.32333;
+	exchangeability_(19,1)=0.32333;
+	exchangeability_(0,17)=0.2476;
+	exchangeability_(17,0)=0.2476;
+	exchangeability_(2,17)=0.14453;
+	exchangeability_(17,2)=0.14453;
+	exchangeability_(7,15)=6.75841;
+	exchangeability_(15,7)=6.75841;
+	exchangeability_(3,14)=0.69826;
+	exchangeability_(14,3)=0.69826;
+	exchangeability_(8,9)=0.90529;
+	exchangeability_(9,8)=0.90529;
+	exchangeability_(3,18)=0.08945;
+	exchangeability_(18,3)=0.08945;
+	exchangeability_(0,3)=0.85429;
+	exchangeability_(3,0)=0.85429;
+	exchangeability_(2,13)=0.0989;
+	exchangeability_(13,2)=0.0989;
+	exchangeability_(0,19)=2.0938;
+	exchangeability_(19,0)=2.0938;
+	exchangeability_(5,12)=1.7088;
+	exchangeability_(12,5)=1.7088;
+	exchangeability_(4,13)=2.1487;
+	exchangeability_(13,4)=2.1487;
+	exchangeability_(10,12)=13.39;
+	exchangeability_(12,10)=13.39;
+	exchangeability_(5,18)=0.01856;
+	exchangeability_(18,5)=0.01856;
+	exchangeability_(14,16)=0.2797;
+	exchangeability_(16,14)=0.2797;
+	exchangeability_(1,13)=0.01272;
+	exchangeability_(13,1)=0.01272;
+	exchangeability_(4,16)=2.4603;
+	exchangeability_(16,4)=2.4603;
+	exchangeability_(6,14)=0.25082;
+	exchangeability_(14,6)=0.25082;
+	exchangeability_(11,15)=0.55529;
+	exchangeability_(15,11)=0.55529;
+	exchangeability_(0,7)=3.51001;
+	exchangeability_(7,0)=3.51001;
+	exchangeability_(2,7)=1.75963;
+	exchangeability_(7,2)=1.75963;
+	exchangeability_(8,18)=3.72861;
+	exchangeability_(18,8)=3.72861;
+	exchangeability_(5,10)=1.42154;
+	exchangeability_(10,5)=1.42154;
+	exchangeability_(15,18)=0.18118;
+	exchangeability_(18,15)=0.18118;
+	exchangeability_(12,16)=2.44602;
+	exchangeability_(16,12)=2.44602;
+	exchangeability_(5,14)=0.35383;
+	exchangeability_(14,5)=0.35383;
+	exchangeability_(7,8)=0.60822;
+	exchangeability_(8,7)=0.60822;
+	exchangeability_(15,17)=0.58399;
+	exchangeability_(17,15)=0.58399;
+	exchangeability_(3,7)=1.42169;
+	exchangeability_(7,3)=1.42169;
+	exchangeability_(6,15)=0.34405;
+	exchangeability_(15,6)=0.34405;
+	exchangeability_(12,13)=1.41888;
+	exchangeability_(13,12)=1.41888;
+	exchangeability_(13,14)=0.0483;
+	exchangeability_(14,13)=0.0483;
+	exchangeability_(3,10)=0.04536;
+	exchangeability_(10,3)=0.04536;
+	exchangeability_(0,13)=0.08564;
+	exchangeability_(13,0)=0.08564;
+	exchangeability_(6,12)=0.1818;
+	exchangeability_(12,6)=0.1818;
+	exchangeability_(4,12)=3.57085;
+	exchangeability_(12,4)=3.57085;
+	exchangeability_(9,14)=0.17025;
+	exchangeability_(14,9)=0.17025;
+	exchangeability_(10,11)=0.39855;
+	exchangeability_(11,10)=0.39855;
+	exchangeability_(12,17)=3.42786;
+	exchangeability_(17,12)=3.42786;
+	exchangeability_(2,19)=0.30708;
+	exchangeability_(19,2)=0.30708;
+	exchangeability_(8,10)=1.5957;
+	exchangeability_(10,8)=1.5957;
+	exchangeability_(1,8)=2.59619;
+	exchangeability_(8,1)=2.59619;
+	exchangeability_(1,5)=1.69615;
+	exchangeability_(5,1)=1.69615;
+	exchangeability_(2,5)=1.29654;
+	exchangeability_(5,2)=1.29654;
+	exchangeability_(0,18)=0.09064;
+	exchangeability_(18,0)=0.09064;
+	exchangeability_(13,18)=47.9331;
+	exchangeability_(18,13)=47.9331;
+	exchangeability_(6,10)=0.1091;
+	exchangeability_(10,6)=0.1091;
+	exchangeability_(9,15)=0.41462;
+	exchangeability_(15,9)=0.41462;
+	exchangeability_(2,15)=3.76162;
+	exchangeability_(15,2)=3.76162;
+	exchangeability_(7,17)=0.79017;
+	exchangeability_(17,7)=0.79017;
+	exchangeability_(2,16)=2.71112;
+	exchangeability_(16,2)=2.71112;
+	exchangeability_(12,19)=2.76337;
+	exchangeability_(19,12)=2.76337;
+	exchangeability_(8,12)=0.78952;
+	exchangeability_(12,8)=0.78952;
+	exchangeability_(3,6)=3.59237;
+	exchangeability_(6,3)=3.59237;
+	exchangeability_(4,11)=0.32915;
+	exchangeability_(11,4)=0.32915;
+	exchangeability_(4,18)=7.47519;
+	exchangeability_(18,4)=7.47519;
+	exchangeability_(0,9)=0.34484;
+	exchangeability_(9,0)=0.34484;
+	exchangeability_(4,14)=0.25495;
+	exchangeability_(14,4)=0.25495;
+	exchangeability_(1,15)=0.65771;
+	exchangeability_(15,1)=0.65771;
+	exchangeability_(2,4)=2.26059;
+	exchangeability_(4,2)=2.26059;
+	exchangeability_(11,13)=0.01472;
+	exchangeability_(13,11)=0.01472;
+	exchangeability_(11,12)=1.13778;
+	exchangeability_(12,11)=1.13778;
+	exchangeability_(10,13)=2.47935;
+	exchangeability_(13,10)=2.47935;
+	exchangeability_(12,14)=0.17849;
+	exchangeability_(14,12)=0.17849;
+	exchangeability_(7,10)=0.23069;
+	exchangeability_(10,7)=0.23069;
+	exchangeability_(0,8)=0.6948;
+	exchangeability_(8,0)=0.6948;
+	exchangeability_(3,4)=0.0576;
+	exchangeability_(4,3)=0.0576;
+	exchangeability_(3,8)=0.65459;
+	exchangeability_(8,3)=0.65459;
+	exchangeability_(2,10)=0.3519;
+	exchangeability_(10,2)=0.3519;
+	exchangeability_(17,18)=5.24246;
+	exchangeability_(18,17)=5.24246;
+	exchangeability_(10,18)=0.61795;
+	exchangeability_(18,10)=0.61795;
+	exchangeability_(6,9)=0.15572;
+	exchangeability_(9,6)=0.15572;
+	exchangeability_(4,9)=2.50086;
+	exchangeability_(9,4)=2.50086;
+	exchangeability_(14,19)=0.31128;
+	exchangeability_(19,14)=0.31128;
+	exchangeability_(9,16)=3.7054;
+	exchangeability_(16,9)=3.7054;
+	exchangeability_(12,15)=0.64762;
+	exchangeability_(15,12)=0.64762;
+	exchangeability_(1,4)=5.65232;
+	exchangeability_(4,1)=5.65232;
+	exchangeability_(4,17)=5.38308;
+	exchangeability_(17,4)=5.38308;
+	exchangeability_(0,11)=0.70884;
+	exchangeability_(11,0)=0.70884;
+	exchangeability_(9,13)=1.00657;
+	exchangeability_(13,9)=1.00657;
+	exchangeability_(1,10)=0.85792;
+	exchangeability_(10,1)=0.85792;
+	exchangeability_(11,19)=0.42683;
+	exchangeability_(19,11)=0.42683;
+	exchangeability_(2,12)=0.91044;
+	exchangeability_(12,2)=0.91044;
+	exchangeability_(10,19)=1.7781;
+	exchangeability_(19,10)=1.7781;
+	exchangeability_(6,8)=0.29497;
+	exchangeability_(8,6)=0.29497;
+	exchangeability_(9,17)=0.24305;
+	exchangeability_(17,9)=0.24305;
+	exchangeability_(7,11)=0.36537;
+	exchangeability_(11,7)=0.36537;
+	exchangeability_(3,15)=0.61969;
+	exchangeability_(15,3)=0.61969;
+	exchangeability_(13,19)=0.57042;
+	exchangeability_(19,13)=0.57042;
+	exchangeability_(14,18)=0.05042;
+	exchangeability_(18,14)=0.05042;
+	exchangeability_(6,18)=0.02071;
+	exchangeability_(18,6)=0.02071;
+	exchangeability_(5,16)=0.70147;
+	exchangeability_(16,5)=0.70147;
+	exchangeability_(5,15)=0.8106;
+	exchangeability_(15,5)=0.8106;
+}
+
+
+if (getName()=="Q1"){
+	exchangeability_(0,0)=-19.5664;
+	exchangeability_(4,4)=-65.1057;
+	exchangeability_(6,6)=-10.5424;
+	exchangeability_(3,3)=-11.3353;
+	exchangeability_(7,7)=-23.1109;
+	exchangeability_(13,13)=-60.638;
+	exchangeability_(9,9)=-39.7488;
+	exchangeability_(8,8)=-31.7781;
+	exchangeability_(11,11)=-13.2063;
+	exchangeability_(12,12)=-44.2615;
+	exchangeability_(10,10)=-35.8062;
+	exchangeability_(2,2)=-24.6285;
+	exchangeability_(5,5)=-20.1882;
+	exchangeability_(14,14)=-6.5181;
+	exchangeability_(15,15)=-41.2845;
+	exchangeability_(1,1)=-18.2377;
+	exchangeability_(16,16)=-30.5101;
+	exchangeability_(17,17)=-23.6469;
+	exchangeability_(19,19)=-36.8734;
+	exchangeability_(18,18)=-67.5678;
+}
+
+
+if (getName()=="Q2"){
+	exchangeability_(0,0)=-49.0805;
+	exchangeability_(4,4)=-50.4887;
+	exchangeability_(6,6)=-23.9777;
+	exchangeability_(3,3)=-17.1359;
+	exchangeability_(7,7)=-9.02826;
+	exchangeability_(13,13)=-27.1194;
+	exchangeability_(9,9)=-23.088;
+	exchangeability_(8,8)=-44.0734;
+	exchangeability_(11,11)=-35.3406;
+	exchangeability_(12,12)=-33.2077;
+	exchangeability_(10,10)=-31.4089;
+	exchangeability_(2,2)=-32.9812;
+	exchangeability_(5,5)=-48.3546;
+	exchangeability_(14,14)=-15.0403;
+	exchangeability_(15,15)=-39.6546;
+	exchangeability_(1,1)=-39.6435;
+	exchangeability_(16,16)=-38.2508;
+	exchangeability_(17,17)=-17.4376;
+	exchangeability_(19,19)=-43.566;
+	exchangeability_(18,18)=-30.3968;
+}
+
+
+if (getName()=="Q3"){
+	exchangeability_(0,0)=-20.8097;
+	exchangeability_(4,4)=-16.9064;
+	exchangeability_(6,6)=-11.6446;
+	exchangeability_(3,3)=-16.4631;
+	exchangeability_(7,7)=-10.4756;
+	exchangeability_(13,13)=-16.965;
+	exchangeability_(9,9)=-16.5974;
+	exchangeability_(8,8)=-24.1307;
+	exchangeability_(11,11)=-16.7838;
+	exchangeability_(12,12)=-19.0925;
+	exchangeability_(10,10)=-11.3098;
+	exchangeability_(2,2)=-29.5243;
+	exchangeability_(5,5)=-22.4636;
+	exchangeability_(14,14)=-6.26964;
+	exchangeability_(15,15)=-29.7382;
+	exchangeability_(1,1)=-18.5876;
+	exchangeability_(16,16)=-16.8966;
+	exchangeability_(17,17)=-8.42441;
+	exchangeability_(19,19)=-17.2728;
+	exchangeability_(18,18)=-21.3923;
+}
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_UL3FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__LLG08_UL3FrequenciesCode
new file mode 100644
index 0000000..6db87a5
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_UL3FrequenciesCode
@@ -0,0 +1,72 @@
+if (getName()=="Q2"){
+	freq_[0] = 0.044015;
+	freq_[4] = 0.00326;
+	freq_[6] = 0.041364;
+	freq_[3] = 0.102405;
+	freq_[7] = 0.168549;
+	freq_[13] = 0.036695;
+	freq_[9] = 0.064277;
+	freq_[8] = 0.015843;
+	freq_[11] = 0.036061;
+	freq_[12] = 0.027358;
+	freq_[10] = 0.118096;
+	freq_[2] = 0.056258;
+	freq_[5] = 0.018409;
+	freq_[14] = 0.124914;
+	freq_[15] = 0.047807;
+	freq_[1] = 0.021591;
+	freq_[16] = 0.022696;
+	freq_[17] = 0.005866;
+	freq_[19] = 0.025892;
+	freq_[18] = 0.018644;
+}
+
+
+if (getName()=="Q3"){
+	freq_[0] = 0.134055;
+	freq_[4] = 0.021008;
+	freq_[6] = 0.028587;
+	freq_[3] = 0.020801;
+	freq_[7] = 0.029069;
+	freq_[13] = 0.038985;
+	freq_[9] = 0.105826;
+	freq_[8] = 0.028138;
+	freq_[11] = 0.049733;
+	freq_[12] = 0.02612;
+	freq_[10] = 0.117458;
+	freq_[2] = 0.02073;
+	freq_[5] = 0.024509;
+	freq_[14] = 0.016306;
+	freq_[15] = 0.038369;
+	freq_[1] = 0.044393;
+	freq_[16] = 0.055334;
+	freq_[17] = 0.017276;
+	freq_[19] = 0.143398;
+	freq_[18] = 0.039905;
+}
+
+
+if (getName()=="Q1"){
+	freq_[0] = 0.104307;
+	freq_[4] = 0.003217;
+	freq_[6] = 0.163928;
+	freq_[3] = 0.085643;
+	freq_[7] = 0.024243;
+	freq_[13] = 0.016126;
+	freq_[9] = 0.016012;
+	freq_[8] = 0.022216;
+	freq_[11] = 0.105577;
+	freq_[12] = 0.011434;
+	freq_[10] = 0.038591;
+	freq_[2] = 0.043722;
+	freq_[5] = 0.074342;
+	freq_[14] = 0.018057;
+	freq_[15] = 0.061232;
+	freq_[1] = 0.092553;
+	freq_[16] = 0.061373;
+	freq_[17] = 0.004086;
+	freq_[19] = 0.032465;
+	freq_[18] = 0.020876;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__LLG08_UL3RatesProps b/src/Bpp/Phyl/Model/Protein/__LLG08_UL3RatesProps
new file mode 100644
index 0000000..075b8dd
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__LLG08_UL3RatesProps
@@ -0,0 +1,18 @@
+if (getName()=="Q1"){
+	rate_ = 1.647026;
+	proportion_ = 0.3203;
+}
+
+
+if (getName()=="Q2"){
+	rate_ = 0.702126;
+	proportion_ = 0.2816;
+}
+
+
+if (getName()=="Q3"){
+	rate_ = 0.690126;
+	proportion_ = 0.3981;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/Protein/__WAG01ExchangeabilityCode b/src/Bpp/Phyl/Model/Protein/__WAG01ExchangeabilityCode
new file mode 100644
index 0000000..4a7669e
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__WAG01ExchangeabilityCode
@@ -0,0 +1,820 @@
+exchangeability_(15,17)=0.523742;
+exchangeability_(17,15)=0.523742;
+exchangeability_(7,7)=-8.57478;
+exchangeability_(7,7)=-8.57478;
+exchangeability_(6,12)=0.315124;
+exchangeability_(12,6)=0.315124;
+exchangeability_(0,2)=0.509848;
+exchangeability_(2,0)=0.509848;
+exchangeability_(0,18)=0.240735;
+exchangeability_(18,0)=0.240735;
+exchangeability_(17,5)=0.215737;
+exchangeability_(5,17)=0.215737;
+exchangeability_(19,2)=0.196246;
+exchangeability_(2,19)=0.196246;
+exchangeability_(13,11)=0.088836;
+exchangeability_(11,13)=0.088836;
+exchangeability_(7,6)=0.567717;
+exchangeability_(6,7)=0.567717;
+exchangeability_(6,3)=6.17416;
+exchangeability_(3,6)=6.17416;
+exchangeability_(17,14)=0.139405;
+exchangeability_(14,17)=0.139405;
+exchangeability_(9,16)=1.45816;
+exchangeability_(16,9)=1.45816;
+exchangeability_(13,3)=0.0467304;
+exchangeability_(3,13)=0.0467304;
+exchangeability_(11,19)=0.305434;
+exchangeability_(19,11)=0.305434;
+exchangeability_(4,18)=0.543833;
+exchangeability_(18,4)=0.543833;
+exchangeability_(7,3)=0.865584;
+exchangeability_(3,7)=0.865584;
+exchangeability_(16,2)=2.03006;
+exchangeability_(2,16)=2.03006;
+exchangeability_(17,17)=-9.85307;
+exchangeability_(17,17)=-9.85307;
+exchangeability_(15,15)=-25.0703;
+exchangeability_(15,15)=-25.0703;
+exchangeability_(11,4)=0.0740339;
+exchangeability_(4,11)=0.0740339;
+exchangeability_(6,13)=0.0811339;
+exchangeability_(13,6)=0.0811339;
+exchangeability_(18,9)=0.42017;
+exchangeability_(9,18)=0.42017;
+exchangeability_(0,11)=0.906265;
+exchangeability_(11,0)=0.906265;
+exchangeability_(5,14)=0.933372;
+exchangeability_(14,5)=0.933372;
+exchangeability_(13,7)=0.049931;
+exchangeability_(7,13)=0.049931;
+exchangeability_(3,15)=1.07176;
+exchangeability_(15,3)=1.07176;
+exchangeability_(4,19)=1.00214;
+exchangeability_(19,4)=1.00214;
+exchangeability_(19,16)=1.38823;
+exchangeability_(16,19)=1.38823;
+exchangeability_(8,14)=0.696198;
+exchangeability_(14,8)=0.696198;
+exchangeability_(14,19)=0.314887;
+exchangeability_(19,14)=0.314887;
+exchangeability_(9,5)=0.113917;
+exchangeability_(5,9)=0.113917;
+exchangeability_(18,11)=0.133264;
+exchangeability_(11,18)=0.133264;
+exchangeability_(17,16)=0.110864;
+exchangeability_(16,17)=0.110864;
+exchangeability_(8,13)=0.679371;
+exchangeability_(13,8)=0.679371;
+exchangeability_(14,3)=0.423984;
+exchangeability_(3,14)=0.423984;
+exchangeability_(5,1)=3.0355;
+exchangeability_(1,5)=3.0355;
+exchangeability_(3,5)=0.616783;
+exchangeability_(5,3)=0.616783;
+exchangeability_(11,5)=3.8949;
+exchangeability_(5,11)=3.8949;
+exchangeability_(3,13)=0.0467304;
+exchangeability_(13,3)=0.0467304;
+exchangeability_(19,17)=0.365369;
+exchangeability_(17,19)=0.365369;
+exchangeability_(16,4)=0.512984;
+exchangeability_(4,16)=0.512984;
+exchangeability_(0,13)=0.210494;
+exchangeability_(13,0)=0.210494;
+exchangeability_(16,8)=0.473307;
+exchangeability_(8,16)=0.473307;
+exchangeability_(0,5)=0.908598;
+exchangeability_(5,0)=0.908598;
+exchangeability_(5,16)=0.857928;
+exchangeability_(16,5)=0.857928;
+exchangeability_(19,13)=0.649892;
+exchangeability_(13,19)=0.649892;
+exchangeability_(13,4)=0.39802;
+exchangeability_(4,13)=0.39802;
+exchangeability_(4,1)=0.528191;
+exchangeability_(1,4)=0.528191;
+exchangeability_(19,14)=0.314887;
+exchangeability_(14,19)=0.314887;
+exchangeability_(8,16)=0.473307;
+exchangeability_(16,8)=0.473307;
+exchangeability_(6,10)=0.154263;
+exchangeability_(10,6)=0.154263;
+exchangeability_(13,1)=0.102711;
+exchangeability_(1,13)=0.102711;
+exchangeability_(9,7)=0.0304501;
+exchangeability_(7,9)=0.0304501;
+exchangeability_(4,5)=0.0988179;
+exchangeability_(5,4)=0.0988179;
+exchangeability_(18,19)=0.31473;
+exchangeability_(19,18)=0.31473;
+exchangeability_(16,0)=2.12111;
+exchangeability_(0,16)=2.12111;
+exchangeability_(16,19)=1.38823;
+exchangeability_(19,16)=1.38823;
+exchangeability_(5,19)=0.301281;
+exchangeability_(19,5)=0.301281;
+exchangeability_(15,11)=0.96713;
+exchangeability_(11,15)=0.96713;
+exchangeability_(11,11)=-22.6586;
+exchangeability_(11,11)=-22.6586;
+exchangeability_(6,2)=0.947198;
+exchangeability_(2,6)=0.947198;
+exchangeability_(2,16)=2.03006;
+exchangeability_(16,2)=2.03006;
+exchangeability_(0,8)=0.316954;
+exchangeability_(8,0)=0.316954;
+exchangeability_(0,4)=1.02704;
+exchangeability_(4,0)=1.02704;
+exchangeability_(19,15)=0.232739;
+exchangeability_(15,19)=0.232739;
+exchangeability_(5,8)=4.29411;
+exchangeability_(8,5)=4.29411;
+exchangeability_(8,15)=0.740169;
+exchangeability_(15,8)=0.740169;
+exchangeability_(5,18)=0.22771;
+exchangeability_(18,5)=0.22771;
+exchangeability_(14,2)=0.195081;
+exchangeability_(2,14)=0.195081;
+exchangeability_(9,18)=0.42017;
+exchangeability_(18,9)=0.42017;
+exchangeability_(14,7)=0.24357;
+exchangeability_(7,14)=0.24357;
+exchangeability_(13,2)=0.0961621;
+exchangeability_(2,13)=0.0961621;
+exchangeability_(8,2)=3.95629;
+exchangeability_(2,8)=3.95629;
+exchangeability_(11,8)=0.890432;
+exchangeability_(8,11)=0.890432;
+exchangeability_(2,17)=0.0719167;
+exchangeability_(17,2)=0.0719167;
+exchangeability_(15,18)=0.786993;
+exchangeability_(18,15)=0.786993;
+exchangeability_(17,2)=0.0719167;
+exchangeability_(2,17)=0.0719167;
+exchangeability_(3,18)=0.325711;
+exchangeability_(18,3)=0.325711;
+exchangeability_(6,5)=5.46947;
+exchangeability_(5,6)=5.46947;
+exchangeability_(11,18)=0.133264;
+exchangeability_(18,11)=0.133264;
+exchangeability_(15,7)=1.34182;
+exchangeability_(7,15)=1.34182;
+exchangeability_(18,15)=0.786993;
+exchangeability_(15,18)=0.786993;
+exchangeability_(7,1)=0.584665;
+exchangeability_(1,7)=0.584665;
+exchangeability_(0,10)=0.397915;
+exchangeability_(10,0)=0.397915;
+exchangeability_(0,7)=1.41672;
+exchangeability_(7,0)=1.41672;
+exchangeability_(16,11)=1.38698;
+exchangeability_(11,16)=1.38698;
+exchangeability_(16,14)=0.795384;
+exchangeability_(14,16)=0.795384;
+exchangeability_(12,19)=2.05845;
+exchangeability_(19,12)=2.05845;
+exchangeability_(5,10)=0.869489;
+exchangeability_(10,5)=0.869489;
+exchangeability_(6,15)=0.704939;
+exchangeability_(15,6)=0.704939;
+exchangeability_(8,17)=0.262569;
+exchangeability_(17,8)=0.262569;
+exchangeability_(9,3)=0.039437;
+exchangeability_(3,9)=0.039437;
+exchangeability_(11,13)=0.088836;
+exchangeability_(13,11)=0.088836;
+exchangeability_(2,0)=0.509848;
+exchangeability_(0,2)=0.509848;
+exchangeability_(16,9)=1.45816;
+exchangeability_(9,16)=1.45816;
+exchangeability_(5,2)=1.54364;
+exchangeability_(2,5)=1.54364;
+exchangeability_(11,17)=0.137505;
+exchangeability_(17,11)=0.137505;
+exchangeability_(15,4)=1.40766;
+exchangeability_(4,15)=1.40766;
+exchangeability_(18,18)=-18.9079;
+exchangeability_(18,18)=-18.9079;
+exchangeability_(7,19)=0.187247;
+exchangeability_(19,7)=0.187247;
+exchangeability_(10,19)=1.80034;
+exchangeability_(19,10)=1.80034;
+exchangeability_(0,1)=0.551571;
+exchangeability_(1,0)=0.551571;
+exchangeability_(12,1)=0.683162;
+exchangeability_(1,12)=0.683162;
+exchangeability_(2,9)=0.554236;
+exchangeability_(9,2)=0.554236;
+exchangeability_(3,4)=0.0302949;
+exchangeability_(4,3)=0.0302949;
+exchangeability_(14,14)=-9.88645;
+exchangeability_(14,14)=-9.88645;
+exchangeability_(3,8)=0.930676;
+exchangeability_(8,3)=0.930676;
+exchangeability_(5,5)=-26.3854;
+exchangeability_(5,5)=-26.3854;
+exchangeability_(9,19)=7.8213;
+exchangeability_(19,9)=7.8213;
+exchangeability_(14,13)=0.161444;
+exchangeability_(13,14)=0.161444;
+exchangeability_(9,0)=0.193335;
+exchangeability_(0,9)=0.193335;
+exchangeability_(13,13)=-15.7317;
+exchangeability_(13,13)=-15.7317;
+exchangeability_(11,16)=1.38698;
+exchangeability_(16,11)=1.38698;
+exchangeability_(10,16)=0.326622;
+exchangeability_(16,10)=0.326622;
+exchangeability_(15,5)=1.02887;
+exchangeability_(5,15)=1.02887;
+exchangeability_(17,13)=1.52964;
+exchangeability_(13,17)=1.52964;
+exchangeability_(3,0)=0.738998;
+exchangeability_(0,3)=0.738998;
+exchangeability_(6,18)=0.196303;
+exchangeability_(18,6)=0.196303;
+exchangeability_(11,0)=0.906265;
+exchangeability_(0,11)=0.906265;
+exchangeability_(5,15)=1.02887;
+exchangeability_(15,5)=1.02887;
+exchangeability_(0,3)=0.738998;
+exchangeability_(3,0)=0.738998;
+exchangeability_(10,1)=0.497671;
+exchangeability_(1,10)=0.497671;
+exchangeability_(16,15)=4.37802;
+exchangeability_(15,16)=4.37802;
+exchangeability_(0,19)=2.00601;
+exchangeability_(19,0)=2.00601;
+exchangeability_(12,2)=0.198221;
+exchangeability_(2,12)=0.198221;
+exchangeability_(5,3)=0.616783;
+exchangeability_(3,5)=0.616783;
+exchangeability_(6,14)=0.682355;
+exchangeability_(14,6)=0.682355;
+exchangeability_(19,19)=-20.0556;
+exchangeability_(19,19)=-20.0556;
+exchangeability_(3,2)=5.42942;
+exchangeability_(2,3)=5.42942;
+exchangeability_(9,15)=0.31944;
+exchangeability_(15,9)=0.31944;
+exchangeability_(14,12)=0.171329;
+exchangeability_(12,14)=0.171329;
+exchangeability_(8,3)=0.930676;
+exchangeability_(3,8)=0.930676;
+exchangeability_(9,10)=3.17097;
+exchangeability_(10,9)=3.17097;
+exchangeability_(11,2)=3.01201;
+exchangeability_(2,11)=3.01201;
+exchangeability_(10,14)=0.415844;
+exchangeability_(14,10)=0.415844;
+exchangeability_(2,10)=0.131528;
+exchangeability_(10,2)=0.131528;
+exchangeability_(18,10)=0.398618;
+exchangeability_(10,18)=0.398618;
+exchangeability_(16,5)=0.857928;
+exchangeability_(5,16)=0.857928;
+exchangeability_(5,13)=0.0999208;
+exchangeability_(13,5)=0.0999208;
+exchangeability_(15,12)=0.493905;
+exchangeability_(12,15)=0.493905;
+exchangeability_(6,1)=0.439157;
+exchangeability_(1,6)=0.439157;
+exchangeability_(5,17)=0.215737;
+exchangeability_(17,5)=0.215737;
+exchangeability_(7,2)=1.12556;
+exchangeability_(2,7)=1.12556;
+exchangeability_(10,18)=0.398618;
+exchangeability_(18,10)=0.398618;
+exchangeability_(10,2)=0.131528;
+exchangeability_(2,10)=0.131528;
+exchangeability_(0,15)=3.37079;
+exchangeability_(15,0)=3.37079;
+exchangeability_(3,16)=0.374866;
+exchangeability_(16,3)=0.374866;
+exchangeability_(15,16)=4.37802;
+exchangeability_(16,15)=4.37802;
+exchangeability_(14,15)=1.61328;
+exchangeability_(15,14)=1.61328;
+exchangeability_(19,1)=0.251849;
+exchangeability_(1,19)=0.251849;
+exchangeability_(3,11)=0.479855;
+exchangeability_(11,3)=0.479855;
+exchangeability_(14,8)=0.696198;
+exchangeability_(8,14)=0.696198;
+exchangeability_(8,4)=0.248972;
+exchangeability_(4,8)=0.248972;
+exchangeability_(5,9)=0.113917;
+exchangeability_(9,5)=0.113917;
+exchangeability_(8,8)=-21.4792;
+exchangeability_(8,8)=-21.4792;
+exchangeability_(9,9)=-20.6973;
+exchangeability_(9,9)=-20.6973;
+exchangeability_(10,17)=0.665309;
+exchangeability_(17,10)=0.665309;
+exchangeability_(10,10)=-17.4299;
+exchangeability_(10,10)=-17.4299;
+exchangeability_(3,1)=0.147304;
+exchangeability_(1,3)=0.147304;
+exchangeability_(15,9)=0.31944;
+exchangeability_(9,15)=0.31944;
+exchangeability_(3,9)=0.039437;
+exchangeability_(9,3)=0.039437;
+exchangeability_(6,0)=1.58285;
+exchangeability_(0,6)=1.58285;
+exchangeability_(11,9)=0.323832;
+exchangeability_(9,11)=0.323832;
+exchangeability_(5,11)=3.8949;
+exchangeability_(11,5)=3.8949;
+exchangeability_(16,3)=0.374866;
+exchangeability_(3,16)=0.374866;
+exchangeability_(0,17)=0.113133;
+exchangeability_(17,0)=0.113133;
+exchangeability_(18,1)=0.381533;
+exchangeability_(1,18)=0.381533;
+exchangeability_(12,13)=1.19063;
+exchangeability_(13,12)=1.19063;
+exchangeability_(15,14)=1.61328;
+exchangeability_(14,15)=1.61328;
+exchangeability_(8,5)=4.29411;
+exchangeability_(5,8)=4.29411;
+exchangeability_(18,2)=1.086;
+exchangeability_(2,18)=1.086;
+exchangeability_(9,14)=0.0999288;
+exchangeability_(14,9)=0.0999288;
+exchangeability_(6,4)=0.021352;
+exchangeability_(4,6)=0.021352;
+exchangeability_(8,7)=0.24941;
+exchangeability_(7,8)=0.24941;
+exchangeability_(14,6)=0.682355;
+exchangeability_(6,14)=0.682355;
+exchangeability_(5,12)=1.54526;
+exchangeability_(12,5)=1.54526;
+exchangeability_(8,10)=0.499462;
+exchangeability_(10,8)=0.499462;
+exchangeability_(10,15)=0.344739;
+exchangeability_(15,10)=0.344739;
+exchangeability_(10,8)=0.499462;
+exchangeability_(8,10)=0.499462;
+exchangeability_(18,16)=0.291148;
+exchangeability_(16,18)=0.291148;
+exchangeability_(16,18)=0.291148;
+exchangeability_(18,16)=0.291148;
+exchangeability_(11,7)=0.373558;
+exchangeability_(7,11)=0.373558;
+exchangeability_(15,6)=0.704939;
+exchangeability_(6,15)=0.704939;
+exchangeability_(18,6)=0.196303;
+exchangeability_(6,18)=0.196303;
+exchangeability_(17,1)=1.16392;
+exchangeability_(1,17)=1.16392;
+exchangeability_(19,12)=2.05845;
+exchangeability_(12,19)=2.05845;
+exchangeability_(2,1)=0.635346;
+exchangeability_(1,2)=0.635346;
+exchangeability_(7,13)=0.049931;
+exchangeability_(13,7)=0.049931;
+exchangeability_(13,18)=6.45428;
+exchangeability_(18,13)=6.45428;
+exchangeability_(10,5)=0.869489;
+exchangeability_(5,10)=0.869489;
+exchangeability_(12,18)=0.428437;
+exchangeability_(18,12)=0.428437;
+exchangeability_(0,14)=1.43855;
+exchangeability_(14,0)=1.43855;
+exchangeability_(15,2)=3.97423;
+exchangeability_(2,15)=3.97423;
+exchangeability_(4,10)=0.384287;
+exchangeability_(10,4)=0.384287;
+exchangeability_(10,13)=2.11517;
+exchangeability_(13,10)=2.11517;
+exchangeability_(3,17)=0.129767;
+exchangeability_(17,3)=0.129767;
+exchangeability_(15,10)=0.344739;
+exchangeability_(10,15)=0.344739;
+exchangeability_(14,1)=0.679489;
+exchangeability_(1,14)=0.679489;
+exchangeability_(14,11)=0.556896;
+exchangeability_(11,14)=0.556896;
+exchangeability_(18,7)=0.103604;
+exchangeability_(7,18)=0.103604;
+exchangeability_(4,11)=0.0740339;
+exchangeability_(11,4)=0.0740339;
+exchangeability_(8,11)=0.890432;
+exchangeability_(11,8)=0.890432;
+exchangeability_(5,0)=0.908598;
+exchangeability_(0,5)=0.908598;
+exchangeability_(9,13)=1.05947;
+exchangeability_(13,9)=1.05947;
+exchangeability_(11,3)=0.479855;
+exchangeability_(3,11)=0.479855;
+exchangeability_(2,4)=0.265256;
+exchangeability_(4,2)=0.265256;
+exchangeability_(10,3)=0.0848047;
+exchangeability_(3,10)=0.0848047;
+exchangeability_(13,19)=0.649892;
+exchangeability_(19,13)=0.649892;
+exchangeability_(15,0)=3.37079;
+exchangeability_(0,15)=3.37079;
+exchangeability_(17,19)=0.365369;
+exchangeability_(19,17)=0.365369;
+exchangeability_(6,9)=0.127395;
+exchangeability_(9,6)=0.127395;
+exchangeability_(19,9)=7.8213;
+exchangeability_(9,19)=7.8213;
+exchangeability_(5,4)=0.0988179;
+exchangeability_(4,5)=0.0988179;
+exchangeability_(16,7)=0.225833;
+exchangeability_(7,16)=0.225833;
+exchangeability_(16,10)=0.326622;
+exchangeability_(10,16)=0.326622;
+exchangeability_(10,12)=4.85402;
+exchangeability_(12,10)=4.85402;
+exchangeability_(0,16)=2.12111;
+exchangeability_(16,0)=2.12111;
+exchangeability_(4,8)=0.248972;
+exchangeability_(8,4)=0.248972;
+exchangeability_(14,18)=0.216046;
+exchangeability_(18,14)=0.216046;
+exchangeability_(15,8)=0.740169;
+exchangeability_(8,15)=0.740169;
+exchangeability_(8,18)=3.87344;
+exchangeability_(18,8)=3.87344;
+exchangeability_(6,11)=2.58443;
+exchangeability_(11,6)=2.58443;
+exchangeability_(4,7)=0.306674;
+exchangeability_(7,4)=0.306674;
+exchangeability_(9,4)=0.170135;
+exchangeability_(4,9)=0.170135;
+exchangeability_(5,6)=5.46947;
+exchangeability_(6,5)=5.46947;
+exchangeability_(11,1)=5.35142;
+exchangeability_(1,11)=5.35142;
+exchangeability_(16,6)=0.822765;
+exchangeability_(6,16)=0.822765;
+exchangeability_(10,11)=0.257555;
+exchangeability_(11,10)=0.257555;
+exchangeability_(12,17)=0.515706;
+exchangeability_(17,12)=0.515706;
+exchangeability_(2,18)=1.086;
+exchangeability_(18,2)=1.086;
+exchangeability_(18,12)=0.428437;
+exchangeability_(12,18)=0.428437;
+exchangeability_(19,6)=0.588731;
+exchangeability_(6,19)=0.588731;
+exchangeability_(5,7)=0.330052;
+exchangeability_(7,5)=0.330052;
+exchangeability_(18,3)=0.325711;
+exchangeability_(3,18)=0.325711;
+exchangeability_(13,5)=0.0999208;
+exchangeability_(5,13)=0.0999208;
+exchangeability_(7,18)=0.103604;
+exchangeability_(18,7)=0.103604;
+exchangeability_(10,9)=3.17097;
+exchangeability_(9,10)=3.17097;
+exchangeability_(12,5)=1.54526;
+exchangeability_(5,12)=1.54526;
+exchangeability_(1,0)=0.551571;
+exchangeability_(0,1)=0.551571;
+exchangeability_(4,3)=0.0302949;
+exchangeability_(3,4)=0.0302949;
+exchangeability_(15,19)=0.232739;
+exchangeability_(19,15)=0.232739;
+exchangeability_(3,3)=-18.1662;
+exchangeability_(3,3)=-18.1662;
+exchangeability_(15,3)=1.07176;
+exchangeability_(3,15)=1.07176;
+exchangeability_(14,4)=0.109404;
+exchangeability_(4,14)=0.109404;
+exchangeability_(4,4)=-8.23665;
+exchangeability_(4,4)=-8.23665;
+exchangeability_(17,11)=0.137505;
+exchangeability_(11,17)=0.137505;
+exchangeability_(9,2)=0.554236;
+exchangeability_(2,9)=0.554236;
+exchangeability_(11,10)=0.257555;
+exchangeability_(10,11)=0.257555;
+exchangeability_(2,11)=3.01201;
+exchangeability_(11,2)=3.01201;
+exchangeability_(10,7)=0.0613037;
+exchangeability_(7,10)=0.0613037;
+exchangeability_(12,15)=0.493905;
+exchangeability_(15,12)=0.493905;
+exchangeability_(1,4)=0.528191;
+exchangeability_(4,1)=0.528191;
+exchangeability_(1,3)=0.147304;
+exchangeability_(3,1)=0.147304;
+exchangeability_(19,0)=2.00601;
+exchangeability_(0,19)=2.00601;
+exchangeability_(17,9)=0.212483;
+exchangeability_(9,17)=0.212483;
+exchangeability_(16,16)=-19.7967;
+exchangeability_(16,16)=-19.7967;
+exchangeability_(13,12)=1.19063;
+exchangeability_(12,13)=1.19063;
+exchangeability_(10,6)=0.154263;
+exchangeability_(6,10)=0.154263;
+exchangeability_(12,12)=-21.1281;
+exchangeability_(12,12)=-21.1281;
+exchangeability_(1,6)=0.439157;
+exchangeability_(6,1)=0.439157;
+exchangeability_(17,8)=0.262569;
+exchangeability_(8,17)=0.262569;
+exchangeability_(15,1)=1.22419;
+exchangeability_(1,15)=1.22419;
+exchangeability_(6,17)=0.156557;
+exchangeability_(17,6)=0.156557;
+exchangeability_(14,5)=0.933372;
+exchangeability_(5,14)=0.933372;
+exchangeability_(8,0)=0.316954;
+exchangeability_(0,8)=0.316954;
+exchangeability_(18,0)=0.240735;
+exchangeability_(0,18)=0.240735;
+exchangeability_(6,8)=0.570025;
+exchangeability_(8,6)=0.570025;
+exchangeability_(1,13)=0.102711;
+exchangeability_(13,1)=0.102711;
+exchangeability_(9,11)=0.323832;
+exchangeability_(11,9)=0.323832;
+exchangeability_(2,6)=0.947198;
+exchangeability_(6,2)=0.947198;
+exchangeability_(16,12)=1.51612;
+exchangeability_(12,16)=1.51612;
+exchangeability_(16,1)=0.554413;
+exchangeability_(1,16)=0.554413;
+exchangeability_(12,16)=1.51612;
+exchangeability_(16,12)=1.51612;
+exchangeability_(7,15)=1.34182;
+exchangeability_(15,7)=1.34182;
+exchangeability_(10,4)=0.384287;
+exchangeability_(4,10)=0.384287;
+exchangeability_(1,7)=0.584665;
+exchangeability_(7,1)=0.584665;
+exchangeability_(2,8)=3.95629;
+exchangeability_(8,2)=3.95629;
+exchangeability_(2,13)=0.0961621;
+exchangeability_(13,2)=0.0961621;
+exchangeability_(18,5)=0.22771;
+exchangeability_(5,18)=0.22771;
+exchangeability_(2,14)=0.195081;
+exchangeability_(14,2)=0.195081;
+exchangeability_(1,8)=2.13715;
+exchangeability_(8,1)=2.13715;
+exchangeability_(17,12)=0.515706;
+exchangeability_(12,17)=0.515706;
+exchangeability_(4,2)=0.265256;
+exchangeability_(2,4)=0.265256;
+exchangeability_(19,10)=1.80034;
+exchangeability_(10,19)=1.80034;
+exchangeability_(13,9)=1.05947;
+exchangeability_(9,13)=1.05947;
+exchangeability_(7,5)=0.330052;
+exchangeability_(5,7)=0.330052;
+exchangeability_(10,0)=0.397915;
+exchangeability_(0,10)=0.397915;
+exchangeability_(12,9)=4.25746;
+exchangeability_(9,12)=4.25746;
+exchangeability_(1,9)=0.186979;
+exchangeability_(9,1)=0.186979;
+exchangeability_(17,10)=0.665309;
+exchangeability_(10,17)=0.665309;
+exchangeability_(3,7)=0.865584;
+exchangeability_(7,3)=0.865584;
+exchangeability_(3,10)=0.0848047;
+exchangeability_(10,3)=0.0848047;
+exchangeability_(9,1)=0.186979;
+exchangeability_(1,9)=0.186979;
+exchangeability_(4,12)=0.390482;
+exchangeability_(12,4)=0.390482;
+exchangeability_(8,6)=0.570025;
+exchangeability_(6,8)=0.570025;
+exchangeability_(18,17)=2.48539;
+exchangeability_(17,18)=2.48539;
+exchangeability_(7,14)=0.24357;
+exchangeability_(14,7)=0.24357;
+exchangeability_(17,4)=0.71707;
+exchangeability_(4,17)=0.71707;
+exchangeability_(12,14)=0.171329;
+exchangeability_(14,12)=0.171329;
+exchangeability_(2,15)=3.97423;
+exchangeability_(15,2)=3.97423;
+exchangeability_(7,17)=0.336983;
+exchangeability_(17,7)=0.336983;
+exchangeability_(12,11)=0.934276;
+exchangeability_(11,12)=0.934276;
+exchangeability_(1,11)=5.35142;
+exchangeability_(11,1)=5.35142;
+exchangeability_(3,6)=6.17416;
+exchangeability_(6,3)=6.17416;
+exchangeability_(11,6)=2.58443;
+exchangeability_(6,11)=2.58443;
+exchangeability_(1,10)=0.497671;
+exchangeability_(10,1)=0.497671;
+exchangeability_(0,9)=0.193335;
+exchangeability_(9,0)=0.193335;
+exchangeability_(19,18)=0.31473;
+exchangeability_(18,19)=0.31473;
+exchangeability_(17,0)=0.113133;
+exchangeability_(0,17)=0.113133;
+exchangeability_(18,13)=6.45428;
+exchangeability_(13,18)=6.45428;
+exchangeability_(16,17)=0.110864;
+exchangeability_(17,16)=0.110864;
+exchangeability_(19,8)=0.118358;
+exchangeability_(8,19)=0.118358;
+exchangeability_(13,6)=0.0811339;
+exchangeability_(6,13)=0.0811339;
+exchangeability_(12,6)=0.315124;
+exchangeability_(6,12)=0.315124;
+exchangeability_(1,12)=0.683162;
+exchangeability_(12,1)=0.683162;
+exchangeability_(6,16)=0.822765;
+exchangeability_(16,6)=0.822765;
+exchangeability_(8,1)=2.13715;
+exchangeability_(1,8)=2.13715;
+exchangeability_(14,9)=0.0999288;
+exchangeability_(9,14)=0.0999288;
+exchangeability_(13,16)=0.171903;
+exchangeability_(16,13)=0.171903;
+exchangeability_(4,9)=0.170135;
+exchangeability_(9,4)=0.170135;
+exchangeability_(8,9)=0.13819;
+exchangeability_(9,8)=0.13819;
+exchangeability_(7,16)=0.225833;
+exchangeability_(16,7)=0.225833;
+exchangeability_(9,8)=0.13819;
+exchangeability_(8,9)=0.13819;
+exchangeability_(1,2)=0.635346;
+exchangeability_(2,1)=0.635346;
+exchangeability_(4,17)=0.71707;
+exchangeability_(17,4)=0.71707;
+exchangeability_(17,7)=0.336983;
+exchangeability_(7,17)=0.336983;
+exchangeability_(2,12)=0.198221;
+exchangeability_(12,2)=0.198221;
+exchangeability_(12,10)=4.85402;
+exchangeability_(10,12)=4.85402;
+exchangeability_(7,11)=0.373558;
+exchangeability_(11,7)=0.373558;
+exchangeability_(12,7)=0.1741;
+exchangeability_(7,12)=0.1741;
+exchangeability_(11,15)=0.96713;
+exchangeability_(15,11)=0.96713;
+exchangeability_(6,19)=0.588731;
+exchangeability_(19,6)=0.588731;
+exchangeability_(2,2)=-25.9582;
+exchangeability_(2,2)=-25.9582;
+exchangeability_(19,11)=0.305434;
+exchangeability_(11,19)=0.305434;
+exchangeability_(1,14)=0.679489;
+exchangeability_(14,1)=0.679489;
+exchangeability_(0,12)=0.893496;
+exchangeability_(12,0)=0.893496;
+exchangeability_(17,6)=0.156557;
+exchangeability_(6,17)=0.156557;
+exchangeability_(13,17)=1.52964;
+exchangeability_(17,13)=1.52964;
+exchangeability_(4,13)=0.39802;
+exchangeability_(13,4)=0.39802;
+exchangeability_(19,3)=0.152335;
+exchangeability_(3,19)=0.152335;
+exchangeability_(13,0)=0.210494;
+exchangeability_(0,13)=0.210494;
+exchangeability_(7,9)=0.0304501;
+exchangeability_(9,7)=0.0304501;
+exchangeability_(12,0)=0.893496;
+exchangeability_(0,12)=0.893496;
+exchangeability_(1,5)=3.0355;
+exchangeability_(5,1)=3.0355;
+exchangeability_(4,16)=0.512984;
+exchangeability_(16,4)=0.512984;
+exchangeability_(17,3)=0.129767;
+exchangeability_(3,17)=0.129767;
+exchangeability_(8,19)=0.118358;
+exchangeability_(19,8)=0.118358;
+exchangeability_(15,13)=0.545931;
+exchangeability_(13,15)=0.545931;
+exchangeability_(14,16)=0.795384;
+exchangeability_(16,14)=0.795384;
+exchangeability_(13,14)=0.161444;
+exchangeability_(14,13)=0.161444;
+exchangeability_(4,6)=0.021352;
+exchangeability_(6,4)=0.021352;
+exchangeability_(8,12)=0.404141;
+exchangeability_(12,8)=0.404141;
+exchangeability_(9,6)=0.127395;
+exchangeability_(6,9)=0.127395;
+exchangeability_(7,8)=0.24941;
+exchangeability_(8,7)=0.24941;
+exchangeability_(1,1)=-19.1362;
+exchangeability_(1,1)=-19.1362;
+exchangeability_(11,14)=0.556896;
+exchangeability_(14,11)=0.556896;
+exchangeability_(4,15)=1.40766;
+exchangeability_(15,4)=1.40766;
+exchangeability_(3,19)=0.152335;
+exchangeability_(19,3)=0.152335;
+exchangeability_(12,8)=0.404141;
+exchangeability_(8,12)=0.404141;
+exchangeability_(12,4)=0.390482;
+exchangeability_(4,12)=0.390482;
+exchangeability_(1,15)=1.22419;
+exchangeability_(15,1)=1.22419;
+exchangeability_(3,12)=0.103754;
+exchangeability_(12,3)=0.103754;
+exchangeability_(6,6)=-22.1859;
+exchangeability_(6,6)=-22.1859;
+exchangeability_(11,12)=0.934276;
+exchangeability_(12,11)=0.934276;
+exchangeability_(19,7)=0.187247;
+exchangeability_(7,19)=0.187247;
+exchangeability_(1,16)=0.554413;
+exchangeability_(16,1)=0.554413;
+exchangeability_(0,0)=-18.9444;
+exchangeability_(0,0)=-18.9444;
+exchangeability_(19,5)=0.301281;
+exchangeability_(5,19)=0.301281;
+exchangeability_(17,18)=2.48539;
+exchangeability_(18,17)=2.48539;
+exchangeability_(13,15)=0.545931;
+exchangeability_(15,13)=0.545931;
+exchangeability_(7,12)=0.1741;
+exchangeability_(12,7)=0.1741;
+exchangeability_(4,14)=0.109404;
+exchangeability_(14,4)=0.109404;
+exchangeability_(6,7)=0.567717;
+exchangeability_(7,6)=0.567717;
+exchangeability_(9,17)=0.212483;
+exchangeability_(17,9)=0.212483;
+exchangeability_(14,0)=1.43855;
+exchangeability_(0,14)=1.43855;
+exchangeability_(13,10)=2.11517;
+exchangeability_(10,13)=2.11517;
+exchangeability_(4,0)=1.02704;
+exchangeability_(0,4)=1.02704;
+exchangeability_(7,10)=0.0613037;
+exchangeability_(10,7)=0.0613037;
+exchangeability_(1,19)=0.251849;
+exchangeability_(19,1)=0.251849;
+exchangeability_(16,13)=0.171903;
+exchangeability_(13,16)=0.171903;
+exchangeability_(18,14)=0.216046;
+exchangeability_(14,18)=0.216046;
+exchangeability_(12,3)=0.103754;
+exchangeability_(3,12)=0.103754;
+exchangeability_(7,4)=0.306674;
+exchangeability_(4,7)=0.306674;
+exchangeability_(1,17)=1.16392;
+exchangeability_(17,1)=1.16392;
+exchangeability_(2,3)=5.42942;
+exchangeability_(3,2)=5.42942;
+exchangeability_(2,19)=0.196246;
+exchangeability_(19,2)=0.196246;
+exchangeability_(19,4)=1.00214;
+exchangeability_(4,19)=1.00214;
+exchangeability_(0,6)=1.58285;
+exchangeability_(6,0)=1.58285;
+exchangeability_(18,8)=3.87344;
+exchangeability_(8,18)=3.87344;
+exchangeability_(3,14)=0.423984;
+exchangeability_(14,3)=0.423984;
+exchangeability_(7,0)=1.41672;
+exchangeability_(0,7)=1.41672;
+exchangeability_(1,18)=0.381533;
+exchangeability_(18,1)=0.381533;
+exchangeability_(14,17)=0.139405;
+exchangeability_(17,14)=0.139405;
+exchangeability_(18,4)=0.543833;
+exchangeability_(4,18)=0.543833;
+exchangeability_(14,10)=0.415844;
+exchangeability_(10,14)=0.415844;
+exchangeability_(13,8)=0.679371;
+exchangeability_(8,13)=0.679371;
+exchangeability_(9,12)=4.25746;
+exchangeability_(12,9)=4.25746;
+exchangeability_(2,5)=1.54364;
+exchangeability_(5,2)=1.54364;
+exchangeability_(2,7)=1.12556;
+exchangeability_(7,2)=1.12556;
+exchangeability_(17,15)=0.523742;
+exchangeability_(15,17)=0.523742;
+exchangeability_(0,0)=-18.9444;
+exchangeability_(4,4)=-8.23665;
+exchangeability_(6,6)=-22.1859;
+exchangeability_(3,3)=-18.1662;
+exchangeability_(7,7)=-8.57478;
+exchangeability_(13,13)=-15.7317;
+exchangeability_(9,9)=-20.6973;
+exchangeability_(8,8)=-21.4792;
+exchangeability_(11,11)=-22.6586;
+exchangeability_(12,12)=-21.1281;
+exchangeability_(10,10)=-17.4299;
+exchangeability_(2,2)=-25.9582;
+exchangeability_(5,5)=-26.3854;
+exchangeability_(14,14)=-9.88645;
+exchangeability_(15,15)=-25.0703;
+exchangeability_(1,1)=-19.1362;
+exchangeability_(16,16)=-19.7967;
+exchangeability_(17,17)=-9.85307;
+exchangeability_(19,19)=-20.0556;
+exchangeability_(18,18)=-18.9079;
diff --git a/src/Bpp/Phyl/Model/Protein/__WAG01FrequenciesCode b/src/Bpp/Phyl/Model/Protein/__WAG01FrequenciesCode
new file mode 100644
index 0000000..32b1c2a
--- /dev/null
+++ b/src/Bpp/Phyl/Model/Protein/__WAG01FrequenciesCode
@@ -0,0 +1,21 @@
+freq_[0]=0.0866279;
+freq_[4]=0.0193078;
+freq_[6]=0.0580589;
+freq_[3]=0.0570451;
+freq_[7]=0.0832518;
+freq_[13]=0.0384319;
+freq_[9]=0.048466;
+freq_[8]=0.0244313;
+freq_[11]=0.0620286;
+freq_[12]=0.0195027;
+freq_[10]=0.086209;
+freq_[2]=0.0390894;
+freq_[5]=0.0367281;
+freq_[14]=0.0457632;
+freq_[15]=0.0695179;
+freq_[1]=0.043972;
+freq_[16]=0.0610127;
+freq_[17]=0.0143859;
+freq_[19]=0.0708956;
+freq_[18]=0.0352742;
+
diff --git a/src/Bpp/Phyl/Model/RE08.cpp b/src/Bpp/Phyl/Model/RE08.cpp
new file mode 100755
index 0000000..d19992e
--- /dev/null
+++ b/src/Bpp/Phyl/Model/RE08.cpp
@@ -0,0 +1,321 @@
+//
+// File: RE08.cpp
+// Created by: Julien Dutheil
+// Created on: Mon Dec 29 10:15 2008
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "RE08.h"
+
+using namespace bpp;
+
+#include <cmath>
+
+using namespace std;
+
+/******************************************************************************/
+
+RE08::RE08(ReversibleSubstitutionModel* simpleModel, double lambda, double mu) :
+  AbstractParameterAliasable("RE08."),
+  AbstractSubstitutionModel(simpleModel->getAlphabet(), "RE08."),
+  AbstractReversibleSubstitutionModel(simpleModel->getAlphabet(), "RE08."),
+  simpleModel_(simpleModel),
+  simpleGenerator_(),
+  simpleExchangeabilities_(),
+  exp_(), p_(), lambda_(lambda), mu_(mu),
+  nestedPrefix_("model_" + simpleModel->getNamespace())
+{
+  addParameter_(new Parameter("RE08.lambda", lambda, &Parameter::R_PLUS));  
+  addParameter_(new Parameter("RE08.mu", mu, &Parameter::R_PLUS));
+  simpleModel_->setNamespace("RE08." + nestedPrefix_);
+  addParameters_(simpleModel->getParameters());
+  //We need to overrired this from the AbstractSubstitutionModel constructor,
+  //since the number of states in the model is no longer equal to the size of the alphabet.
+  size_ = simpleModel->getNumberOfStates() + 1;
+  chars_.insert(chars_.begin(), -1);
+  generator_.resize(size_, size_);
+  exchangeability_.resize(size_, size_);
+  freq_.resize(size_);
+  eigenValues_.resize(size_);
+  leftEigenVectors_.resize(size_, size_);
+  rightEigenVectors_.resize(size_, size_);
+  p_.resize(size_,size_);
+  updateMatrices();
+}
+
+/******************************************************************************/
+  
+void RE08::updateMatrices()
+{
+  double f = (lambda_ == 0 && mu_ == 0) ? 1 : lambda_ / (lambda_ + mu_);
+  
+  // Frequencies:
+  for(size_t i = 0; i < size_ - 1; i++)
+    freq_[i] = simpleModel_->freq(i) * f;
+
+  freq_[size_-1] = (1. - f);
+
+  simpleGenerator_ = simpleModel_->getGenerator();
+  simpleExchangeabilities_ = simpleModel_->getExchangeabilityMatrix();
+
+  // Generator and exchangeabilities:
+  for (size_t i = 0; i < size_ - 1; i++)
+  {
+    for (size_t j = 0; j < size_ - 1; j++)
+    {
+      generator_(i, j) = simpleGenerator_(i, j);
+      exchangeability_(i, j) = simpleExchangeabilities_(i, j) / f;
+      if (i == j) 
+      {
+        generator_(i, j) -= mu_;
+        exchangeability_(i, j) -= (mu_ / f) / simpleModel_->freq(i);
+      }
+    }
+    generator_(i, size_ - 1) = mu_;
+    generator_(size_ - 1, i) = lambda_ * simpleModel_->freq(i);
+    exchangeability_(i, size_ - 1) = lambda_ + mu_;
+    exchangeability_(size_ - 1, i) = lambda_ + mu_;
+  }
+  generator_(size_ - 1, size_ - 1) = -lambda_;
+  exchangeability_(size_ - 1, size_ - 1) = -(lambda_ + mu_); 
+
+  //It is very likely that we are able to compute the eigen values and vector from the one of the simple model.
+  //For now however, we will use a numerical diagonalization:
+  AbstractSubstitutionModel::updateMatrices();
+  //We do not use the one from  AbstractReversibleSubstitutionModel, since we already computed the generator.
+}
+  
+/******************************************************************************/
+
+double RE08::Pij_t(size_t i, size_t j, double d) const
+{
+  double f = (lambda_ == 0 && mu_ == 0) ? 1. : lambda_ / (lambda_ + mu_);
+  if(i < size_ - 1 && j < size_ - 1)
+  {
+    return (simpleModel_->Pij_t(i, j, d) - simpleModel_->freq(j)) * exp(-mu_ * d)
+      + freq_[j] + (simpleModel_->freq(j) - freq_[j]) * exp(-(lambda_ + mu_) * d);
+  }
+  else
+  {
+    if (i == size_ - 1)
+    {
+      if (j < size_ - 1)
+      {
+        return freq_[j] * (1. - exp(-(lambda_ + mu_) * d));
+      }
+      else
+      {
+        return 1. - f * (1. - exp(-(lambda_ + mu_) * d));
+      }
+    }
+    else
+    {  
+      return freq_[j] * (1. - exp(-(lambda_ + mu_) * d));
+    }
+  }
+}
+
+/******************************************************************************/
+
+double RE08::dPij_dt(size_t i, size_t j, double d) const
+{
+  double f = (lambda_ == 0 && mu_ == 0) ? 1. : lambda_ / (lambda_ + mu_);
+  if(i < size_ - 1 && j < size_ - 1)
+  {
+    return simpleModel_->dPij_dt(i, j, d) * exp(-mu_ * d)
+      - mu_ * (simpleModel_->Pij_t(i, j, d) - simpleModel_->freq(j)) * exp(-mu_ * d)
+      - (lambda_ + mu_) * (simpleModel_->freq(j) - freq_[j]) * exp(-(lambda_ + mu_) * d);
+  }
+  else
+  {
+    if (i == size_ - 1)
+    {
+      if (j < size_ - 1)
+      {
+        return (lambda_ + mu_) * freq_[j] * exp(-(lambda_ + mu_) * d);
+      }
+      else
+      {
+        return - f * (lambda_ + mu_) * exp(-(lambda_ + mu_) * d);
+      }
+    }
+    else
+    {  
+      return (lambda_ + mu_) * freq_[j] * exp(-(lambda_ + mu_) * d);
+    }
+  }
+}
+
+/******************************************************************************/
+
+double RE08::d2Pij_dt2(size_t i, size_t j, double d) const
+{
+  double f = (lambda_ == 0 && mu_ == 0) ? 1. : lambda_ / (lambda_ + mu_);
+  if(i < size_ - 1 && j < size_ - 1)
+  {
+    return simpleModel_->d2Pij_dt2(i, j, d) * exp(-mu_ * d)
+      - 2 * mu_ * simpleModel_->dPij_dt(i, j, d) * exp(-mu_ * d)
+      + mu_ * mu_ * (simpleModel_->Pij_t(i, j, d) - simpleModel_->freq(j)) * exp(-mu_ * d)
+      + (lambda_ + mu_) * (lambda_ + mu_) * (simpleModel_->freq(j) - freq_[j]) * exp(-(lambda_ + mu_) * d);
+  }
+  else
+  {
+    if (i == size_ - 1)
+    {
+      if (j < size_ - 1)
+      {
+        return - (lambda_ + mu_) * (lambda_ + mu_) * freq_[j] * exp(-(lambda_ + mu_) * d);
+      }
+      else
+      {
+        return f * (lambda_ + mu_) * (lambda_ + mu_) * exp(-(lambda_ + mu_) * d);
+      }
+    }
+    else
+    {  
+      return - (lambda_ + mu_) * (lambda_ + mu_) * freq_[j] * exp(-(lambda_ + mu_) * d);
+    }
+  }
+}
+
+/******************************************************************************/
+
+const Matrix<double> & RE08::getPij_t(double d) const
+{
+  RowMatrix<double> simpleP = simpleModel_->getPij_t(d);
+  double f = (lambda_ == 0 && mu_ == 0) ? 1. : lambda_ / (lambda_ + mu_);
+  for (size_t i = 0; i < size_ - 1; i++)
+  {
+    for (size_t j = 0; j < size_ - 1; j++)
+    {
+      p_(i, j) = (simpleP(i, j) - simpleModel_->freq(j)) * exp(-mu_ * d)
+          + freq_[j] + (simpleModel_->freq(j) - freq_[j]) * exp(-(lambda_ + mu_) * d);
+    }
+  }
+  for(size_t j = 0; j < size_ - 1; j++)
+  {
+    p_(size_ - 1, j) = freq_[j] * (1. - exp(-(lambda_ + mu_) * d));
+  }
+  p_(size_ - 1, size_ - 1) = 1. - f * (1. - exp(-(lambda_ + mu_) * d));
+  for(size_t i = 0; i < size_ - 1; i++)
+  {  
+    p_(i, size_ - 1) = freq_[size_ - 1] * (1. - exp(-(lambda_ + mu_) * d));
+  }
+  return p_;
+}
+
+/******************************************************************************/
+
+const Matrix<double> & RE08::getdPij_dt(double d) const
+{
+  RowMatrix<double> simpleP = simpleModel_->getPij_t(d);
+  RowMatrix<double> simpleDP = simpleModel_->getdPij_dt(d);
+  double f = (lambda_ == 0 && mu_ == 0) ? 1. : lambda_ / (lambda_ + mu_);
+  for (size_t i = 0; i < size_ - 1; i++)
+  {
+    for (size_t j = 0; j < size_ - 1; j++)
+    {
+      p_(i, j) = simpleDP(i, j) * exp(-mu_ * d)
+          - mu_ * (simpleP(i, j) - simpleModel_->freq(j)) * exp(-mu_ * d)
+          - (lambda_ + mu_) * (simpleModel_->freq(j) - freq_[j]) * exp(-(lambda_ + mu_) * d);
+    }
+  }
+  for (size_t j = 0; j < size_ - 1; j++)
+  {
+    p_(size_ - 1, j) = (lambda_ + mu_) * freq_[j] * exp(-(lambda_ + mu_) * d);
+  }
+  p_(size_ - 1, size_ - 1) = - f * (lambda_ + mu_) * exp(-(lambda_ + mu_) * d);
+  for (size_t i = 0; i < size_ - 1; i++)
+  {  
+    p_(i, size_ - 1) = (lambda_ + mu_) * freq_[size_ - 1] * exp(-(lambda_ + mu_) * d);
+  }
+  return p_;
+}
+
+/******************************************************************************/
+
+const Matrix<double> & RE08::getd2Pij_dt2(double d) const
+{
+  RowMatrix<double> simpleP = simpleModel_->getPij_t(d);
+  RowMatrix<double> simpleDP = simpleModel_->getdPij_dt(d);
+  RowMatrix<double> simpleD2P = simpleModel_->getd2Pij_dt2(d);
+  double f = (lambda_ == 0 && mu_ == 0) ? 1. : lambda_ / (lambda_ + mu_);
+  for (size_t i = 0; i < size_ - 1; i++)
+  {
+    for (size_t j = 0; j < size_ - 1; j++)
+    {
+      p_(i, j) = simpleD2P(i, j) * exp(-mu_ * d)
+          - 2 * mu_ * simpleDP(i, j) * exp(-mu_ * d)
+          + mu_ * mu_ * (simpleP(i, j) - simpleModel_->freq(j)) * exp(-mu_ * d)
+          + (lambda_ + mu_) * (lambda_ + mu_) * (simpleModel_->freq(j) - freq_[j]) * exp(-(lambda_ + mu_) * d);
+    }
+  }
+  for (size_t j = 0; j < size_ - 1; j++)
+  {
+    p_(size_ - 1, j) = - (lambda_ + mu_) * (lambda_ + mu_) * freq_[j] * exp(-(lambda_ + mu_) * d);
+  }
+  p_(size_ - 1, size_ - 1) = f * (lambda_ + mu_) * (lambda_ + mu_) * exp(-(lambda_ + mu_) * d);
+  for(size_t i = 0; i < size_ - 1; i++)
+  {  
+    p_(i, size_ - 1) = - (lambda_ + mu_) * (lambda_ + mu_) * freq_[size_ - 1] * exp(-(lambda_ + mu_) * d);
+  }
+  return p_;
+}
+
+/******************************************************************************/
+
+double RE08::getInitValue(size_t i, int state) const throw (IndexOutOfBoundsException, BadIntException)
+{
+  if (i >= size_) throw IndexOutOfBoundsException("RE08::getInitValue", i, 0, size_ - 1);
+  if (state < -1 || !getAlphabet()->isIntInAlphabet(state))
+    throw BadIntException(state, "RE08::getInitValue. Character " + getAlphabet()->intToChar(state) + " is not allowed in model.");
+  if (i == size_ - 1 && state == -1) return 1.;
+  vector<int> states = getAlphabet()->getAlias(state);
+  for (size_t j = 0; j < states.size(); j++)
+    if ((int)i == states[j]) return 1.;
+  return 0.;
+}
+
+/******************************************************************************/
+
+void RE08::setNamespace(const string& prefix)
+{
+  AbstractSubstitutionModel::setNamespace(prefix);
+  //We also need to update the namespace of the nested model:
+  simpleModel_->setNamespace(prefix + nestedPrefix_);
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Model/RE08.h b/src/Bpp/Phyl/Model/RE08.h
new file mode 100755
index 0000000..078fdc0
--- /dev/null
+++ b/src/Bpp/Phyl/Model/RE08.h
@@ -0,0 +1,200 @@
+//
+// File: RE08.h
+// Created by: Julien Dutheil
+// Created on: Mon Dec 29 10:15 2008
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _RE08_H_
+#define _RE08_H_
+
+#include "SubstitutionModel.h"
+#include "AbstractSubstitutionModel.h"
+
+namespace bpp
+{
+
+/**
+ * @brief The Rivas-Eddy substitution model with gap characters.
+ *
+ * This model expends any reversible substitution model with gaps as an additional state.
+ * Although the conditionnal subtitution process is reversible, the insertion/deletion process
+ * needs not be. The model hence adds two parameters for insertion and deletions, @f$\lambda at f$ and @f$\mu at f$.
+ * If we note @f$Q at f$ the (simple) transition matrix (= Markov generator) and @f$Q^\epsilon at f$ the extended one, we have: 
+ * @f[
+ * Q^\epsilon =
+ * \left(
+ * \begin{array}{ccc|c}
+ * & & & \mu \\ 
+ * & \rule{0cm}{1cm}\rule{1cm}{0cm}Q-\mu\delta_{ij} & & \vdots \\ 
+ * & & & \mu \\
+ * \hline
+ * \lambda\pi_1 & \ldots & \lambda\pi_n & -\lambda \\ 
+ * \end{array}
+ * \right)
+ * @f]
+ * where @f$n at f$ is the number of states of the simple model (in most case equal to the size of the alphabet) and @f$(\pi_1,\ldots,\pi_n)@f$ is the vector of equilibrium frequencies of the conditional model.
+ * @f$\delta_{ij}@f$ is 1 if i=j, 0 otherwise.
+ * Note that in the original paper @f$Q at f$ is noted as @f$R at f$, and @f$Q_t at f$ is used for the probability matrix, which is referred here as @f$P^\epsilon(t)@f$ for consistency with the documentation of other models. 
+ * 
+ * The extended Markov model is reversible, and the equilibrium frequencies are
+ * @f[
+ * \pi^\epsilon = \left( \pi \cdot \frac{\lambda}{\lambda + \mu}, \frac{\mu}{\lambda + \mu}\right).
+ * @f]
+ * The corresponding exchangeability matrix is:
+ * @f[
+ * S^\epsilon = 
+ * \left(
+ * \begin{array}{ccc|c}
+ * & & & \lambda + \mu \\ 
+ * & \rule{0cm}{1cm}\rule{1cm}{0cm}(S - \frac{\mu\delta_{ij}}{\pi_i})\frac{\lambda+\mu}{\lambda} & & \vdots \\ 
+ * & & & \lambda + \mu \\
+ * \hline
+ * \lambda + \mu & \ldots & \lambda + \mu & - (\lambda + \mu) \\ 
+ * \end{array}
+ * \right)
+ * @f]
+ * The eigen values and vectors are computed numerically, but the transition probabilities are computed analytically from the simple substitution model, together with the first and second order derivatives according to time.
+ *
+ * Please note that the original Rivas and Eddy method uses this substitution model with a modification of the Felsenstein algorithm.
+ *
+ * Reference:
+ * - Rivas E and Eddy SR (2008), _Probabilistic Phylogenetic Inference with Insertions and Deletions_, 4(9):e1000172, in _PLoS Computational Biology_. 
+ */
+class RE08:
+  public AbstractReversibleSubstitutionModel
+{
+  private:
+    ReversibleSubstitutionModel* simpleModel_;
+    RowMatrix<double> simpleGenerator_;
+    RowMatrix<double> simpleExchangeabilities_;
+    mutable double exp_;
+    mutable RowMatrix<double> p_;
+    double lambda_;
+    double mu_;
+    std::string nestedPrefix_;
+
+	public:
+    /**
+     * @brief Build a new Rivas & Eddy model from a standard substitution model.
+     * 
+     * The alphabet and number of states for the extended model will be derived from the simple one.
+     *
+     * @param simpleModel The simple model to use to build the extended one.
+     * THE RE08 class will own the simple one, meaning that it will be destroyed together with the RE08 instance, and cloned when cloning the RE08 instance.
+     * To prevent the original simple model to be destroyed, you should make a copy of it before creating the RE08 instance.
+     * @param lambda Insertion rate.
+     * @param mu     Deletion rate.
+     */
+		RE08(ReversibleSubstitutionModel* simpleModel, double lambda = 0, double mu = 0);
+
+    RE08(const RE08& model):
+      AbstractParameterAliasable(model),
+      AbstractSubstitutionModel(model),
+      AbstractReversibleSubstitutionModel(model),
+      simpleModel_(dynamic_cast<ReversibleSubstitutionModel*>(model.simpleModel_->clone())),
+      simpleGenerator_(model.simpleGenerator_),
+      simpleExchangeabilities_(model.simpleExchangeabilities_),
+      exp_(model.exp_),
+      p_(model.p_),
+      lambda_(model.lambda_),
+      mu_(model.mu_),
+      nestedPrefix_(model.nestedPrefix_)
+    {}
+
+    RE08& operator=(const RE08& model)
+    {
+      AbstractParameterAliasable::operator=(model);
+      AbstractSubstitutionModel::operator=(model);
+      AbstractReversibleSubstitutionModel::operator=(model);
+      simpleModel_             = dynamic_cast<ReversibleSubstitutionModel*>(model.simpleModel_->clone());
+      simpleGenerator_         = model.simpleGenerator_;
+      simpleExchangeabilities_ = model.simpleExchangeabilities_;
+      exp_                     = model.exp_;
+      p_                       = model.p_;
+      lambda_                  = model.lambda_;
+      mu_                      = model.mu_;
+      nestedPrefix_            = model.nestedPrefix_;
+      return *this;
+    }
+
+		virtual ~RE08() { delete simpleModel_; }
+
+    RE08* clone() const { return new RE08(*this); }
+
+  public:
+	
+		double Pij_t    (size_t i, size_t j, double d) const;
+		double dPij_dt  (size_t i, size_t j, double d) const;
+		double d2Pij_dt2(size_t i, size_t j, double d) const;
+		const Matrix<double>& getPij_t    (double d) const;
+		const Matrix<double>& getdPij_dt  (double d) const;
+		const Matrix<double>& getd2Pij_dt2(double d) const;
+
+    std::string getName() const { return "RE08"; }
+
+    /**
+     * @brief This method is forwarded to the simple model.
+     *
+     * @param data The data to be passed to the simple model (gaps will be ignored).
+     */
+    void setFreqFromData(const SequenceContainer& data) {}
+	
+    void fireParameterChanged(const ParameterList& parameters)
+    {
+      AbstractParameterAliasable::fireParameterChanged(parameters);      
+      simpleModel_->matchParametersValues(parameters);
+      lambda_ = getParameter_(0).getValue();
+      mu_     = getParameter_(1).getValue();
+      updateMatrices();
+    }
+
+    size_t getNumberOfStates() const { return size_; }
+
+    double getInitValue(size_t i, int state) const throw (IndexOutOfBoundsException, BadIntException);
+  
+    void setNamespace(const std::string& prefix);
+
+    const SubstitutionModel* getNestedModel() const { return simpleModel_; }
+
+  protected:
+
+		void updateMatrices();
+};
+
+} //end of namespace bpp.
+
+#endif	//_RE08_H_
+
diff --git a/src/Bpp/Phyl/Model/RateDistribution/ConstantRateDistribution.h b/src/Bpp/Phyl/Model/RateDistribution/ConstantRateDistribution.h
new file mode 100644
index 0000000..8143e78
--- /dev/null
+++ b/src/Bpp/Phyl/Model/RateDistribution/ConstantRateDistribution.h
@@ -0,0 +1,66 @@
+//
+// File: ConstantRateDistribution.h
+// Created by: Julien Dutheil
+// Created on: Fri Nov 16 14:37 2012
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2012)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _CONSTANTRATEDISTRIBUTION_H_
+#define _CONSTANTRATEDISTRIBUTION_H_
+
+//From bpp-core
+#include <Bpp/Numeric/Prob/ConstantDistribution.h>
+
+namespace bpp {
+
+class ConstantRateDistribution:
+  public ConstantDistribution
+{
+  public:
+    ConstantRateDistribution():
+      AbstractParameterAliasable("Constant."),
+      ConstantDistribution(1.)
+    {
+      deleteParameter_(0);
+    }
+
+    ConstantRateDistribution* clone() const { return new ConstantRateDistribution(*this); }
+    
+};
+
+} //end of namespace bpp;
+
+#endif //_CONSTANTRATEDISTRIBUTION_H_
+
diff --git a/src/Bpp/Phyl/Model/RateDistribution/ExponentialDiscreteRateDistribution.h b/src/Bpp/Phyl/Model/RateDistribution/ExponentialDiscreteRateDistribution.h
new file mode 100644
index 0000000..e647f63
--- /dev/null
+++ b/src/Bpp/Phyl/Model/RateDistribution/ExponentialDiscreteRateDistribution.h
@@ -0,0 +1,66 @@
+//
+// File: ExponentialDiscreteRateDistribution.h
+// Created by: Julien Dutheil
+// Created on: Fri Nov 16 14:37 2012
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2012)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _EXPONENTIALDISCRETERATEDISTRIBUTION_H_
+#define _EXPONENTIALDISCRETERATEDISTRIBUTION_H_
+
+//From bpp-core
+#include <Bpp/Numeric/Prob/ExponentialDiscreteDistribution.h>
+
+namespace bpp {
+
+class ExponentialDiscreteRateDistribution:
+  public ExponentialDiscreteDistribution
+{
+  public:
+    ExponentialDiscreteRateDistribution(size_t nbClasses):
+      AbstractParameterAliasable("Exponential."),
+      ExponentialDiscreteDistribution(nbClasses, 1.)
+    {
+      deleteParameter_(0);
+    }
+
+    ExponentialDiscreteRateDistribution* clone() const { return new ExponentialDiscreteRateDistribution(*this); }
+    
+};
+
+} //end of namespace bpp;
+
+#endif //_EXPONENTIALDISCRETERATEDISTRIBUTION_H_
+
diff --git a/src/Bpp/Phyl/Model/RateDistribution/GammaDiscreteRateDistribution.h b/src/Bpp/Phyl/Model/RateDistribution/GammaDiscreteRateDistribution.h
new file mode 100644
index 0000000..5159ec1
--- /dev/null
+++ b/src/Bpp/Phyl/Model/RateDistribution/GammaDiscreteRateDistribution.h
@@ -0,0 +1,66 @@
+//
+// File: GammaDiscreteRateDistribution.h
+// Created by: Julien Dutheil
+// Created on: Fri Nov 16 14:37 2012
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2012)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _GAMMADISCRETERATEDISTRIBUTION_H_
+#define _GAMMADISCRETERATEDISTRIBUTION_H_
+
+//From bpp-core
+#include <Bpp/Numeric/Prob/GammaDiscreteDistribution.h>
+
+namespace bpp {
+
+class GammaDiscreteRateDistribution:
+  public GammaDiscreteDistribution
+{
+  public:
+    GammaDiscreteRateDistribution(size_t nbClasses, double alpha = 1.):
+      AbstractParameterAliasable("Gamma."),
+      GammaDiscreteDistribution(nbClasses, alpha, alpha)
+    {
+      aliasParameters("alpha", "beta");
+    }
+
+    GammaDiscreteRateDistribution* clone() const { return new GammaDiscreteRateDistribution(*this); }
+    
+};
+
+} //end of namespace bpp;
+
+#endif //_GAMMADISCRETERATEDISTRIBUTION_H_
+
diff --git a/src/Bpp/Phyl/Model/RateDistribution/GaussianDiscreteRateDistribution.h b/src/Bpp/Phyl/Model/RateDistribution/GaussianDiscreteRateDistribution.h
new file mode 100644
index 0000000..75eb37e
--- /dev/null
+++ b/src/Bpp/Phyl/Model/RateDistribution/GaussianDiscreteRateDistribution.h
@@ -0,0 +1,66 @@
+//
+// File: GaussianDiscreteRateDistribution.h
+// Created by: Julien Dutheil
+// Created on: Fri Nov 16 14:37 2012
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2012)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _GAUSSIANDISCRETERATEDISTRIBUTION_H_
+#define _GAUSSIANDISCRETERATEDISTRIBUTION_H_
+
+//From bpp-core
+#include <Bpp/Numeric/Prob/GaussianDiscreteDistribution.h>
+
+namespace bpp {
+
+class GaussianDiscreteRateDistribution:
+  public GaussianDiscreteDistribution
+{
+  public:
+    GaussianDiscreteRateDistribution(size_t nbClasses, double sigma):
+      AbstractParameterAliasable("Gaussian."),
+      GaussianDiscreteDistribution(nbClasses, 1., sigma)
+    {
+      deleteParameter_(0);
+    }
+
+    GaussianDiscreteRateDistribution* clone() const { return new GaussianDiscreteRateDistribution(*this); }
+    
+};
+
+} //end of namespace bpp;
+
+#endif //_GAUSSIANDISCRETERATEDISTRIBUTION_H_
+
diff --git a/src/Bpp/Phyl/Model/RateDistributionFactory.cpp b/src/Bpp/Phyl/Model/RateDistributionFactory.cpp
new file mode 100644
index 0000000..5c5767c
--- /dev/null
+++ b/src/Bpp/Phyl/Model/RateDistributionFactory.cpp
@@ -0,0 +1,64 @@
+//
+// File: RateDistributionFactory.cpp
+// Created by: Julien Dutheil
+//             Vincent Ranwez
+// Created on: Fri apr 14 11:11 2006
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "RateDistributionFactory.h"
+
+#include "RateDistribution/ConstantRateDistribution.h"
+#include "RateDistribution/GammaDiscreteRateDistribution.h"
+#include "RateDistribution/GaussianDiscreteRateDistribution.h"
+#include "RateDistribution/ExponentialDiscreteRateDistribution.h"
+
+using namespace bpp;
+using namespace std;
+
+const string RateDistributionFactory::CONSTANT_DISTRIBUTION = "Constant";
+const string RateDistributionFactory::GAMMA_DISTRIBUTION = "Gamma";
+const string RateDistributionFactory::GAUSSIAN_DISTRIBUTION = "Gaussian";
+const string RateDistributionFactory::EXPONENTIAL_DISTRIBUTION = "Exponential";
+
+DiscreteDistribution* RateDistributionFactory::createDiscreteDistribution(const string& distName, unsigned int nbClasses) throw (Exception)
+{
+       if (distName == GAMMA_DISTRIBUTION) return new GammaDiscreteRateDistribution(nbClasses);
+  else if (distName == GAUSSIAN_DISTRIBUTION) return new GaussianDiscreteRateDistribution(nbClasses, 1.);
+  else if (distName == EXPONENTIAL_DISTRIBUTION) return new ExponentialDiscreteRateDistribution(nbClasses);
+  else if (distName == CONSTANT_DISTRIBUTION) return new ConstantRateDistribution();
+  else throw Exception("RateDistributionFactory::createDistribution(). Unknown rate distribution: " + distName);
+}
+
diff --git a/src/Bpp/Phyl/Model/RateDistributionFactory.h b/src/Bpp/Phyl/Model/RateDistributionFactory.h
new file mode 100644
index 0000000..79a5fe5
--- /dev/null
+++ b/src/Bpp/Phyl/Model/RateDistributionFactory.h
@@ -0,0 +1,110 @@
+//
+// File: RateDistributionFactory.h
+// Created by: Julien Dutheil
+//             Vincent Ranwez
+// Created on: Fri apr 14 11:11 2006
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _RATEDISTRIBUTIONFACTORY_H_
+#define _RATEDISTRIBUTIONFACTORY_H_
+
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+
+// From the STL:
+#include <string>
+
+namespace bpp
+{
+
+/**
+ * @brief Utilitary class for creating rate distributions.
+ *
+ * @see SubstitutionModelFactory
+ */
+class RateDistributionFactory
+{
+public:
+  static const std::string CONSTANT_DISTRIBUTION;
+  static const std::string GAMMA_DISTRIBUTION;
+  static const std::string GAUSSIAN_DISTRIBUTION;
+  static const std::string EXPONENTIAL_DISTRIBUTION;
+
+private:
+  unsigned int nbClasses_; // For discrete distributions. 
+  
+public:
+  /**
+   * @brief Creates a new factory object.
+   *
+   * Example:
+   * @code
+   * DiscreteDistribution* dist = RateDistributionFactory().createDiscreteDistribution(RateDistributionFactory::GAMMA_DISTRIBUTION);
+   * // or DiscreteDistribution* dist = RateDistributionFactory(10).createDiscreteDistribution(RateDistributionFactory::GAMMA_DISTRIBUTION);
+   * // or DiscreteDistribution* dist = RateDistributionFactory().createDiscreteDistribution(RateDistributionFactory::GAMMA_DISTRIBUTION, 10);
+   * // dist can be used in any object dealing with rate distributions.
+   * @endcode
+   */
+  RateDistributionFactory(unsigned int nbClasses = 4): nbClasses_(nbClasses) {}
+  virtual ~RateDistributionFactory() {}
+
+public:
+  /**
+   * @brief Get a new dynamically created DiscreteDistribution object.
+   *
+   * @param distName The name of the distribution to use.
+   * @param nbClasses The number of classes to use. This override the value passed to the constructor and is ignored for a constant distribution.
+   * @return A pointer toward a new discrete distribution, with default parameter values.
+   * @throw Exception If the dist name do not match any available distribution.
+   */
+  virtual DiscreteDistribution* createDiscreteDistribution(const std::string& distName, unsigned int nbClasses) throw (Exception);
+  /**
+   * @brief Get a new dynamically created DiscreteDistribution object.
+   *
+   * @param distName The name of the distribution to use.
+   * @return A pointer toward a new discrete distribution, with default parameter values.
+   * @throw Exception If the dist name do not match any available distribution.
+   */
+  virtual DiscreteDistribution* createDiscreteDistribution(const std::string& distName) throw (Exception)
+  {
+    return createDiscreteDistribution(distName, nbClasses_);
+  }
+
+};
+
+} //end of namespace bpp.
+
+#endif //_RATEDISTRIBUTIONFACTORY_H_
+
diff --git a/src/Bpp/Phyl/Model/StateMap.cpp b/src/Bpp/Phyl/Model/StateMap.cpp
new file mode 100644
index 0000000..b2c9730
--- /dev/null
+++ b/src/Bpp/Phyl/Model/StateMap.cpp
@@ -0,0 +1,53 @@
+//
+// File: StateMap.cpp
+// Created by: Julien Dutheil
+// Created on: Wed Jun 13 15:03 2012
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "StateMap.h"
+
+using namespace bpp;
+
+CanonicalStateMap::CanonicalStateMap(const Alphabet* alphabet, bool includeGaps):
+  AbstractStateMap(alphabet)
+{
+  for (unsigned int i = 0; i < alphabet->getSize(); ++i) {
+    states_.push_back(i);
+  }
+  if (includeGaps)
+    states_.push_back(alphabet->getGapCharacterCode());
+}
+
diff --git a/src/Bpp/Phyl/Model/StateMap.h b/src/Bpp/Phyl/Model/StateMap.h
new file mode 100644
index 0000000..0c3011b
--- /dev/null
+++ b/src/Bpp/Phyl/Model/StateMap.h
@@ -0,0 +1,166 @@
+//
+// File: StateMap.h
+// Created by: Julien Dutheil
+// Created on: Wed Jun 13 15:03 2012
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _STATEMAP_H_
+#define _STATEMAP_H_
+
+#include <Bpp/Clonable.h>
+#include <Bpp/Seq/Alphabet/Alphabet.h>
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+//From the STL:
+#include <vector>
+#include <string>
+
+namespace bpp
+{
+
+  /**
+   * @brief Map the states of a given alphabet which have a model state.
+   */
+  class StateMap:
+    public virtual Clonable
+  {
+    public:
+      virtual ~StateMap() {}
+      virtual StateMap* clone() const = 0;
+
+    public:
+      /**
+       * @return The associated alphabet.
+       */
+      virtual const Alphabet* getAlphabet() const = 0;
+
+      /**
+       * @return The number of states supported by the model.
+       */
+      virtual size_t getNumberOfStates() const = 0;
+
+      /**
+       * @param index The model state.
+       * @return The corresponding alphabet character as int code.
+       */
+      virtual int stateAsInt(size_t index) const = 0;
+
+      /**
+       * @param index The model state.
+       * @return The corresponding alphabet character as character code.
+       */
+      virtual std::string stateAsChar(size_t index) const = 0;
+
+      /**
+       * @param code The int code of the character to check.
+       * @return The corresponding model state, is any.
+       */
+      virtual size_t whichState(int code) const = 0;
+      
+      /**
+       * @param code The character code of the character to check.
+       * @return The corresponding model state, is any.
+       */
+      virtual size_t whichState(const std::string& code) const = 0;
+  };
+
+  /**
+   * @brief A convenience partial implementation of the StateMap interface.
+   *
+   * Model states are stored as their corresponding int codes, stored in a vector 'states_'.
+   * This vector has to be initialized and filled by the derived class.
+   */
+  class AbstractStateMap:
+    public virtual StateMap
+  {
+    protected:
+      const Alphabet* alphabet_;
+      std::vector<int> states_;
+
+    public:
+      AbstractStateMap(const Alphabet* alphabet):
+        alphabet_(alphabet),
+        states_()
+      {}
+
+      AbstractStateMap(const AbstractStateMap& absm):
+        alphabet_(absm.alphabet_),
+        states_(absm.states_)
+      {}
+
+      AbstractStateMap& operator=(const AbstractStateMap& absm)
+      {
+        alphabet_ = absm.alphabet_;
+        states_ = absm.states_;
+        return *this;
+      }
+
+    public:
+      virtual const Alphabet* getAlphabet() const { return alphabet_; }
+      virtual size_t getNumberOfStates() const { return states_.size(); }
+      virtual int stateAsInt(size_t index) const { return states_[index]; }
+      virtual std::string stateAsChar(size_t index) const { return alphabet_->intToChar(states_[index]); }
+      virtual size_t whichState(int code) const throw (Exception) {
+        try { return VectorTools::which(states_, code); }
+        catch (ElementNotFoundException<int>& ex) { throw Exception("AbstractStateMap::whichState. Unsupported alphabet char: " + code); }
+      }
+      virtual size_t whichState(const std::string& code) const throw (Exception) {
+        try { return VectorTools::which(states_, alphabet_->charToInt(code)); }
+        catch (ElementNotFoundException<int>& ex) { throw Exception("AbstractStateMap::whichState. Unsupported alphabet char: " + code); }
+      }
+
+  };
+
+  /**
+   * @brief This class implements a state map where all resolved states are modeled.
+   *
+   * For nucleotides, the underlying states are for instance: A (0), C (1), G (2), T/U (3).
+   * Optionally, gaps can be modeled.
+   */
+  class CanonicalStateMap:
+    public AbstractStateMap
+  {
+    public:
+      CanonicalStateMap(const Alphabet* alphabet, bool includeGaps);
+      virtual CanonicalStateMap* clone() const { return new CanonicalStateMap(*this); }
+
+  };
+
+}// end of namespace bpp
+
+#endif //_STATEMAP_H_
+
diff --git a/src/Bpp/Phyl/Model/SubstitutionModel.h b/src/Bpp/Phyl/Model/SubstitutionModel.h
new file mode 100755
index 0000000..dd5a518
--- /dev/null
+++ b/src/Bpp/Phyl/Model/SubstitutionModel.h
@@ -0,0 +1,493 @@
+//
+// File: SubstitutionModel.h
+// Created by: Julien Dutheil
+// Created on: Mon May 26 14:52:34 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _SUBSTITUTIONMODEL_H_
+#define _SUBSTITUTIONMODEL_H_
+
+#include <cstdlib>
+#include <map>
+#include <string>
+
+#include <Bpp/Exceptions.h>
+#include <Bpp/Numeric/Parameter.h>
+#include <Bpp/Numeric/ParameterList.h>
+#include <Bpp/Numeric/ParameterAliasable.h>
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Matrix/Matrix.h>
+
+//From Seqlib:
+#include <Bpp/Seq/Alphabet/Alphabet.h>
+#include <Bpp/Seq/Container/SequenceContainer.h>
+#include "FrequenciesSet/FrequenciesSet.h"
+
+namespace bpp
+{
+class SubstitutionModel;
+
+/**
+ * @brief Exception that may be thrown by susbstitution models.
+ *
+ * @see SubstitutionModel
+ */
+class SubstitutionModelException :
+  public Exception
+{
+protected:
+  const SubstitutionModel* model_;
+
+public:
+  SubstitutionModelException(const std::string& text, const SubstitutionModel* sm = 0);
+
+  SubstitutionModelException(const SubstitutionModelException& sme) :
+    Exception(sme), model_(sme.model_) {}
+
+  SubstitutionModelException& operator=(const SubstitutionModelException& sme)
+  {
+    Exception::operator=(sme);
+    model_ = sme.model_;
+    return *this;
+  }
+
+  ~SubstitutionModelException() throw ();
+
+public:
+  /**
+   * @brief Get the model that throws the exception.
+   *
+   * @return The model that throws the exception.
+   */
+  virtual const SubstitutionModel* getSubstitutionModel() const { return model_; }
+};
+
+/**
+ * @brief Interface for all substitution models.
+ *
+ * A substitution model is based on a Markov generator \f$Q\f$, the size of
+ * which depends on the alphabet used (4 for nucleotides, 20 for proteins, etc.).
+ * Each SubstitutionModel object hence includes a pointer toward an alphabet,
+ * and provides a method to retrieve the alphabet used (getAlphabet() method).
+ *
+ * What we want from a substitution model is to compute the probabilities of state
+ * j at time t geven state j at time 0 (\f$P_{i,j}(t)\f$).
+ * Typically, this is computed using the formula
+ * \f[
+ * P(t) = e^{r \times t \times Q},
+ * \f]
+ * where \f$P(t)\f$ is the matrix with all probabilities \f$P_{i,j}(t)\f$, and
+ * \f$ r \f$ the rate.
+ * For some models, the \f$P_{i,j}(t)\f$'s can be computed analytically.
+ *
+ * For more complex models, we need to use a eigen-decomposition of \f$Q\f$:
+ * \f[ Q = U^{-1} . D . U, \f]
+ * where \f$D = diag(\lambda_i)\f$ is a diagonal matrix.
+ * Hence
+ * \f[
+ * P(t) = e^{r \times t \times Q} = U^{-1} . e^{r \times D \times t} . U,
+ * \f]
+ * where \f$e^{r \times D \times t} = diag\left(e^{r \times \lambda_i \times t}\right)\f$ is a
+ * diagonal matrix with all terms equal to exp the terms in \f$D\f$ multiplied per \f$ r \times t \f$.
+ * \f$U\f$ is the matrix of left eigen vectors (by row), and \f$U^{-1}\f$ is the matrix
+ * of right eigen vectors (by column).
+ * The values in \f$D\f$ are the eigen values of \f$Q\f$.
+ * All \f$Q,U,U^{-1}\f$ and \f$D\f$ (its diagonal) may be retrieved from the
+ * class (getEigenValues(), getRowRightEigenVectors() and getColumnLeftEigenVectors()
+ * functions).
+ *
+ * First and second order derivatives of \f$P(t)\f$ with respect to \f$t\f$
+ * can also be retrieved.
+ * These methods may be useful for optimization processes.
+ * Derivatives may be computed analytically, or using the general formulas:
+ * \f[
+ * \frac{\partial P(t)}{\partial t} =
+ * U^{-1} . diag\left(r \times \lambda_i \times e^{r \times \lambda_i \times t}\right) . U
+ * \f]
+ * and
+ * \f[
+ * \frac{\partial^2 P(t)}{\partial t^2} =
+ * U^{-1} . diag\left(r^2 \times \lambda_i^2 \times e^{r \times \lambda_i \times t}\right) . U
+ * \f]
+ *
+ *
+ * If Q is not symmetric, then the eigenvalue matrix D is block diagonal
+ * with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
+ * a + i*b, in 2-by-2 blocks, [a, b; -b, a].  That is, if the complex
+ * eigenvalues look like
+ * <pre>
+ * 
+ *           a + ib   .        .    .
+ *           .        a - ib   .    .
+ *           .        .        x    .
+ *           .        .        .    y
+ * </pre>
+ * then D looks like
+ * <pre>
+ * 
+ *           a          b      .    .
+ *          -b          a      .    .
+ *           .          .      x    .
+ *           .          .      .    y
+ * </pre>
+ *
+ * and exp(tD) equals
+ * <pre>
+ * 
+ *           exp(ta)cos(tb)   exp(ta)sin(tb)  .        .
+ *          -exp(ta)sin(tb)   exp(ta)cos(tb)  .        . 
+ *           .                .               exp(tx)  .
+ *           .                .               .        exp(ty)
+ * </pre>
+ *
+ *
+ *
+ * If U is singular, it cannot be inverted. In this case exp(tQ) is
+ * approximated using Taylor decomposition:
+ *
+ * \f[
+ * P(t) = Id + tQ + \frac{(tQ)^2}{2!} + ... + \frac{(tQ)^n}{n!} + ... 
+ * \f]
+ *
+ * To prevent approximation issues, if @\f$ max(tQ) @\f$ is too high
+ * (currently above 0.5), @\f$ t @\f$ is divided in an ad hoc way
+ * (e.g. by @\f$ N @\f$), and we compute @\f$ P(t) = (P(t/N))^N @\f$
+ * with a Taylor decomposition for @\f$ P(t/N) @\f$.
+ *
+ * In this case, derivatives according to @\f$ t @\f$ are computed
+ * analytically too.
+ *
+ */
+
+class SubstitutionModel :
+  public virtual ParameterAliasable
+{
+public:
+  SubstitutionModel() {}
+  virtual ~SubstitutionModel() {}
+
+#ifndef NO_VIRTUAL_COV
+  SubstitutionModel* clone() const = 0;
+#endif
+
+public:
+  /**
+   * @brief Get the name of the model.
+   *
+   * @return The name of this model.
+   */
+  virtual std::string getName() const = 0;
+
+  /**
+   * @return The supported states of the model, as a vector of int codes.
+   *
+   * @see Alphabet
+   */
+  virtual const std::vector<int>& getAlphabetChars() const = 0;
+
+  /**
+   * @brief Get the char in the alphabet corresponding to a given state in the model.
+   *
+   * In most cases, this method will return i.
+   * @param i The index of the state.
+   * @return The corresponding state in the alphabet.
+   * @see MarkovModulatedSubstitutionModel
+   * @see getStates()
+   */
+  virtual int getAlphabetChar(size_t i) const = 0;
+
+  /**
+   * @brief Get the state in the model corresponding to a particular char in the alphabet.
+   *
+   * @param i The alphabet char to check.
+   * @return A vector of indices of model states.
+   */
+  virtual std::vector<size_t> getModelStates(int i) const = 0;
+
+  /**
+   * @return Equilibrium frequency associated to character i.
+   * @see getFrequencies(), getStates()
+   */
+  virtual double freq(size_t i) const = 0;
+
+  /**
+   * @return The rate in the generator of change from state i to state j.
+   *
+   * @see getStates();
+   */
+  virtual double Qij(size_t i, size_t j) const = 0;
+
+  /**
+   * @return The probability of change from state i to state j during time t.
+   * @see getPij_t(), getStates()
+   */
+  virtual double Pij_t(size_t i, size_t j, double t) const = 0;
+
+  /**
+   * @return The first order derivative of the probability of change from state
+   * i to state j with respect to time t, at time t.
+   * @see getdPij_dt(), getStates()
+   */
+  virtual double dPij_dt(size_t i, size_t j, double t) const = 0;
+
+  /**
+   * @return The second order derivative of the probability of change from state
+   * i to state j with respect to time t, at time t.
+   * @see getd2Pij_dt2(), getStates()
+   */
+  virtual double d2Pij_dt2(size_t i, size_t j, double t) const = 0;
+
+  /**
+   * @return A vector of all equilibrium frequencies.
+   * @see freq()
+   */
+  virtual const Vdouble& getFrequencies() const = 0;
+
+  /**
+   * @return The normalized Markov generator matrix, i.e. all
+   * normalized rates of changes from state i to state j. The
+   * generator is normalized so that
+   * (i) \f$ \forall i; \sum_j Q_{i,j} = 0 \f$, meaning that
+   * $\f$ \forall i; Q_{i,i} = -\sum_{j \neq i}Q_{i,j}\f$, and
+   * (ii) \f$ \sum_i Q_{i,i} \times \pi_i = -1\f$.
+   * This means that, under normalization, the mean rate of replacement at
+   * equilibrium is 1 and that time \f$t\f$ are measured in units of
+   * expected number of changes per site. Additionnaly, the rate_ attibute provides
+   * the possibility to increase or decrease this mean rate.
+   *
+   * See Kosiol and Goldman (2005), Molecular Biology And Evolution 22(2) 193-9.
+   * @see Qij()
+   */
+  virtual const Matrix<double>& getGenerator() const = 0;
+
+  /**
+   * @return The matrix of exchangeability terms.
+   * It is recommended that exchangeability matrix be normalized so that the normalized
+   * generator be obtained directly by the dot product \f$S . \pi\f$.
+   */
+  virtual const Matrix<double>& getExchangeabilityMatrix() const = 0;
+
+  /**
+   * @return The exchangeability between state i and state j.
+   *
+   * By definition Sij(i,j) = Sij(j,i).
+   */
+  
+  virtual double Sij(size_t i, size_t j) const = 0;
+  /**
+   * @return All probabilities of change from state i to state j during time t.
+   * @see Pij_t()
+   */
+  virtual const Matrix<double>& getPij_t(double t) const = 0;
+
+  /**
+   * @return Get all first order derivatives of the probability of change from state
+   * i to state j with respect to time t, at time t.
+   * @see dPij_dt()
+   */
+  virtual const Matrix<double>& getdPij_dt(double t) const = 0;
+
+  /**
+   * @return All second order derivatives of the probability of change from state
+   * i to state j with respect to time t, at time t.
+   * @see d2Pij_dt2()
+   */
+  virtual const Matrix<double>& getd2Pij_dt2(double t) const = 0;
+
+  /**
+   * @brief Set if eigenValues and Vectors must be computed
+   */
+  virtual void enableEigenDecomposition(bool yn) = 0;
+
+  /**
+   * @brief Tell if eigenValues and Vectors must be computed
+   */
+  virtual bool enableEigenDecomposition() = 0;
+
+  /**
+   * @return A vector with all real parts of the eigen values of the generator of this model;
+   */
+  virtual const Vdouble& getEigenValues() const = 0;
+
+  /**
+   * @return A vector with all imaginary parts of the eigen values of the generator of this model;
+   */
+  virtual const Vdouble& getIEigenValues() const = 0;
+
+  /**
+   * @return True if the model is diagonalizable in R.
+   */
+  virtual bool isDiagonalizable() const = 0;
+  
+  /**
+   * @return True is the model is non-singular.
+   */
+  virtual bool isNonSingular() const = 0;
+
+  /**
+   * @return A matrix with left eigen vectors.
+   * Each row in the matrix stands for an eigen vector.
+   */
+  virtual const Matrix<double>& getRowLeftEigenVectors() const = 0;
+
+  /**
+   * @return A matrix with right eigen vectors.
+   * Each column in the matrix stands for an eigen vector.
+   */
+  virtual const Matrix<double>& getColumnRightEigenVectors() const = 0;
+
+  /**
+   * @return Get the alphabet associated to this model.
+   */
+  virtual const Alphabet* getAlphabet() const = 0;
+
+  /**
+   * @brief Get the number of states.
+   *
+   * For most models, this equals the size of the alphabet.
+   *
+   * @return The number of different states in the model.
+   */
+  virtual size_t getNumberOfStates() const = 0;
+
+  /**
+   * This method is used to initialize likelihoods in reccursions.
+   * It typically sends 1 if i = state, 0 otherwise, where
+   * i is one of the possible states of the alphabet allowed in the model
+   * and state is the observed state in the considered sequence/site.
+   *
+   * @param i the index of the state in the model.
+   * @param state An observed state in the sequence/site.
+   * @return 1 or 0 depending if the two states are compatible.
+   * @throw IndexOutOfBoundsException if array position is out of range.
+   * @throw BadIntException if states are not allowed in the associated alphabet.
+   * @see getStates();
+   */
+  virtual double getInitValue(size_t i, int state) const throw (IndexOutOfBoundsException, BadIntException) = 0;
+
+  /**
+   * @brief Get the scalar product of diagonal elements of the generator
+   * and the frequencies vector.
+   * If the generator is normalized, then scale=1. Otherwise each element
+   * must be multiplied by 1/scale.
+   *
+   * @return Minus the scalar product of diagonal elements and the frequencies vector.
+   */
+  virtual double getScale() const = 0;
+
+  /**
+   * @brief Set the rate of the generator, defined as the scalar
+   * product of diagonal elements of the generator and the frequencies
+   * vector.
+   *
+   * When the generator is normalized, scale=1. Otherwise each element
+   * is multiplied such that the correct scale is set.
+   *
+   */
+  virtual void setScale(double scale) = 0;
+
+  /**
+   * @brief Get the rate
+   */
+  virtual double getRate() const = 0;
+
+  /**
+   * @brief Set the rate of the model (must be positive).
+   * @param rate must be positive.
+   */
+  
+  virtual void setRate(double rate) = 0;
+
+  virtual void addRateParameter() = 0;
+  
+  /**
+   * @brief Set equilibrium frequencies equal to the frequencies estimated
+   * from the data.
+   *
+   * @param data The sequences to use.
+   * @param pseudoCount A quantity @f$\psi at f$ to add to adjust the observed
+   *   values in order to prevent issues due to missing states on small data set.
+   * The corrected frequencies shall be computed as
+   * @f[
+   * \pi_i = \frac{n_i+\psi}{\sum_j (f_j+\psi)}
+   * @f]
+   */
+  virtual void setFreqFromData(const SequenceContainer& data, double pseudoCount = 0) = 0;
+
+  /**
+   * @brief Set equilibrium frequencies
+   *
+   * @param frequencies The map of the frequencies to use.
+   */
+  virtual void setFreq(std::map<int, double>& frequencies) {}
+
+  /**
+   * @brief If the model owns a FrequenciesSet, returns a pointer to
+   * it, otherwise return 0.
+   *
+   */
+
+  virtual const FrequenciesSet* getFrequenciesSet() const {return NULL;}
+};
+
+
+/**
+ * @brief Interface for reversible substitution models.
+ *
+ * For reversible models,
+ * \f[ Q = S . \pi, \f]
+ * where \f$S\f$ is a symetric matrix called the exchangeability matrix, and
+ * \f$\Pi\f$ the diagonal matrix with all equilibrium frequencies.
+ * The frequencies may be retrieved as a vector by the getFrequencies() method
+ * or individually by the freq() method.
+ * The \f$S\f$ matrix may be obtained by the getExchangeabilityMatrix().
+ */
+class ReversibleSubstitutionModel :
+  public virtual SubstitutionModel
+{
+public:
+  ReversibleSubstitutionModel() {}
+  virtual ~ReversibleSubstitutionModel() {}
+
+#ifndef NO_VIRTUAL_COV
+  ReversibleSubstitutionModel* clone() const = 0;
+#endif
+};
+
+} //end of namespace bpp.
+
+#endif  //_SUBSTITUTIONMODEL_H_
+
diff --git a/src/Bpp/Phyl/Model/SubstitutionModelFactory.cpp b/src/Bpp/Phyl/Model/SubstitutionModelFactory.cpp
new file mode 100644
index 0000000..dcbc37d
--- /dev/null
+++ b/src/Bpp/Phyl/Model/SubstitutionModelFactory.cpp
@@ -0,0 +1,188 @@
+//
+// File: SubstitutionModelFactory.cpp
+// Created by: Julien Dutheil
+//             Vincent Ranwez
+// Created on: Fri apr 14 11:11 2006
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "SubstitutionModelFactory.h"
+#include "SubstitutionModelSetTools.h"
+#include "Protein/JCprot.h"
+#include "Nucleotide/K80.h"
+#include "Nucleotide/T92.h"
+#include "Nucleotide/L95.h"
+#include "Nucleotide/F84.h"
+#include "Nucleotide/TN93.h"
+#include "Nucleotide/HKY85.h"
+#include "Nucleotide/GTR.h"
+#include "Nucleotide/SSR.h"
+#include "Protein/JTT92.h"
+#include "Protein/DSO78.h"
+#include "Protein/WAG01.h"
+#include "Protein/LG08.h"
+
+// From bpp-seq:
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <algorithm>
+
+using namespace std;
+
+const string SubstitutionModelFactory::JUKES_CANTOR                = "JC69";
+const string SubstitutionModelFactory::KIMURA_2P                   = "K80";
+const string SubstitutionModelFactory::HASEGAWA_KISHINO_YANO       = "HKY85";
+const string SubstitutionModelFactory::TAMURA_NEI                  = "TN93";
+const string SubstitutionModelFactory::GENERAL_TIME_REVERSIBLE     = "HKY85";
+const string SubstitutionModelFactory::STRAND_SYMMETRIC_REVERSIBLE = "SSR";
+const string SubstitutionModelFactory::TAMURA                      = "T92";
+const string SubstitutionModelFactory::LOBRY                       = "L95";
+const string SubstitutionModelFactory::FELSENSTEIN                 = "F84";
+const string SubstitutionModelFactory::JOHN_TAYLOR_THORNTON        = "JTT92";
+const string SubstitutionModelFactory::DAYHOFF_SCHWARTZ_ORCUTT     = "DSO78";
+const string SubstitutionModelFactory::WHELAN_AND_GOLDMAN          = "WAG";
+const string SubstitutionModelFactory::LE_GASCUEL                  = "LG08";
+
+SubstitutionModel* SubstitutionModelFactory::createModel(const string& modelName) const throw (AlphabetException, Exception)
+{
+  if (modelName == JUKES_CANTOR)
+  {
+    if (AlphabetTools::isNucleicAlphabet(alphabet_))
+      return new JCnuc(dynamic_cast<const NucleicAlphabet *>(alphabet_));
+    else
+      return new JCprot(dynamic_cast<const ProteicAlphabet *>(alphabet_));
+  }
+  else if(modelName == KIMURA_2P)
+  {
+    try { 
+      return new K80(dynamic_cast<const NucleicAlphabet *>(alphabet_));
+    } catch(Exception & e) {
+      throw AlphabetException("SubstitutionModelFactory::createInstanceOf(). K80 model requires a nucleotide alphabet.", alphabet_);
+    }
+  }
+  else if(modelName == TAMURA)
+  {
+    try { 
+      return new T92(dynamic_cast<const NucleicAlphabet *>(alphabet_));
+    } catch(Exception & e) {
+      throw AlphabetException("SubstitutionModelFactory::createInstanceOf(). T92 model requires a nucleotide alphabet.", alphabet_);
+    }
+  }
+  else if(modelName == LOBRY)
+  {
+    try { 
+      return new L95(dynamic_cast<const NucleicAlphabet *>(alphabet_));
+    } catch(Exception & e) {
+      throw AlphabetException("SubstitutionModelFactory::createInstanceOf(). L95 model requires a nucleotide alphabet.", alphabet_);
+    }
+  }
+  else if(modelName == FELSENSTEIN)
+  {
+    try { 
+      return new F84(dynamic_cast<const NucleicAlphabet *>(alphabet_));
+    } catch(Exception & e) {
+      throw AlphabetException("SubstitutionModelFactory::createInstanceOf(). T92 model requires a nucleotide alphabet.", alphabet_);
+    }
+  }
+  else if(modelName == TAMURA_NEI)
+  {
+    try { 
+      return new TN93(dynamic_cast<const NucleicAlphabet *>(alphabet_));
+    } catch(Exception & e) {
+      throw AlphabetException("SubstitutionModelFactory::createInstanceOf(). TN93 model requires a nucleotide alphabet.", alphabet_);
+    }
+  }
+  else if(modelName == HASEGAWA_KISHINO_YANO)
+  {
+    try { 
+      return new HKY85(dynamic_cast<const NucleicAlphabet *>(alphabet_));
+    } catch(Exception & e) {
+      throw AlphabetException("SubstitutionModelFactory::createInstanceOf(). HKY85 model requires a nucleotide alphabet.", alphabet_);
+    }
+  }
+  else if(modelName == GENERAL_TIME_REVERSIBLE)
+  {
+    try { 
+      return new GTR(dynamic_cast<const NucleicAlphabet *>(alphabet_));
+    } catch(Exception & e) {
+      throw AlphabetException("SubstitutionModelFactory::createInstanceOf(). GTR model requires a nucleotide alphabet.", alphabet_);
+    }
+  }
+  else if(modelName == STRAND_SYMMETRIC_REVERSIBLE)
+  {
+    try { 
+      return new SSR(dynamic_cast<const NucleicAlphabet *>(alphabet_));
+    } catch(Exception & e) {
+      throw AlphabetException("SubstitutionModelFactory::createInstanceOf(). SSR model requires a nucleotide alphabet.", alphabet_);
+    }
+  }
+  else if(modelName == JOHN_TAYLOR_THORNTON)
+  {
+    try { 
+      return new JTT92(dynamic_cast<const ProteicAlphabet *>(alphabet_));
+    } catch(Exception & e) {
+      throw AlphabetException("SubstitutionModelFactory::createInstanceOf(). JTT92 model requires a protein alphabet.", alphabet_);
+    }
+  }
+  else if(modelName == DAYHOFF_SCHWARTZ_ORCUTT)
+  {
+    try { 
+      return new DSO78(dynamic_cast<const ProteicAlphabet *>(alphabet_));
+    } catch(Exception & e) {
+      throw AlphabetException("SubstitutionModelFactory::createInstanceOf(). DSO78 model requires a protein alphabet.", alphabet_);
+    }
+  }
+  else if(modelName == WHELAN_AND_GOLDMAN)
+  {
+    try { 
+      return new WAG01(dynamic_cast<const ProteicAlphabet *>(alphabet_));
+    } catch(Exception & e) {
+      throw AlphabetException("SubstitutionModelFactory::createInstanceOf(). WAG01 model requires a protein alphabet.", alphabet_);
+    }
+  }
+  else if(modelName == LE_GASCUEL)
+  {
+    try { 
+      return new LG08(dynamic_cast<const ProteicAlphabet *>(alphabet_));
+    } catch(Exception & e) {
+      throw AlphabetException("SubstitutionModelFactory::createInstanceOf(). LE08 model requires a protein alphabet.", alphabet_);
+    }
+  }
+  else throw Exception("SubstitutionModelFactory::createModel(). Unknown model: " + modelName);
+}
+
diff --git a/src/Bpp/Phyl/Model/SubstitutionModelFactory.h b/src/Bpp/Phyl/Model/SubstitutionModelFactory.h
new file mode 100644
index 0000000..630c3f2
--- /dev/null
+++ b/src/Bpp/Phyl/Model/SubstitutionModelFactory.h
@@ -0,0 +1,131 @@
+//
+// File: SubstitutionModelFactory.h
+// Created by: Julien Dutheil
+//             Vincent Ranwez
+// Created on: Fri apr 14 11:11 2006
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004, 2005, 2006)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _SUBSTITUTIOMODELFACTORY_H_
+#define _SUBSTITUTIOMODELFACTORY_H_
+
+#include "../Model/Nucleotide/JCnuc.h"
+#include "../Tree.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/Alphabet.h>
+#include <Bpp/Seq/Alphabet/AlphabetExceptions.h>
+#include <Bpp/Seq/GeneticCode/GeneticCode.h>
+
+// From the STL:
+#include <string>
+
+namespace bpp
+{
+
+/**
+ * @brief Utilitary class for creating substitution models.
+ */
+class SubstitutionModelFactory
+{
+  public:
+    static const std::string JUKES_CANTOR;
+    static const std::string KIMURA_2P;
+    static const std::string HASEGAWA_KISHINO_YANO;
+    static const std::string TAMURA_NEI;
+    static const std::string GENERAL_TIME_REVERSIBLE;
+    static const std::string STRAND_SYMMETRIC_REVERSIBLE;
+    static const std::string TAMURA;
+    static const std::string LOBRY;
+    static const std::string FELSENSTEIN;
+    static const std::string JOHN_TAYLOR_THORNTON;
+    static const std::string DAYHOFF_SCHWARTZ_ORCUTT;
+    static const std::string WHELAN_AND_GOLDMAN;
+    static const std::string LE_GASCUEL;
+  
+  private:
+    const Alphabet* alphabet_;
+    const GeneticCode* geneticCode_;
+  
+  public:
+    /**
+     * @brief Creates a new factory object with the given alphabet.
+     *
+     * This factory only provides ways to instanciate simple substitution models,
+     * for nucleotides and proteins.
+     *
+     * @param alphabet The alphabet for wich models must be instanciated.
+     * @param geneticCode Genetic code to use for codon model.
+     *
+     * Example:
+     * @code
+     * const Alphabet* alphabet = new DNA();
+     * SubstitutionModel* model = SubstitutionModelFactory(alphabet)
+     *     .createModel(SubstitutionModelFactory::TAMURA);
+     * // model can be used in any object dealing with a nucleotide substitution models.
+     * @endcode
+     */
+    SubstitutionModelFactory(const Alphabet* alphabet, const GeneticCode* geneticCode):
+      alphabet_(alphabet), geneticCode_(geneticCode) {}
+    
+    SubstitutionModelFactory(const SubstitutionModelFactory& smf) :
+      alphabet_(smf.alphabet_), geneticCode_(smf.geneticCode_) {}
+    
+    SubstitutionModelFactory& operator=(const SubstitutionModelFactory& smf)
+    {
+      alphabet_    = smf.alphabet_;
+      geneticCode_ = smf.geneticCode_;
+      return *this;
+    }
+    
+    virtual ~SubstitutionModelFactory() {}
+
+  public:
+    /**
+     * @brief Get a new dynamically created SubstitutionModel object.
+     *
+     * @param modelName The name of the model to use.
+     * @return A pointer toward a new substitution model, with default parameter values.
+     * @throw AlphabetException If the model is not compatible with the given alphabet.
+     * @throw Exception If the model name do not match any available model.
+     */
+    virtual SubstitutionModel* createModel(const std::string& modelName) const throw (AlphabetException, Exception);
+
+};
+
+} //end of namespace bpp.
+
+#endif //_SUBSTITUTIOMODELFACTORY_H_
+
diff --git a/src/Bpp/Phyl/Model/SubstitutionModelSet.cpp b/src/Bpp/Phyl/Model/SubstitutionModelSet.cpp
new file mode 100644
index 0000000..e0567a7
--- /dev/null
+++ b/src/Bpp/Phyl/Model/SubstitutionModelSet.cpp
@@ -0,0 +1,471 @@
+//
+// File: SubstitutionModelSet.cpp
+// Created by: Bastien Boussau
+//             Julien Dutheil
+// Created on: Tue Aug 21 2007
+//
+
+/*
+  Copyright or <A9> or Copr. CNRS, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use,
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info".
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability.
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or
+  data to be ensured and,  more generally, to use and operate it in the
+  same conditions as regards security.
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "SubstitutionModelSet.h"
+#include "MixedSubstitutionModel.h"
+
+#include <Bpp/Utils/MapTools.h>
+
+using namespace bpp;
+using namespace std;
+
+SubstitutionModelSet::SubstitutionModelSet(const SubstitutionModelSet& set) :
+  AbstractParameterAliasable(set),
+  alphabet_             (set.alphabet_),
+  nbStates_             (set.nbStates_),
+  modelSet_(set.modelSet_.size()),
+  rootFrequencies_(set.stationarity_ ? 0 : dynamic_cast<FrequenciesSet*>(set.rootFrequencies_->clone())),
+  nodeToModel_          (set.nodeToModel_),
+  modelToNodes_         (set.modelToNodes_),
+  paramToModels_        (set.paramToModels_),
+  paramNamesCount_      (set.paramNamesCount_),
+  modelParameterNames_  (set.modelParameterNames_),
+  modelParameters_      (set.modelParameters_),
+  stationarity_         (set.stationarity_)
+{
+  // Duplicate all model objects:
+  for (size_t i = 0; i < set.modelSet_.size(); i++)
+    {
+      modelSet_[i] = dynamic_cast<SubstitutionModel*>(set.modelSet_[i]->clone());
+    }
+}
+
+SubstitutionModelSet& SubstitutionModelSet::operator=(const SubstitutionModelSet& set)
+{
+  AbstractParameterAliasable::operator=(set);
+  alphabet_            = set.alphabet_;
+  nbStates_            = set.nbStates_;
+  nodeToModel_         = set.nodeToModel_;
+  modelToNodes_        = set.modelToNodes_;
+  paramToModels_       = set.paramToModels_;
+  paramNamesCount_     = set.paramNamesCount_;
+  modelParameterNames_ = set.modelParameterNames_;
+  modelParameters_     = set.modelParameters_;
+  stationarity_        = set.stationarity_;
+  if (set.stationarity_)
+    rootFrequencies_.reset(0);
+  else
+    rootFrequencies_.reset(dynamic_cast<FrequenciesSet*>(set.rootFrequencies_->clone()));
+
+  // Duplicate all model objects:
+  modelSet_.resize(set.modelSet_.size());
+  for (size_t i = 0; i < set.modelSet_.size(); i++)
+    {
+      modelSet_[i] = dynamic_cast<SubstitutionModel*>(set.modelSet_[i]->clone());
+    }
+  return *this;
+}
+
+void SubstitutionModelSet::clear()
+{
+  resetParameters_();
+  nbStates_=0;
+  for (size_t i = 0; i < modelSet_.size(); i++)
+    {
+      delete modelSet_[i];
+    }
+  modelSet_.clear();
+  rootFrequencies_.reset();
+  nodeToModel_.clear();
+  paramToModels_.clear();
+  paramNamesCount_.clear();
+  modelParameterNames_.clear();
+  modelParameters_.clear();
+  stationarity_=true;
+
+}
+
+void SubstitutionModelSet::setRootFrequencies(FrequenciesSet* rootFreqs)
+{
+  if (rootFreqs){
+    stationarity_=false;
+    rootFrequencies_.reset(rootFreqs);
+    addParameters_(rootFrequencies_->getParameters());
+  }
+}
+
+std::vector<int> SubstitutionModelSet::getNodesWithParameter(const std::string& name) const
+  throw (ParameterNotFoundException)
+{
+  vector<int> ids;
+  size_t offset = stationarity_ ? 0 : rootFrequencies_->getNumberOfParameters();
+  for (size_t i = 0; i < paramToModels_.size(); i++)
+    {
+      if (getParameter_(offset + i).getName() == name)
+        {
+          for (size_t j = 0; j < paramToModels_[i].size(); j++)
+            {
+              vector<int> v = modelToNodes_[paramToModels_[i][j]];
+              VectorTools::append(ids, v);
+            }
+          return ids;
+        }
+    }
+  throw ParameterNotFoundException("SubstitutionModelSet::getNodesWithParameter.", name);
+}
+
+vector<size_t> SubstitutionModelSet::getModelsWithParameter(const std::string& name) const
+  throw (ParameterNotFoundException)
+{
+  vector<size_t> indices;
+  size_t offset = stationarity_ ? 0 : rootFrequencies_->getNumberOfParameters();
+  for (size_t i = 0; i < paramToModels_.size(); i++)
+    {
+      if (getParameter_(offset + i).getName() == name)
+        return paramToModels_[i];
+    }
+  throw ParameterNotFoundException("SubstitutionModelSet::getModelsWithParameter.", name);
+}
+
+void SubstitutionModelSet::addModel(SubstitutionModel* model, const std::vector<int>& nodesId, const vector<string>& newParams) throw (Exception)
+{
+  if (model->getAlphabet()->getAlphabetType() != alphabet_->getAlphabetType())
+    throw Exception("SubstitutionModelSet::addModel. A Substitution Model cannot be added to a Model Set if it does not have the same alphabet.");
+  if (modelSet_.size() > 0 && model->getNumberOfStates() != nbStates_)
+    throw Exception("SubstitutionModelSet::addModel. A Substitution Model cannot be added to a Model Set if it does not have the same number of states.");
+  if (modelSet_.size() == 0)
+    nbStates_ = model->getNumberOfStates();
+  modelSet_.push_back(model);
+  size_t thisModelIndex = modelSet_.size() - 1;
+
+  // Associate this model to specified nodes:
+  for (size_t i = 0; i < nodesId.size(); i++)
+    {
+      nodeToModel_[nodesId[i]] = thisModelIndex;
+      modelToNodes_[thisModelIndex].push_back(nodesId[i]);
+    }
+
+  // Associate parameters:
+  string pname;
+  modelParameters_.push_back(ParameterList());
+  for (size_t i  = 0; i < newParams.size(); i++)
+    {
+      pname = newParams[i];
+      modelParameterNames_.push_back(pname);
+      vector<size_t> modelsIndex(1, thisModelIndex);
+      paramToModels_.push_back(modelsIndex);
+      Parameter* p = new Parameter(model->getParameters().getParameter(pname)); // We work with namespaces here, so model->getParameter(pname) does not work.
+      modelParameters_[thisModelIndex].addParameter(p->clone());
+      p->setName(pname + "_" + TextTools::toString(++paramNamesCount_[pname])); // Change name to unique name in case of shared parameters.
+      addParameter_(p);
+    }
+}
+
+void SubstitutionModelSet::setModel(SubstitutionModel* model, size_t modelIndex) throw (Exception, IndexOutOfBoundsException)
+{
+  if (model->getAlphabet()->getAlphabetType() != alphabet_->getAlphabetType())
+    throw Exception("SubstitutionModelSet::setModel. A Substitution Model cannot be added to a Model Set if it does not have the same alphabet");
+  if (modelIndex >= modelSet_.size())
+    throw IndexOutOfBoundsException("SubstitutionModelSet::setModel.", modelIndex, 0, modelSet_.size());
+  delete modelSet_[modelIndex];
+  modelSet_[modelIndex] = model;
+}
+
+void SubstitutionModelSet::removeModel(size_t modelIndex) throw (Exception)
+{
+  modelSet_.erase(modelSet_.begin() + modelIndex);
+  // Erase all parameter references to this model and translate other indices...
+  for (size_t i = 0; i < paramToModels_.size(); i++)
+    {
+      for (size_t j = paramToModels_[i].size(); j > 0; j--)
+        {
+          if (paramToModels_[i][j - 1] == modelIndex)
+            {
+              paramToModels_[i].erase(paramToModels_[i].begin() + j - 1);
+            }
+          else if (paramToModels_[i][j - 1] > modelIndex)
+            paramToModels_[i][j - 1]--;  // Correct indice due to removal!
+        }
+    }
+  checkOrphanParameters(true);
+}
+
+ParameterList SubstitutionModelSet::getModelParameters(size_t modelIndex) const
+{
+  ParameterList pl;
+  size_t offset = stationarity_ ? 0 : rootFrequencies_->getNumberOfParameters(); // Root frequencies are the first parameters! We should ignore them here.
+  for (size_t i = 0; i < modelParameterNames_.size(); i++)
+    {
+      // Check associations:
+      const vector<size_t>* modelIndexes = &paramToModels_[i];
+      for (size_t j = 0; j < modelIndexes->size(); j++)
+        {
+          if ((*modelIndexes)[j] == modelIndex)
+            {
+              pl.addParameter(getParameter_(offset + i));
+              break;
+            }
+        }
+    }
+  return pl;
+}
+
+void SubstitutionModelSet::listModelNames(std::ostream& out) const
+{
+  for (size_t i = 0; i < modelSet_.size(); i++)
+    {
+      out << "Model " << i + 1 << ": " << modelSet_[i]->getName() << "\t attached to nodes ";
+      for (size_t j = 0; j < modelToNodes_[i].size(); j++)
+        {
+          out << modelToNodes_[i][j];
+        }
+      out << endl;
+    }
+}
+
+void SubstitutionModelSet::setParameterToModel(size_t parameterIndex, size_t modelIndex) throw (IndexOutOfBoundsException)
+{
+  size_t offset = stationarity_ ? 0 : rootFrequencies_->getNumberOfParameters();
+  if (parameterIndex < offset)
+    throw IndexOutOfBoundsException("SubstitutionModelSet::setParameterToModel. Can't assign a root frequency parameter to a branch model.", parameterIndex, offset - 1, paramToModels_.size() + offset - 1);
+  if (parameterIndex >= paramToModels_.size() + offset)
+    throw IndexOutOfBoundsException("SubstitutionModelSet::setParameterToModel.", parameterIndex, offset - 1, paramToModels_.size() + offset - 1);
+  if (modelIndex >= modelSet_.size())
+    throw IndexOutOfBoundsException("SubstitutionModelSet::setParameterToModel.", modelIndex, 0, modelSet_.size() - 1);
+  if (VectorTools::contains(paramToModels_[parameterIndex - offset], modelIndex))
+    throw Exception("SubstitutionModelSet::setParameterToModel: parameter " + getParameter_(parameterIndex - offset).getName() + " already set to model " + TextTools::toString(modelIndex) + ".");
+  paramToModels_[parameterIndex - offset].push_back(modelIndex);
+  modelParameters_[modelIndex].addParameter(
+                                            modelSet_[modelIndex]->getParameters().getParameter(modelParameterNames_[parameterIndex - offset]));
+  //Update value of modified model:
+  modelSet_[modelIndex]->matchParametersValues(getParameters().subList(parameterIndex - offset));
+}
+
+void SubstitutionModelSet::unsetParameterToModel(size_t parameterIndex, size_t modelIndex) throw (IndexOutOfBoundsException, Exception)
+{
+  size_t offset = stationarity_ ? 0 : rootFrequencies_->getNumberOfParameters();
+  if (parameterIndex < offset)
+    throw IndexOutOfBoundsException("SubstitutionModelSet::unsetParameterToModel. Can't unset a root frequency parameter.", parameterIndex, offset - 1, paramToModels_.size() + offset - 1);
+  if (parameterIndex >= paramToModels_.size() + offset)
+    throw IndexOutOfBoundsException("SubstitutionModelSet::unsetParameterToModel.", parameterIndex, offset - 1, paramToModels_.size() + offset - 1);
+  if (modelIndex >= modelSet_.size())
+    throw IndexOutOfBoundsException("SubstitutionModelSet::setParameterToModel.", modelIndex, 0, modelSet_.size() - 1);
+  if (!VectorTools::contains(paramToModels_[parameterIndex - offset], modelIndex))
+    throw Exception("SubstitutionModelSet::unsetParameterToModel: parameter " + getParameter_(parameterIndex).getName() + " is not currently set to model " + TextTools::toString(modelIndex) + ".");
+  remove(paramToModels_[parameterIndex - offset].begin(), paramToModels_[parameterIndex - offset].end(), modelIndex);
+  modelParameters_[modelIndex].deleteParameter(modelParameterNames_[parameterIndex - offset]);
+  checkOrphanModels(true);
+  checkOrphanParameters(true);
+}
+
+void SubstitutionModelSet::addParameter(const Parameter& parameter, const vector<int>& nodesId) throw (Exception)
+{
+  modelParameterNames_.push_back(parameter.getName());
+  Parameter* p = parameter.clone();
+  p->setName(p->getName() + "_" + TextTools::toString(++paramNamesCount_[p->getName()]));
+  addParameter_(p);
+  // Build model indexes:
+  vector<size_t> modelIndexes(nodesId.size());
+  for (size_t i = 0; i < nodesId.size(); ++i)
+  {
+    if (nodeToModel_.find(nodesId[i]) == nodeToModel_.end())
+      throw Exception("SubstitutionModelSet::addParameter. This node has no associated model: " + TextTools::toString(nodesId[i]));
+    size_t pos = nodeToModel_[nodesId[i]];
+    modelParameters_[pos].addParameter(parameter);
+    modelIndexes[i] = pos;
+  }
+  paramToModels_.push_back(modelIndexes);
+  //Update model values:
+  fireParameterChanged(getParameters().subList(p->getName()));
+}
+
+void SubstitutionModelSet::addParameters(const ParameterList& parameters, const vector<int>& nodesId) throw (Exception)
+{
+  for (size_t i = 0; i < parameters.size(); i++)
+    {
+      modelParameterNames_.push_back(parameters[i].getName());
+    }
+  ParameterList pl(parameters);
+  for (size_t i = 0; i < pl.size(); i++)
+    {
+      pl[i].setName(pl[i].getName() + "_" + TextTools::toString(++paramNamesCount_[pl[i].getName()]));
+    }
+  addParameters_(pl);
+  // Build model indexes:
+  vector<size_t> modelIndexes(nodesId.size());
+  map<size_t, size_t> counts; //Check is a model is affected to several nodes.
+  for (size_t i = 0; i < nodesId.size(); i++)
+    {
+      if (nodeToModel_.find(nodesId[i]) == nodeToModel_.end())
+        throw Exception("SubstitutionModelSet::addParameters. This node has no associated model: " + TextTools::toString(nodesId[i]));
+      size_t pos = nodeToModel_[nodesId[i]];
+      size_t count = counts[pos]++;
+      if (count == 0)
+        modelParameters_[pos].addParameters(parameters);
+      modelIndexes[i] = pos;
+    }
+  for (size_t i = 0; i < pl.size(); i++)
+    {
+      paramToModels_.push_back(modelIndexes);
+    }
+  //Update model values:
+  fireParameterChanged(pl);
+}
+
+void SubstitutionModelSet::removeParameter(const string& name) throw (ParameterNotFoundException)
+{
+  size_t offset = stationarity_ ? 0 : rootFrequencies_->getNumberOfParameters();
+  for (size_t i = 0; i < modelParameterNames_.size(); i++)
+    {
+      if (getParameter_(offset + i).getName() == name)
+        {
+          vector<int> nodesId = getNodesWithParameter(name);
+          for (size_t j = 0; j < nodesId.size(); j++)
+            {
+              size_t pos = nodeToModel_[nodesId[j]];
+              string tmp = modelParameterNames_[i];
+              if (modelParameters_[pos].hasParameter(tmp))
+                modelParameters_[pos].deleteParameter(tmp);
+            }
+          paramToModels_.erase(paramToModels_.begin() + i);
+          modelParameterNames_.erase(modelParameterNames_.begin() + i);
+          deleteParameter_(offset + i);
+          return;
+        }
+    }
+  throw ParameterNotFoundException("SubstitutionModelSet::removeParameter.", name);
+}
+
+void SubstitutionModelSet::fireParameterChanged(const ParameterList& parameters)
+{
+  // For now, we actualize all parameters... we'll optimize later!
+  // Update root frequencies:
+  updateRootFrequencies();
+
+  // First we actualize the modelParameters_ array:
+  size_t offset = stationarity_ ? 0 : rootFrequencies_->getNumberOfParameters(); // Root frequencies are the first parameters! We should ignore them here.
+  for (size_t i = 0; i < modelParameterNames_.size(); i++)
+    {
+      // Check associations:
+      vector<size_t>* modelIndexes = &paramToModels_[i];
+      for (size_t j = 0; j < modelIndexes->size(); j++)
+        {
+          if (!modelParameters_[(*modelIndexes)[j]].hasParameter(modelParameterNames_[i]))
+            {
+              cerr << "DEBUG: Error, no parameter with name " << modelParameterNames_[i] << " for model " << (*modelIndexes)[j] << endl;
+            }
+          if (offset + i > getNumberOfParameters()) cerr << "DEBUG: Error, missing parameter " << (offset + i) << "/" << getNumberOfParameters() << endl;
+          modelParameters_[(*modelIndexes)[j]].getParameter(modelParameterNames_[i]).setValue(getParameter_(offset + i).getValue());
+        }
+    }
+
+  // Then we update all models in the set:
+  for (size_t i = 0; i < modelParameters_.size(); i++)
+    {
+      modelSet_[i]->matchParametersValues(modelParameters_[i]);
+    }
+}
+
+bool SubstitutionModelSet::checkOrphanModels(bool throwEx) const
+  throw (Exception)
+{
+  vector<size_t> index = MapTools::getValues(nodeToModel_);
+  for (size_t i = 0; i < modelSet_.size(); i++)
+    {
+      if (!VectorTools::contains(index, i))
+        {
+          if (throwEx) throw Exception("SubstitutionModelSet::checkOrphanModels(). Model '" + TextTools::toString(i + 1) + "' is associated to no node.");
+          return false;
+        }
+    }
+  return true;
+}
+
+bool SubstitutionModelSet::checkOrphanParameters(bool throwEx) const
+  throw (Exception)
+{
+  for (size_t i = 0; i < paramToModels_.size(); i++)
+    {
+      if (paramToModels_[i].size() == 0)
+        {
+          if (throwEx) throw Exception("SubstitutionModelSet::checkOrphanParameters(). Parameter '" + getParameter_(i).getName() + "' is associated to no model.");
+          return false;
+        }
+    }
+  return true;
+}
+
+bool SubstitutionModelSet::checkOrphanNodes(const Tree& tree, bool throwEx) const
+  throw (Exception)
+{
+  vector<int> ids = tree.getNodesId();
+  int rootId = tree.getRootId();
+  for (size_t i = 0; i < ids.size(); i++)
+    {
+      if (ids[i] != rootId && nodeToModel_.find(ids[i]) == nodeToModel_.end())
+        {
+          if (throwEx) throw Exception("SubstitutionModelSet::checkOrphanNodes(). Node '" + TextTools::toString(ids[i]) + "' in tree has no model associated.");
+          return false;
+        }
+    }
+  return true;
+}
+
+bool SubstitutionModelSet::checkUnknownNodes(const Tree& tree, bool throwEx) const
+  throw (Exception)
+{
+  vector<int> ids = tree.getNodesId();
+  int id;
+  int rootId = tree.getRootId();
+  for (size_t i = 0; i < modelToNodes_.size(); i++)
+    {
+      for (size_t j = 0; j < modelToNodes_[i].size(); j++)
+        {
+          id = modelToNodes_[i][j];
+          if (id == rootId || !VectorTools::contains(ids, id))
+            {
+              if (throwEx) throw Exception("SubstitutionModelSet::checkUnknownNodes(). Node '" + TextTools::toString(id) + "' is not found in tree or is the root node.");
+              return false;
+            }
+        }
+    }
+  return true;
+}
+
+bool SubstitutionModelSet::hasMixedSubstitutionModel() const
+{
+  for (size_t i = 0; i < getNumberOfModels(); i++)
+    {
+      if (dynamic_cast<const MixedSubstitutionModel*>(getModel(i)) != NULL)
+        return true;
+    }
+  return false;
+}
+
diff --git a/src/Bpp/Phyl/Model/SubstitutionModelSet.h b/src/Bpp/Phyl/Model/SubstitutionModelSet.h
new file mode 100644
index 0000000..71c2299
--- /dev/null
+++ b/src/Bpp/Phyl/Model/SubstitutionModelSet.h
@@ -0,0 +1,590 @@
+//
+// File: SubstitutionModelSet.h
+// Created by: Bastien Boussau
+//             Julien Dutheil
+// Created on: Tue Aug 21 2007
+//
+
+/*
+   Copyright or (c) or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _SUBSTITUTIONMODELSET_H_
+#define _SUBSTITUTIONMODELSET_H_
+
+
+#include "../Tree.h"
+#include "SubstitutionModel.h"
+#include "AbstractSubstitutionModel.h"
+#include "FrequenciesSet/FrequenciesSet.h"
+
+#include <Bpp/Exceptions.h>
+#include <Bpp/Numeric/Random/RandomTools.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+// From Seqlib:
+#include <Bpp/Seq/Alphabet/Alphabet.h>
+#include <Bpp/Seq/Alphabet/NucleicAlphabet.h>
+
+// From the STL:
+#include <vector>
+#include <map>
+#include <algorithm>
+#include <memory>
+
+namespace bpp
+{
+/**
+ * @brief Substitution models manager for non-homogeneous / non-reversible models of evolution.
+ *
+ * This class contains a set of substitution models, and their assigment toward the branches of a phylogenetic tree.
+ * Each branch in the tree corresponds to a model in the set, but a susbstitution model may correspond to several branches.
+ * The particular case where all branches point toward a unique model is the homogeneous case.
+ *
+ * This class also deals with the parameters associated to the models.
+ * In the homogeneous case, the parameter list is the same as the list in susbstitution model.
+ * When two models at least are specified, these models may have their own parameters or share some of them.
+ * To deal with this issue, the SubstitutionModelSet class contains its own parameter list and an index which tells to which
+ * models these parameters apply to.
+ * Since parameters in a list must have unique names, duplicated names are numbered according to the order in the list.
+ * To track the relationships between names in the list and names in each model, the parameter list is duplicated in modelParameters_.
+ * The user only act on parameters_, the fireParameterChanged function, automatically called, will update the modelParameters_ field.
+ *
+ * In the non-homogeneous and homogeneous non-reversible cases, the likelihood depends on the position of the root.
+ * The states frequencies at the root of the tree are hence distinct parameters.
+ * Theses are accounted by a FrequenciesSet objet, managed by the SubstitutionModelSet class.
+ * The corresponding parameters, if any, are added at the begining of the global parameter list.
+ *
+ * If the heterogenity of the model does not affect the equilibrium frequencies, the model can be considered as stationary.
+ * In such a model, the process is supposed to be at equilibrium all along the trees, including at the root.
+ * Whether a model should be considered as stationary or not is left to the user. If the "asumme stationarity" option is set when
+ * building the set, then no FrequenciesSet object is used, but the frequencies are taken to be the same as the one at the first
+ * model in the set. Nothing hence prevents you to build a "supposingly stationary model which actually is not", so be careful!!
+ *
+ * This class provides several methods to specify which model and/or which parameter is associated to which branch/clade.
+ * Several check points are provided, but some are probably missing due to the large set of possible models that this class allows to build,
+ * so be carefull!
+ *
+ * @see SubstitutionModelSetTools for methods that provide instances of the SubstitutionModelSet for general cases.
+ */
+class SubstitutionModelSet :
+  public AbstractParameterAliasable
+{
+protected:
+  /**
+   * @brief A pointer toward the common alphabet to all models in the set.
+   */
+  const Alphabet* alphabet_;
+
+  size_t nbStates_;
+
+  /**
+   * @brief Contains all models used in this tree.
+   */
+  std::vector<SubstitutionModel*> modelSet_;
+
+private:
+  /**
+   * @brief Root frequencies.
+   */
+  std::auto_ptr<FrequenciesSet> rootFrequencies_;
+
+  /**
+   * @brief Contains for each node in a tree the index of the corresponding model in modelSet_
+   */
+  mutable std::map<int, size_t> nodeToModel_;
+  mutable std::map<size_t, std::vector<int> > modelToNodes_;
+
+  /**
+   * @brief Contains for each parameter in the list the indexes of the corresponding models in modelSet_ that share this parameter.
+   */
+  std::vector< std::vector<size_t> > paramToModels_;
+
+  std::map<std::string, size_t> paramNamesCount_;
+
+  /**
+   * @brief Contains for each parameter in the list the corresponding name in substitution models.
+   */
+  std::vector<std::string> modelParameterNames_;
+
+  /**
+   * @brief Parameters for each model in the set.
+   *
+   * The parameters_ field, inherited from AbstractSubstitutionModel contains all parameters, with unique names.
+   * To make the correspondance with parameters for each model in the set, we duplicate them in this array.
+   * In most cases, this is something like 'theta_1 <=> theta', 'theta_2 <=> theta', etc.
+   */
+  std::vector<ParameterList> modelParameters_;
+
+  bool stationarity_;
+
+public:
+  /**
+   * @brief Create a model set according to the specified alphabet.
+   * Stationarity is assumed.
+   *
+   * @param alpha The alphabet to use for this set.
+   */
+  SubstitutionModelSet(const Alphabet* alpha):
+    AbstractParameterAliasable(""),
+    alphabet_(alpha),
+    nbStates_(0),
+    modelSet_(),
+    rootFrequencies_(0),
+    nodeToModel_(),
+    modelToNodes_(),
+    paramToModels_(),
+    paramNamesCount_(),
+    modelParameterNames_(),
+    modelParameters_(),
+    stationarity_(true)
+  {
+  }
+
+  /**
+   * @brief Create a model set according to the specified alphabet and root frequencies.
+   * Stationarity is not assumed.
+   *
+   * @param alpha The alphabet to use for this set.
+   * @param rootFreqs The frequencies at root node. The underlying object will be owned by this instance.
+   */
+  SubstitutionModelSet(const Alphabet* alpha, FrequenciesSet* rootFreqs):
+    AbstractParameterAliasable(""),
+    alphabet_(alpha),
+    nbStates_(0),
+    modelSet_(),
+    rootFrequencies_(0),
+    nodeToModel_(),
+    modelToNodes_(),
+    paramToModels_(),
+    paramNamesCount_(),
+    modelParameterNames_(),
+    modelParameters_(),
+    stationarity_(true)
+  {
+    setRootFrequencies(rootFreqs);
+  }
+
+  /**
+   * @brief Resets all the information contained in this object.
+   *
+   */
+   
+  void clear();
+  
+  /**
+   * @brief Sets a given FrequenciesSet for root frequencies.
+   *
+   * @param rootFreqs The FrequenciesSet for root frequencies.
+   */
+
+  void setRootFrequencies(FrequenciesSet* rootFreqs);
+
+  SubstitutionModelSet(const SubstitutionModelSet& set);
+
+  SubstitutionModelSet& operator=(const SubstitutionModelSet& set);
+
+  virtual ~SubstitutionModelSet()
+  {
+    for (size_t i = 0; i < modelSet_.size(); i++) { delete modelSet_[i]; }
+  }
+
+#ifndef NO_VIRTUAL_COV
+  SubstitutionModelSet*
+#else
+  Clonable*
+#endif
+  clone() const { return new SubstitutionModelSet(*this); }
+
+public:
+  /**
+   * @brief Get the number of states associated to this model set.
+   *
+   * @return The number of states.
+   * @throw Exception if no model is associated to the set.
+   */
+  size_t getNumberOfStates() const throw (Exception)
+  {
+    return nbStates_;
+  }
+
+  /**
+   * @brief Get the index of a given parameter in the list of all parameters.
+   *
+   * @param name The name of the parameter to look for.
+   * @return The position of the parameter in the global parameter list.
+   * @throw ParameterNotFoundException If no parameter with this name is found.
+   */
+  size_t getParameterIndex(const std::string& name) const throw (ParameterNotFoundException)
+  {
+    for (size_t i = 0; i < getNumberOfParameters(); i++)
+    {
+      if (getParameter_(i).getName() == name) return i;
+    }
+    throw ParameterNotFoundException("SubstitutionModelSet::getParameterIndex().", name);
+  }
+
+  /**
+   * @brief Get the model name of a given parameter in the list of all parameters.
+   *
+   * @param name The name of the parameter to look for.
+   * @return The model name of the parameter in the global parameter list.
+   * @throw ParameterNotFoundException If no parameter with this name is found.
+   * @throw Exception If the parameter is not a 'model' parameter (that is, it is a root frequency parameter).
+   */
+  std::string getParameterModelName(const std::string& name) const throw (ParameterNotFoundException, Exception)
+  {
+    size_t pos = getParameterIndex(name);
+    if (stationarity_)
+      return modelParameterNames_[pos];
+    else
+    {
+      size_t rfs = rootFrequencies_->getNumberOfParameters();
+      if (pos < rfs) throw Exception("SubstitutionModelSet::getParameterModelName(). This parameter as no model name: " + name);
+      return modelParameterNames_[pos - rfs];
+    }
+  }
+
+  /**
+   * To be called when a parameter has changed.
+   * Depending on parameters, this will actualize the _initialFrequencies vector or the corresponding models in the set.
+   * @param parameters The modified parameters.
+   */
+  virtual void fireParameterChanged(const ParameterList& parameters);
+
+  /**
+   * @return The current number of distinct substitution models in this set.
+   */
+  size_t getNumberOfModels() const { return modelSet_.size(); }
+
+  /**
+   * @return True iff there is a MixedSubstitutionModel in the SubstitutionModelSet
+   **/
+
+  bool hasMixedSubstitutionModel() const;
+
+  /**
+   * @brief Get one model from the set knowing its index.
+   *
+   * @param i Index of the model in the set.
+   * @return A pointer toward the corresponding model.
+   */
+  const SubstitutionModel* getModel(size_t i) const throw (IndexOutOfBoundsException)
+  {
+    if (i > modelSet_.size()) throw IndexOutOfBoundsException("SubstitutionModelSet::getNumberOfModels().", 0, modelSet_.size() - 1, i);
+    return modelSet_[i];
+  }
+
+  SubstitutionModel* getModel(size_t i) throw (IndexOutOfBoundsException)
+  {
+    if (i > modelSet_.size()) throw IndexOutOfBoundsException("SubstitutionModelSet::getNumberOfModels().", 0, modelSet_.size() - 1, i);
+    return modelSet_[i];
+  }
+
+  /**
+   * @brief Get the index in the set of the model associated to a particular node id.
+   *
+   * @param nodeId The id of the query node.
+   * @return The index of the model associated to the given node.
+   * @throw Exception If no model is found for this node.
+   */
+  size_t getModelIndexForNode(int nodeId) const throw (Exception)
+  {
+   std::map<int, size_t>::iterator i = nodeToModel_.find(nodeId);
+    if (i == nodeToModel_.end())
+      throw Exception("SubstitutionModelSet::getModelIndexForNode(). No model associated to node with id " + TextTools::toString(nodeId));
+    return i->second;
+  }
+
+  /**
+   * @brief Get the model associated to a particular node id.
+   *
+   * @param nodeId The id of the query node.
+   * @return A pointer toward the corresponding model.
+   * @throw Exception If no model is found for this node.
+   */
+  const SubstitutionModel* getModelForNode(int nodeId) const throw (Exception)
+  {
+   std::map<int, size_t>::const_iterator i = nodeToModel_.find(nodeId);
+    if (i == nodeToModel_.end())
+      throw Exception("SubstitutionModelSet::getModelForNode(). No model associated to node with id " + TextTools::toString(nodeId));
+    return modelSet_[i->second];
+  }
+  SubstitutionModel* getModelForNode(int nodeId) throw (Exception)
+  {
+   std::map<int, size_t>::iterator i = nodeToModel_.find(nodeId);
+    if (i == nodeToModel_.end())
+      throw Exception("SubstitutionModelSet::getModelForNode(). No model associated to node with id " + TextTools::toString(nodeId));
+    return modelSet_[i->second];
+  }
+
+  /**
+   * @brief Get a list of nodes id for which the given model is associated.
+   *
+   * @param i The index of the model in the set.
+   * @return A vector with the ids of the node associated to this model.
+   * @throw IndexOutOfBoundsException If the index is not valid.
+   */
+  const std::vector<int>& getNodesWithModel(size_t i) const throw (IndexOutOfBoundsException)
+  {
+    if (i >= modelSet_.size()) throw IndexOutOfBoundsException("SubstitutionModelSet::getNodesWithModel().", i, 0, modelSet_.size());
+    return modelToNodes_[i];
+  }
+
+  /**
+   * @param name The name of the parameter to look for.
+   * @return The list of nodes with a model containing the specified parameter.
+   * @throw ParameterNotFoundException If no parameter with the specified name is found.
+   */
+  std::vector<int> getNodesWithParameter(const std::string& name) const throw (ParameterNotFoundException);
+
+  /**
+   * @param name The name of the parameter to look for.
+   * @return The list of model indices containing the specified parameter.
+   * @throw ParameterNotFoundException If no parameter with the specified name is found.
+   */
+  std::vector<size_t> getModelsWithParameter(const std::string& name) const throw (ParameterNotFoundException);
+
+  /**
+   * @brief Add a new model to the set, and set relationships with nodes and params.
+   *
+   * @param model A pointer toward a susbstitution model, that will added to the set.
+   * Warning! The set will now be the owner of the pointer, and will destroy it if needed!
+   * Copy the model first if you don't want it to be lost!
+   * @param nodesId the set of nodes in the tree that points toward this model.
+   * This will override any previous affectation.
+   * @param newParams The names of the parameters that have to be added to the global list.
+   * These parameters will only be affected to this susbstitution model.
+   * You can use the setParameterToModel function to assign this parameter to an additional model, and the
+   * unsetParameterToModel to remove the relationship with this model for instance.
+   * Parameters not specified in newParams will be ignored, unless you manually assign them to another parameter with
+   * setParameterToModel.
+   * @throw Exception in case of error:
+   * <ul>
+   * <li>if the new model does not match the alphabet<li>
+   * <li>if the new model does not have the same number of states than existing ones<li>
+   * <li>etc.</li>
+   * </ul>
+   */
+  void addModel(SubstitutionModel* model, const std::vector<int>& nodesId, const std::vector<std::string>& newParams) throw (Exception);
+
+  /**
+   * @brief Change a given model.
+   *
+   * The new model will be copied and will replace the old one.
+   * All previous associations will be kept the same.
+   * @param model A pointer toward a susbstitution model, that will added to the set.
+   * Warning! The set will now be the owner of the pointer, and will destroy it if needed!
+   * Copy the model first if you don't want it to be lost!
+   * @param modelIndex The index of the existing model to replace.
+   */
+  void setModel(SubstitutionModel* model, size_t modelIndex) throw (Exception, IndexOutOfBoundsException);
+
+  /**
+   * @brief Associate an existing model with a given node.
+   *
+   * If the node was was previously associated to a model, the old association is deleted.
+   * If other nodes are associated to this model, the association is conserved.
+   *
+   * @param modelIndex The position of the model in the set.
+   * @param nodeNumber The id of the corresponding node.
+   */
+  void setModelToNode(size_t modelIndex, int nodeNumber) throw (IndexOutOfBoundsException)
+  {
+    if (modelIndex >= nodeToModel_.size()) throw IndexOutOfBoundsException("SubstitutionModelSet::setModelToNode.", modelIndex, 0, nodeToModel_.size() - 1);
+    nodeToModel_[nodeNumber] = modelIndex;
+  }
+
+  /**
+   * @brief Assign a parameter to a model.
+   *
+   * @param parameterIndex The index of the parameter in the list.
+   * @param modelIndex     The index of the model in the list.
+   * @throw IndexOutOfBoundsException If one of the index is not valid.
+   */
+  void setParameterToModel(size_t parameterIndex, size_t modelIndex) throw (IndexOutOfBoundsException);
+
+  /**
+   * @brief Unset a given parameter to the specified model.
+   *
+   * @param parameterIndex The index of the parameter in the list.
+   * @param modelIndex     The index of the model in the list.
+   * @throw IndexOutOfBoundsException If one of the index is not valid.
+   * @throw Exception If the pseicified parameter is not currently associated to the specified model.
+   */
+  void unsetParameterToModel(size_t parameterIndex, size_t modelIndex) throw (IndexOutOfBoundsException, Exception);
+
+  /**
+   * @brief Add a parameter to the list, and link it to specified existing nodes.
+   *
+   * @param parameter The parameter to add. Its name must match model parameter names.
+   * @param nodesId The list of ids of the nodes to link with these parameters.
+   * Nodes must have a corresponding model in the set.
+   * @throw Exception If one of the above requirement is not true.
+   */
+  void addParameter(const Parameter& parameter, const std::vector<int>& nodesId) throw (Exception);
+
+  /**
+   * @brief Add several parameters to the list, and link them to specified existing nodes.
+   *
+   * @param parameters The list of parameters to add. Its name must match model parameter names.
+   * @param nodesId The list of ids of the nodes to link with these parameters.
+   * Nodes must have a corresponding model in the set.
+   * @throw Exception If one of the above requirement is not true.
+   */
+  void addParameters(const ParameterList& parameters, const std::vector<int>& nodesId) throw (Exception);
+
+  /**
+   * @brief Remove a parameter from the list, and unset it to all linked nodes and models.
+   *
+   * @param name The name of the parameter to remove.
+   * @throw ParameterNotFoundException If no parameter with the given name is found in the list.
+   */
+  void removeParameter(const std::string& name) throw (ParameterNotFoundException);
+
+  /**
+   * @brief Remove a model from the set, and all corresponding parameters.
+   *
+   * @param modelIndex The index of the model in the set.
+   * @throw Exception if a parameter becomes orphan because of the removal.
+   */
+  void removeModel(size_t modelIndex) throw (Exception);
+
+  void listModelNames(std::ostream& out = std::cout) const;
+
+  /**
+   * @return The set of root frequencies.
+   */
+  const FrequenciesSet* getRootFrequenciesSet() const { return rootFrequencies_.get(); }
+
+  /**
+   * @return The values of the root frequencies.
+   */
+  std::vector<double> getRootFrequencies() const
+  {
+    if (stationarity_)
+      return modelSet_[0]->getFrequencies();
+    else
+      return rootFrequencies_->getFrequencies();
+  }
+
+  /**
+   * @brief Get the parameters corresponding to the root frequencies.
+   *
+   * @return The parameters corresponding to the root frequencies.
+   */
+  ParameterList getRootFrequenciesParameters() const
+  {
+    if (stationarity_)
+      return ParameterList();
+    else
+      return rootFrequencies_->getParameters();
+  }
+
+  /**
+   * @brief Get the parameters corresponding attached to the nodes of the tree.
+   *
+   * That is, all the parameters without the root frequencies.
+   *
+   * @return The parameters attached to the nodes of the tree.
+   */
+  ParameterList getNodeParameters() const
+  {
+    ParameterList pl;
+    for (size_t i = stationarity_ ? 0 : rootFrequencies_->getNumberOfParameters();
+        i < getNumberOfParameters(); i++)
+    {
+      pl.addParameter(getParameter_(i));
+    }
+    return pl;
+  }
+
+  /**
+   * @brief Get the parameters attached to a Model.
+   *
+   * @param modelIndex the index of the model in the set
+   *
+   * @return The parameters attached to the model.
+   */
+
+  ParameterList getModelParameters(size_t modelIndex) const;
+
+  const Alphabet* getAlphabet() const { return alphabet_; }
+
+  /**
+   * @brief Check if the model set is fully specified for a given tree.
+   *
+   * This include:
+   * - that each node as a model set up,
+   * - that each model in the set is attributed to a node,
+   * - that each parameter in the set actually correspond to a model.
+   * - all nodes ids in the set refer to an existing node in the tree.
+   *
+   * @param tree The tree to check.
+   * @param throwEx Tell if an exception have to be thrown in case of test not passed.
+   */
+  bool isFullySetUpFor(const Tree& tree, bool throwEx = true) const throw (Exception)
+  {
+    return checkOrphanModels(throwEx)
+           && checkOrphanParameters(throwEx)
+           && checkOrphanNodes(tree, throwEx)
+           && checkUnknownNodes(tree, throwEx);
+  }
+
+protected:
+  /**
+   * Set rootFrequencies_ from parameters.
+   */
+  void updateRootFrequencies()
+  {
+    if (!stationarity_)
+      rootFrequencies_->matchParametersValues(getParameters());
+  }
+
+  /**
+   * @name Check function.
+   *
+   * @{
+   */
+  bool checkOrphanModels(bool throwEx) const throw (Exception);
+
+  bool checkOrphanParameters(bool throwEx) const throw (Exception);
+
+  bool checkOrphanNodes(const Tree& tree, bool throwEx) const throw (Exception);
+
+  bool checkUnknownNodes(const Tree& tree, bool throwEx) const throw (Exception);
+  /** @} */
+};
+} // end of namespace bpp.
+
+#endif // _SUBSTITUTIONMODELSET_H_
+
diff --git a/src/Bpp/Phyl/Model/SubstitutionModelSetTools.cpp b/src/Bpp/Phyl/Model/SubstitutionModelSetTools.cpp
new file mode 100644
index 0000000..35a3cf5
--- /dev/null
+++ b/src/Bpp/Phyl/Model/SubstitutionModelSetTools.cpp
@@ -0,0 +1,211 @@
+//
+// File: SubstitutionModelSetTools.cpp
+// Created by: Julien Dutheil
+// Created on: tue Sep 17 16:57 2007
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "SubstitutionModelSetTools.h"
+#include "MixedSubstitutionModelSet.h"
+#include "MixedSubstitutionModel.h"
+
+using namespace bpp;
+
+using namespace std;
+
+SubstitutionModelSet* SubstitutionModelSetTools::createHomogeneousModelSet(
+  SubstitutionModel* model,
+  FrequenciesSet* rootFreqs,
+  const Tree* tree
+  ) throw (AlphabetException, Exception)
+{
+  // Check alphabet:
+  if (model->getAlphabet()->getAlphabetType() != rootFreqs->getAlphabet()->getAlphabetType())
+    throw AlphabetMismatchException("SubstitutionModelSetTools::createHomogeneousModelSet()", model->getAlphabet(), rootFreqs->getAlphabet());
+  if (dynamic_cast<MixedSubstitutionModel*>(model) != NULL)
+    throw Exception("createHomogeneousModelSet non yet programmed for mixture models.");
+
+  SubstitutionModelSet*  modelSet = new SubstitutionModelSet(model->getAlphabet());
+
+  modelSet->setRootFrequencies(rootFreqs);
+  // We assign this model to all nodes in the tree (excepted root node), and link all parameters with it.
+  vector<int> ids = tree->getNodesId();
+  int rootId = tree->getRootId();
+  unsigned int pos = 0;
+  for (unsigned int i = 0; i < ids.size(); i++)
+  {
+    if (ids[i] == rootId)
+    {
+      pos = i;
+      break;
+    }
+  }
+  ids.erase(ids.begin() + pos);
+  modelSet->addModel(model, ids, model->getParameters().getParameterNames());
+
+  return modelSet;
+}
+
+SubstitutionModelSet* SubstitutionModelSetTools::createNonHomogeneousModelSet(
+  SubstitutionModel* model,
+  FrequenciesSet* rootFreqs,
+  const Tree* tree,
+  const vector<string>& globalParameterNames
+  ) throw (AlphabetException, Exception)
+{
+  // Check alphabet:
+  if (rootFreqs && model->getAlphabet()->getAlphabetType() != rootFreqs->getAlphabet()->getAlphabetType())
+    throw AlphabetMismatchException("SubstitutionModelSetTools::createNonHomogeneousModelSet()", model->getAlphabet(), rootFreqs->getAlphabet());
+  ParameterList globalParameters, branchParameters;
+  globalParameters = model->getParameters();
+
+  vector<string> globalParameterNames2; // vector of the complete names of global parameters
+
+  // First get correct parameter names
+  size_t i, j;
+
+  for (i = 0; i < globalParameterNames.size(); i++)
+  {
+    if (globalParameterNames[i].find("*") != string::npos)
+    {
+      for (j = 0; j < globalParameters.size(); j++)
+      {
+        StringTokenizer stj(globalParameterNames[i], "*", true, false);
+        size_t pos1, pos2;
+        string parn = globalParameters[j].getName();
+        bool flag(true);
+        string g = stj.nextToken();
+        pos1 = parn.find(g);
+        if (pos1 != 0)
+          flag = false;
+        pos1 += g.length();
+        while (flag && stj.hasMoreToken())
+        {
+          g = stj.nextToken();
+          pos2 = parn.find(g, pos1);
+          if (pos2 == string::npos)
+          {
+            flag = false;
+            break;
+          }
+          pos1 = pos2 + g.length();
+        }
+        if (flag &&
+            ((g.length() == 0) || (pos1 == parn.length()) || (parn.rfind(g) == parn.length() - g.length())))
+          globalParameterNames2.push_back(parn);
+      }
+    }
+    else if (!globalParameters.hasParameter(globalParameterNames[i]))
+      throw Exception("SubstitutionModelSetTools::createNonHomogeneousModelSet. Parameter '" + globalParameterNames[i] + "' is not valid.");
+    else
+      globalParameterNames2.push_back(globalParameterNames[i]);
+  }
+
+  // remove non global parameters
+  for (i = globalParameters.size(); i > 0; i--)
+  {
+    if (find(globalParameterNames2.begin(), globalParameterNames2.end(), globalParameters[i - 1].getName()) == globalParameterNames2.end())
+    {
+      // not a global parameter:
+      branchParameters.addParameter(globalParameters[i - 1]);
+      globalParameters.deleteParameter(i - 1);
+    }
+  }
+
+  bool mixed = (dynamic_cast<MixedSubstitutionModel*>(model) != NULL);
+  SubstitutionModelSet*  modelSet;
+  if (mixed)
+  {
+    modelSet = new MixedSubstitutionModelSet(model->getAlphabet());
+    // Remove the "relproba" parameters from the branch parameters and put them in the global parameters, for the hypernodes
+    for (i = branchParameters.size(); i > 0; i--)
+    {
+      if (branchParameters[i - 1].getName().find("relproba") != string::npos)
+      {
+        globalParameters.addParameter(branchParameters[i - 1]);
+        branchParameters.deleteParameter(i - 1);
+      }
+    }
+  }
+  else
+    modelSet = new SubstitutionModelSet(model->getAlphabet());
+
+  if (rootFreqs)
+    modelSet->setRootFrequencies(rootFreqs);
+
+  // We assign a copy of this model to all nodes in the tree (excepted root node), and link all parameters with it.
+  vector<int> ids = tree->getNodesId();
+  int rootId = tree->getRootId();
+  size_t pos = 0;
+  for (i = 0; i < ids.size(); i++)
+  {
+    if (ids[i] == rootId)
+    {
+      pos = i;
+      break;
+    }
+  }
+
+  ids.erase(ids.begin() + pos);
+  for (i = 0; i < ids.size(); i++)
+  {
+    modelSet->addModel(dynamic_cast<SubstitutionModel*>(model->clone()), vector<int>(1, ids[i]), branchParameters.getParameterNames());
+  }
+
+  // Now add global parameters to all nodes:
+  modelSet->addParameters(globalParameters, ids);
+
+  // Defines the hypernodes if mixed
+  if (mixed)
+  {
+    MixedSubstitutionModelSet* pMSMS = dynamic_cast<MixedSubstitutionModelSet*>(modelSet);
+    MixedSubstitutionModel* pMSM = dynamic_cast<MixedSubstitutionModel*>(model);
+
+    size_t nbm = pMSM->getNumberOfModels();
+    for (i = 0; i < nbm; i++)
+    {
+      pMSMS->addEmptyHyperNode();
+      for (j = 0; j < ids.size(); j++)
+      {
+        pMSMS->addToHyperNode(j, vector<int>(1, static_cast<int>(i)));
+      }
+    }
+    pMSMS->computeHyperNodesProbabilities();
+  }
+
+  delete model; // delete template model.
+  return modelSet;
+}
+
diff --git a/src/Bpp/Phyl/Model/SubstitutionModelSetTools.h b/src/Bpp/Phyl/Model/SubstitutionModelSetTools.h
new file mode 100644
index 0000000..8ffbe57
--- /dev/null
+++ b/src/Bpp/Phyl/Model/SubstitutionModelSetTools.h
@@ -0,0 +1,100 @@
+//
+// File: SubstitutionModelSetTools.h
+// Created by: Julien Dutheil
+// Created on: tue Sep 17 16:57 2007
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _SUBSTITUTIONMODELSETTOOLS_H_
+#define _SUBSTITUTIONMODELSETTOOLS_H_
+
+#include "SubstitutionModelSet.h"
+#include "../Tree.h"
+
+//From the STL:
+#include <vector>
+#include <map>
+
+namespace bpp
+{
+
+/**
+ * @brief Tools for automatically creating SubstitutionModelSet objects.
+ */
+class SubstitutionModelSetTools
+{
+
+  public:
+
+    /**
+     * @brief Create a SubstitutionModelSet object, corresponding to the homogeneous case.
+     *
+     * This class is mainly for testing purpose.
+     *
+     * @param model     The model to use.
+     * @param rootFreqs A FrequenciesSet object to parametrize root frequencies.
+     * @param tree      The tree to use for the construction of the set.
+     */
+    static SubstitutionModelSet* createHomogeneousModelSet(
+        SubstitutionModel* model,
+        FrequenciesSet* rootFreqs,
+        const Tree* tree
+      ) throw (AlphabetException, Exception);
+
+    /**
+     * @brief Create a SubstitutionModelSet object, with one model per branch.
+     *
+     * All branches share the same type of model, but allow one set of parameters per branch.
+     * This is also possible to specify some parameters to be common to all branches.
+     *
+     * @param model                The model to use.
+     * @param rootFreqs            A FrequenciesSet object to parametrize root frequencies.
+     * @param tree                 The tree to use for the construction of the set.
+     * @param globalParameterNames Common parameters for all branches.
+     * All other parameters will be considered distinct for all branches.
+     */
+    static SubstitutionModelSet* createNonHomogeneousModelSet(
+        SubstitutionModel* model,
+        FrequenciesSet* rootFreqs,
+        const Tree* tree,
+        const std::vector<std::string>& globalParameterNames
+      ) throw (AlphabetException, Exception);
+
+};
+
+} //end of namespace bpp.
+
+#endif //_SUBSTITUTIONMODELSETTOOLS_H_
+
diff --git a/src/Bpp/Phyl/Model/TS98.h b/src/Bpp/Phyl/Model/TS98.h
new file mode 100644
index 0000000..48208af
--- /dev/null
+++ b/src/Bpp/Phyl/Model/TS98.h
@@ -0,0 +1,138 @@
+//
+// File: TS98.h
+// Created by: Julien Dutheil
+// Created on: Sat Aug 19 11:37 2006
+//
+
+/*
+  Copyright or © or Copr. CNRS, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _TS98_H_
+#define _TS98_H_
+
+#include "MarkovModulatedSubstitutionModel.h"
+
+//From NumCalc:
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+#include <Bpp/Numeric/Parameter.h>
+
+namespace bpp
+{
+
+  /**
+   * @brief Tuffley and Steel's 1998 covarion model.
+   *
+   * This model is a subclass of the so-called Markov-modulated substitution models,
+   * with a rate matrix
+   * @f[
+   * G = \begin{pmatrix}
+   * -s_1 & s_1\\
+   * s_2 & -s_2
+   * \end{pmatrix}
+   * @f]
+   * and
+   * @f[
+   * D_R = \begin{pmatrix}
+   * 0 & 0\\
+   * 0 & \dfrac{s_1+s_2}{s_1}
+   * \end{pmatrix}.
+   * @f]
+   * This model was originally designed for nucleotides sequences, but it can be used with other alphabets.
+   *
+   * @see MarkovModulatedSubstitutionModel
+   *
+   * Tuffley C. and Steel M. A., Modelling the covarion hypothesis of nucleotide substitution (1998),
+   * _Math. Biosci._, 147:63-91.
+   */
+  class TS98:
+    public MarkovModulatedSubstitutionModel
+  {
+  public:
+    /**
+     * @brief Build a new TS98 substitution model.
+     *
+     * @param model The substitution model to use. May be of any alphabet type.
+     * @param s1    First rate parameter.
+     * @param s2    Second rate parameter.
+     * @param normalizeRateChanges Tell if the rate transition matrix should be normalized.
+     */
+    TS98(ReversibleSubstitutionModel * model, double s1 = 1., double s2 = 1., bool normalizeRateChanges = false):
+      MarkovModulatedSubstitutionModel(model, normalizeRateChanges, "TS98.")
+    {
+      nbRates_ = 2;
+      ratesExchangeability_.resize(2, 2);
+      rates_.resize(2, 2);
+      ratesFreq_.resize(2);
+      addParameter_(new Parameter("TS98.s1", s1, &Parameter::R_PLUS_STAR));
+      addParameter_(new Parameter("TS98.s2", s2, &Parameter::R_PLUS_STAR));
+      updateRatesModel();
+      updateMatrices();
+    }
+
+    virtual ~TS98() {}
+
+#ifndef NO_VIRTUAL_COV
+    TS98*
+#else
+    Clonable*
+#endif
+    clone() const { return new TS98(*this); }
+
+  public:
+    std::string getName() const { return "TS98"; }
+
+    double getRate() const { return 1.;}
+
+    void setRate(double rate) {};
+
+    void addRateParameter() {};
+
+  protected:
+    void updateRatesModel()
+    {
+      double s1 = getParameterValue("s1");
+      double s2 = getParameterValue("s2");
+      ratesFreq_[0] = s2/(s1+s2);
+      ratesFreq_[1] = s1/(s1+s2);
+      rates_(1,1) = (s1+s2)/s1;
+      ratesExchangeability_(0,1) = ratesExchangeability_(1,0) = s1+s2;
+      ratesExchangeability_(0,0) = -s1*(s1+s2)/s2;
+      ratesExchangeability_(1,1) = -s2*(s1+s2)/s1;
+    }
+	
+  };
+
+} //end of namespace bpp.
+
+#endif // _TS98_H_
+
diff --git a/src/Bpp/Phyl/Model/WordSubstitutionModel.cpp b/src/Bpp/Phyl/Model/WordSubstitutionModel.cpp
new file mode 100644
index 0000000..5f10c0c
--- /dev/null
+++ b/src/Bpp/Phyl/Model/WordSubstitutionModel.cpp
@@ -0,0 +1,319 @@
+//
+// File: WordSubstitutionModel.cpp
+// Created by:  Laurent Gueguen
+// Created on: Jan 2009
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "WordSubstitutionModel.h"
+#include "FrequenciesSet/WordFrequenciesSet.h"
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Matrix/EigenValue.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/WordAlphabet.h>
+#include <Bpp/Seq/Container/SequenceContainerTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <cmath>
+
+using namespace std;
+
+/******************************************************************************/
+
+WordSubstitutionModel::WordSubstitutionModel(
+  const std::vector<SubstitutionModel*>& modelVector,
+  const std::string& st) :
+  AbstractParameterAliasable((st == "") ? "Word." : st),
+  AbstractSubstitutionModel(AbstractWordSubstitutionModel::extractAlph(modelVector),
+                            (st == "") ? "Word." : st),
+  AbstractWordSubstitutionModel(modelVector,
+                                (st == "") ? "Word." : st)
+{
+  size_t i, nbmod = VSubMod_.size();
+
+  // relative rates
+  for (i = 0; i < nbmod - 1; i++)
+  {
+    addParameter_(new Parameter("Word.relrate" + TextTools::toString(i + 1), 1.0 / static_cast<int>(nbmod - i), &Parameter::PROP_CONSTRAINT_EX));
+  }
+
+  WordSubstitutionModel::updateMatrices();
+}
+
+WordSubstitutionModel::WordSubstitutionModel(
+  const Alphabet* alph,
+  const std::string& st) :
+  AbstractParameterAliasable((st == "") ? "Word." : st),
+  AbstractSubstitutionModel(alph,
+                            (st == "") ? "Word." : st),
+  AbstractWordSubstitutionModel(alph,
+                                (st == "") ? "Word." : st)
+{}
+
+WordSubstitutionModel::WordSubstitutionModel(
+  SubstitutionModel* pmodel,
+  unsigned int num,
+  const std::string& st) :
+  AbstractParameterAliasable((st == "") ? "Word." : st),
+  AbstractSubstitutionModel(pmodel->getAlphabet(),
+                            (st == "") ? "Word." : st),
+  AbstractWordSubstitutionModel(pmodel,
+                                num,
+                                (st == "") ? "Word." : st)
+{
+  size_t i;
+
+  // relative rates
+  for (i = 0; i < num - 1; i++)
+  {
+    addParameter_(new Parameter("Word.relrate" + TextTools::toString(i + 1), 1.0 / static_cast<int>(num - i ), &Parameter::PROP_CONSTRAINT_EX));
+  }
+
+  WordSubstitutionModel::updateMatrices();
+}
+
+void WordSubstitutionModel::updateMatrices()
+{
+  size_t i, nbmod = VSubMod_.size();
+  double x, y;
+  x = 1.0;
+
+  for (i = 0; i < nbmod - 1; i++)
+  {
+    y = getParameterValue("relrate" + TextTools::toString(i + 1));
+    Vrate_[i] = x * y;
+    x *= 1 - y;
+  }
+  Vrate_[nbmod - 1] = x;
+
+  AbstractWordSubstitutionModel::updateMatrices();
+}
+
+void WordSubstitutionModel::completeMatrices()
+{
+  size_t nbmod = VSubMod_.size();
+  size_t i, p, j, m;
+  size_t salph = getAlphabet()->getSize();
+
+  // freq_ for this generator
+
+  for (i = 0; i < salph; i++)
+  {
+    freq_[i] = 1;
+    j = i;
+    for (p = nbmod - 1; p >= 0; p--)
+    {
+      m = VSubMod_[p]->getNumberOfStates();
+      freq_[i] *= VSubMod_[p]->getFrequencies()[j % m];
+      j /= m;
+    }
+  }
+}
+
+const RowMatrix<double>& WordSubstitutionModel::getPij_t(double d) const
+{
+  vector<const Matrix<double>*> vM;
+  size_t nbmod = VSubMod_.size();
+  size_t i, j;
+
+  for (i = 0; i < nbmod; i++)
+  {
+    vM.push_back(&VSubMod_[i]->getPij_t(d * Vrate_[i] * rate_));
+  }
+
+  size_t t;
+  double x;
+  size_t i2, j2;
+  size_t nbStates = getNumberOfStates();
+  size_t p;
+
+  for (i = 0; i < nbStates; i++)
+  {
+    for (j = 0; j < nbStates; j++)
+    {
+      x = 1.;
+      i2 = i;
+      j2 = j;
+      for (p = nbmod; p > 0; p--)
+      {
+        t = VSubMod_[p - 1]->getNumberOfStates();
+        x *= (*vM[p - 1])(i2 % t, j2 % t);
+        i2 /= t;
+        j2 /= t;
+      }
+      pijt_(i, j) = x;
+    }
+  }
+  return pijt_;
+}
+
+const RowMatrix<double>& WordSubstitutionModel::getdPij_dt(double d) const
+{
+  vector<const Matrix<double>*> vM, vdM;
+  size_t nbmod = VSubMod_.size();
+  size_t i, j;
+
+  for (i = 0; i < nbmod; i++)
+  {
+    vM.push_back(&VSubMod_[i]->getPij_t(d * Vrate_[i] * rate_));
+    vdM.push_back(&VSubMod_[i]->getdPij_dt(d * Vrate_[i] * rate_));
+  }
+
+  size_t t;
+  double x, r;
+  size_t i2, j2;
+  size_t nbStates = getNumberOfStates();
+  size_t p, q;
+
+  for (i = 0; i < nbStates; i++)
+  {
+    for (j = 0; j < nbStates; j++)
+    {
+      r = 0;
+      for (q = 0; q < nbmod; q++)
+      {
+        i2 = i;
+        j2 = j;
+        x = 1;
+        for (p = nbmod; p > 0; p--)
+        {
+          t = VSubMod_[p - 1]->getNumberOfStates();
+          if (q != p - 1)
+            x *= (*vM[p - 1])(i2 % t, j2 % t);
+          else
+            x *= rate_ * Vrate_[p - 1] * (*vdM[p - 1])(i2 % t, j2 % t);
+          i2 /= t;
+          j2 /= t;
+        }
+        r += x;
+      }
+      dpijt_(i, j) = r;
+    }
+  }
+  return dpijt_;
+}
+
+const RowMatrix<double>& WordSubstitutionModel::getd2Pij_dt2(double d) const
+
+{
+  vector<const Matrix<double>*> vM, vdM, vd2M;
+  size_t nbmod = VSubMod_.size();
+  size_t i, j;
+
+  for (i = 0; i < nbmod; i++)
+  {
+    vM.push_back(&VSubMod_[i]->getPij_t(d * Vrate_[i] * rate_));
+    vdM.push_back(&VSubMod_[i]->getdPij_dt(d * Vrate_[i] * rate_));
+    vd2M.push_back(&VSubMod_[i]->getd2Pij_dt2(d * Vrate_[i] * rate_));
+  }
+
+
+  double r, x;
+  size_t p, b, q, t;
+
+  size_t i2, j2;
+  size_t nbStates = getNumberOfStates();
+
+
+  for (i = 0; i < nbStates; i++)
+  {
+    for (j = 0; j < nbStates; j++)
+    {
+      r = 0;
+      for (q = 1; q < nbmod; q++)
+      {
+        for (b = 0; b < q; b++)
+        {
+          x = 1;
+          i2 = i;
+          j2 = j;
+          for (p = nbmod; p > 0; p--)
+          {
+            t = VSubMod_[p - 1]->getNumberOfStates();
+            if ((p - 1 == q) || (p - 1 == b))
+              x *= rate_ * Vrate_[p - 1] * (*vdM[p - 1])(i2 % t, j2 % t);
+            else
+              x *= (*vM[p - 1])(i2 % t, j2 % t);
+
+            i2 /= t;
+            j2 /= t;
+          }
+          r += x;
+        }
+      }
+
+      r *= 2;
+
+      for (q = 0; q < nbmod; q++)
+      {
+        x = 1;
+        i2 = i;
+        j2 = j;
+        for (p = nbmod; p > 0; p--)
+        {
+          t = VSubMod_[p - 1]->getNumberOfStates();
+          if (q != p - 1)
+            x *= (*vM[p - 1])(i2 % t, j2 % t);
+          else
+            x *= rate_ * rate_ * Vrate_[p - 1] * Vrate_[p - 1] * (*vd2M[p - 1])(i2 % t, j2 % t);
+
+          i2 /= t;
+          j2 /= t;
+        }
+        r += x;
+      }
+      d2pijt_(i, j) = r;
+    }
+  }
+  return d2pijt_;
+}
+
+string WordSubstitutionModel::getName() const
+{
+  size_t nbmod = VSubMod_.size();
+  string s = "WordSubstitutionModel model: " + VSubMod_[0]->getName();
+  for (size_t i = 1; i < nbmod - 1; i++)
+  {
+    s += " " + VSubMod_[i]->getName();
+  }
+
+  return s;
+}
+
+
diff --git a/src/Bpp/Phyl/Model/WordSubstitutionModel.h b/src/Bpp/Phyl/Model/WordSubstitutionModel.h
new file mode 100644
index 0000000..fe32fbb
--- /dev/null
+++ b/src/Bpp/Phyl/Model/WordSubstitutionModel.h
@@ -0,0 +1,129 @@
+//
+// File: WordSubstitutionModel.h
+// Created by: Laurent Gueguen
+// Created on: Jan 2009
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _WORDSUBSTITUTIONMODEL_H_
+#define _WORDSUBSTITUTIONMODEL_H_
+
+#include "AbstractWordSubstitutionModel.h"
+#include <Bpp/Numeric/Matrix/Matrix.h>
+#include <Bpp/BppVector.h>
+
+namespace bpp
+{
+/**
+ * @brief Basal class for words of reversible substitution models.
+ * @author Laurent Guéguen
+ *
+ * Only substitutions with one letter changed are accepted. Hence the
+ * equilibrium frequency of each word is the product of the
+ * equilibrium frequencies of the letters.</p>
+ *
+ * If there are @f$n at f$ models, @f$\rho_i at f$ is the rate of
+ * model i (@f$\sum_{i=1}^{n} \rho_i = 1 at f$) and the rates
+ * are defined by relative rates parameters @f$r_i at f$
+ * (called "relratei") with:
+ * @f[
+ * 1 <= i < n, \rho_i = (1-r_1).(1-r_2)...(1-r_{i-1}).r_{i}
+ * @f]
+ * @f[
+ * \rho_n = (1-r_1).(1-r_2)...(1-r_{n-1})
+ * @f]
+ * and
+ * @f[
+ * \forall 1 <= i < n, r_i = \frac{\rho_i}{1-(\rho_1+...\rho_{i-1})}
+ * @f]
+ * where @f$\rho_i at f$ stands for the rate of position @f$i at f$.
+ */
+
+class WordSubstitutionModel :
+  public AbstractWordSubstitutionModel
+{
+public:
+  /**
+   * @brief Build a new WordSubstitutionModel object from a
+   * Vector of pointers to SubstitutionModels.
+   *
+   * @param modelVector the Vector of substitution models to use, in
+   *   the order of the positions in the words from left to right. All
+   *   the models must be different objects to avoid parameters
+   *   redundancy, otherwise only the first model is used. The used models
+   *   are owned by the instance.
+   * @param st the Namespace.
+   */
+  WordSubstitutionModel(const std::vector<SubstitutionModel*>& modelVector, const std::string& st = "");
+
+  /**
+   * @brief Build a new WordSubstitutionModel object from a
+   * pointer to an SubstitutionModel and a number of
+   * desired models.
+   *
+   * @param pmodel pointer to the substitution model to use in all the
+   *  positions. It is owned by the instance.
+   * @param num The number of models involved.
+   * @param st the Namespace.
+   */
+  WordSubstitutionModel(SubstitutionModel* pmodel, unsigned int num, const std::string& st = "");
+
+  virtual ~WordSubstitutionModel() {}
+
+  WordSubstitutionModel* clone() const { return new WordSubstitutionModel(*this); }
+
+protected:
+  /**
+   *@brief Constructor for the derived classes only
+   */
+
+  WordSubstitutionModel(const Alphabet* alph, const std::string& = "");
+
+  virtual void updateMatrices();
+  virtual void completeMatrices();
+
+public:
+  virtual const RowMatrix<double>& getPij_t(double d) const;
+
+  virtual const RowMatrix<double>& getdPij_dt(double d) const;
+
+  virtual const RowMatrix<double>& getd2Pij_dt2(double d) const;
+
+  virtual std::string getName() const;
+};
+} // end of namespace bpp.
+
+#endif  // _WORDSUBSTITUTIONMODEL
+
diff --git a/src/Bpp/Phyl/NNISearchable.h b/src/Bpp/Phyl/NNISearchable.h
new file mode 100755
index 0000000..1844154
--- /dev/null
+++ b/src/Bpp/Phyl/NNISearchable.h
@@ -0,0 +1,151 @@
+//
+// File: NNISearchable.h
+// Created by: Julien Dutheil
+//             Vincent Ranwez
+// Created on: Thu Jul 28 16:32 2005
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _NNISEARCHABLE_H_
+#define _NNISEARCHABLE_H_
+
+#include "Node.h"
+#include "TreeTemplate.h"
+#include "TopologySearch.h"
+
+namespace bpp
+{
+
+/**
+ * @brief Interface for Nearest Neighbor Interchanges algorithms.
+ *
+ * This interface defines the methods to work with NNI algorithms.
+ * 
+ * NNISearchable objects are supposed to work with TreeTemplate objects.
+ * NNI are defined as follow:
+ * <pre>
+ * ------------->
+ *     +------- C
+ *     |
+ * D --+ X  +-- B
+ *     |    |
+ *     +----+ F
+ *          |
+ *          +-- A
+ * </pre>
+ * Where:
+ * -F is the focus (parent) node,
+ * -A and B are the son of F
+ * -X is the parent of F and so on.
+ * Two NNI's are possible for branch (XF):
+ * - swaping B and C, which is the same as D and A
+ * - swaping A and C, which is the same as D and B
+ * Because of the rooted representation, we'll consider B \f$\leftrightarrow\f$ C and A \f$\leftrightarrow\f$ C,
+ * which are simpler to perform.
+ *
+ * For unrooted tree, we have at the 'root' node:
+ * <pre>
+ * ------------->
+ *   +------- D
+ *   |
+ * X +------- C
+ *   |
+ *   |    +-- B
+ *   |    |
+ *   +----+ F
+ *        |
+ *        +-- A
+ * </pre>
+ * In this case, we swap A or B with one of C or D.
+ * Which one of C or D depends on the implementation, but will always be the same,
+ * so that swapping A or B involve 2 distinct NNI.
+ * 
+ */
+class NNISearchable:
+  public TopologyListener,
+  public virtual Clonable
+{
+	public:
+		NNISearchable() {}
+		virtual ~NNISearchable() {}
+
+#ifndef NO_VIRTUAL_COV
+    virtual NNISearchable* clone() const = 0;
+#endif
+
+	public:
+
+		/**
+		 * @brief Send the score of a NNI movement, without performing it.
+		 *
+		 * This methods sends the score variation.
+		 * This variation must be negative if the new point is better,
+		 * i.e. the object is to be used with a minimizing optimization
+		 * (for consistence with Optimizer objects).
+		 *
+		 * @param nodeId The id of the node defining the NNI movement.
+		 * @return The score variation of the NNI.
+		 * @throw NodeException If the node does not define a valid NNI.
+		 */
+		virtual double testNNI(int nodeId) const throw (NodeException) = 0;
+
+		/**
+		 * @brief Perform a NNI movement.
+		 *
+		 * @param nodeId The id of the node defining the NNI movement.
+		 * @throw NodeException If the node does not define a valid NNI.
+		 */
+		virtual void doNNI(int nodeId) throw (NodeException) = 0;
+
+		/**
+		 * @brief Get the tree associated to this NNISearchable object.
+		 *
+		 * @return The tree associated to this instance.
+		 */
+		virtual const Tree& getTopology() const = 0;
+    
+    /**
+     * @brief Get the current score of this NNISearchable object.
+     *
+     * @return The current score of this instance.
+     */
+    virtual double getTopologyValue() const throw (Exception) = 0;
+
+};
+
+} //end of namespace bpp.
+
+#endif //_NNISEARCHABLE_H_
+
diff --git a/src/Bpp/Phyl/NNITopologySearch.cpp b/src/Bpp/Phyl/NNITopologySearch.cpp
new file mode 100644
index 0000000..668a5dd
--- /dev/null
+++ b/src/Bpp/Phyl/NNITopologySearch.cpp
@@ -0,0 +1,367 @@
+//
+// File: NNITopologySearch.cpp
+// Created by: Julien Dutheil
+// Created on: Wed Oct 12 10:52 2005
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "NNITopologySearch.h"
+#include "Likelihood/NNIHomogeneousTreeLikelihood.h"
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <cmath>
+
+using namespace std;
+
+const string NNITopologySearch::FAST   = "Fast";
+const string NNITopologySearch::BETTER = "Better";
+const string NNITopologySearch::PHYML  = "PhyML";
+
+void NNITopologySearch::notifyAllPerformed(const TopologyChangeEvent& event)
+{
+  searchableTree_->topologyChangePerformed(event);
+  for (size_t i = 0; i < topoListeners_.size(); i++)
+  {
+    topoListeners_[i]->topologyChangePerformed(event);
+  }
+}
+
+void NNITopologySearch::notifyAllTested(const TopologyChangeEvent& event)
+{
+  searchableTree_->topologyChangeTested(event);
+  for (size_t i = 0; i < topoListeners_.size(); i++)
+  {
+    topoListeners_[i]->topologyChangeTested(event);
+  }
+}
+
+void NNITopologySearch::notifyAllSuccessful(const TopologyChangeEvent& event)
+{
+  searchableTree_->topologyChangeSuccessful(event);
+  for (size_t i = 0; i < topoListeners_.size(); i++)
+  {
+    topoListeners_[i]->topologyChangeSuccessful(event);
+  }
+}
+
+void NNITopologySearch::search() throw (Exception)
+{
+  if (algorithm_ == FAST)
+    searchFast();
+  else if (algorithm_ == BETTER)
+    searchBetter();
+  else if (algorithm_ == PHYML)
+    searchPhyML();
+  else
+    throw Exception("Unknown NNI algorithm: " + algorithm_ + ".\n");
+}
+
+void NNITopologySearch::searchFast() throw (Exception)
+{
+  bool test = true;
+  do
+  {
+    TreeTemplate<Node> tree(searchableTree_->getTopology());
+    vector<Node*> nodes = tree.getNodes();
+
+    vector<Node*> nodesSub = nodes;
+    for (size_t i = nodesSub.size(); i > 0; i--)
+    {
+      // !!! must not reach i==0 because of size_t
+      if (!(nodesSub[i - 1]->hasFather()))
+        nodesSub.erase(nodesSub.begin() + i - 1);  // Remove root node.
+      else if (!(nodesSub[i - 1]->getFather()->hasFather()))
+        nodesSub.erase(nodesSub.begin() + i - 1);  // Remove son of root node.
+    }
+
+    // Test all NNIs:
+    test = false;
+    for (size_t i = 0; !test && i < nodesSub.size(); i++)
+    {
+      Node* node = nodesSub[i];
+      double diff = searchableTree_->testNNI(node->getId());
+      if (verbose_ >= 3)
+      {
+        ApplicationTools::displayResult("   Testing node " + TextTools::toString(node->getId())
+                                        + " at " + TextTools::toString(node->getFather()->getId()),
+                                        TextTools::toString(diff));
+      }
+
+      if (diff < 0.)
+      { // Good NNI found...
+        if (verbose_ >= 2)
+        {
+          ApplicationTools::displayResult("   Swapping node " + TextTools::toString(node->getId())
+                                          + " at " + TextTools::toString(node->getFather()->getId()),
+                                          TextTools::toString(diff));
+        }
+        searchableTree_->doNNI(node->getId());
+        // Notify:
+        notifyAllPerformed(TopologyChangeEvent());
+        test = true;
+
+        if (verbose_ >= 1)
+          ApplicationTools::displayResult("   Current value", TextTools::toString(searchableTree_->getTopologyValue(), 10));
+      }
+    }
+  }
+  while (test);
+}
+
+void NNITopologySearch::searchBetter() throw (Exception)
+{
+  bool test = true;
+  do
+  {
+    TreeTemplate<Node> tree(searchableTree_->getTopology());
+    vector<Node*> nodes = tree.getNodes();
+
+    if (verbose_ >= 3)
+      ApplicationTools::displayTask("Test all possible NNIs...");
+
+    vector<Node*> nodesSub = nodes;
+    for (size_t i = nodesSub.size(); i > 0; i--)
+    { // !!! must not reach i==0 because of size_t
+      if (!(nodesSub[i - 1]->hasFather()))
+        nodesSub.erase(nodesSub.begin() + i - 1);  // Remove root node.
+      else if (!(nodesSub[i - 1]->getFather()->hasFather()))
+        nodesSub.erase(nodesSub.begin() + i - 1);  // Remove son of root node.
+    }
+
+    // Test all NNIs:
+    vector<Node*> improving;
+    vector<double> improvement;
+    if (verbose_ >= 2 && ApplicationTools::message)
+      ApplicationTools::message->endLine();
+    for (size_t i = 0; i < nodesSub.size(); i++)
+    {
+      Node* node = nodesSub[i];
+      double diff = searchableTree_->testNNI(node->getId());
+      if (verbose_ >= 3)
+      {
+        ApplicationTools::displayResult("   Testing node " + TextTools::toString(node->getId())
+                                        + " at " + TextTools::toString(node->getFather()->getId()),
+                                        TextTools::toString(diff));
+      }
+
+      if (diff < 0.)
+      {
+        improving.push_back(node);
+        improvement.push_back(diff);
+      }
+    }
+    if (verbose_ >= 3)
+      ApplicationTools::displayTaskDone();
+    test = improving.size() > 0;
+    if (test)
+    {
+      size_t nodeMin = VectorTools::whichMin(improvement);
+      Node* node = improving[nodeMin];
+      if (verbose_ >= 2)
+        ApplicationTools::displayResult("   Swapping node " + TextTools::toString(node->getId())
+                                        + " at " + TextTools::toString(node->getFather()->getId()),
+                                        TextTools::toString(improvement[nodeMin]));
+      searchableTree_->doNNI(node->getId());
+
+      // Notify:
+      notifyAllPerformed(TopologyChangeEvent());
+
+      if (verbose_ >= 1)
+        ApplicationTools::displayResult("   Current value", TextTools::toString(searchableTree_->getTopologyValue(), 10));
+    }
+  }
+  while (test);
+}
+
+void NNITopologySearch::searchPhyML() throw (Exception)
+{
+  bool test = true;
+  do
+  {
+    if (verbose_ >= 3)
+      ApplicationTools::displayTask("Test all possible NNIs...");
+    TreeTemplate<Node> tree(searchableTree_->getTopology());
+    vector<Node*> nodes = tree.getNodes();
+    vector<Node*> nodesSub = nodes;
+    for (size_t i = nodesSub.size(); i > 0; i--)
+    {
+      // !!! must not reach i==0 because of size_t
+      if (!(nodesSub[i - 1]->hasFather()))
+        nodesSub.erase(nodesSub.begin() + i - 1);  // Remove root node.
+      else if (!(nodesSub[i - 1]->getFather()->hasFather()))
+        nodesSub.erase(nodesSub.begin() + i - 1);  // Remove son of root node.
+    }
+
+    // Test all NNIs:
+    vector<int> improving;
+    vector<Node*> improvingNodes;
+    vector<double> improvement;
+    if (verbose_ >= 2 && ApplicationTools::message)
+      ApplicationTools::message->endLine();
+    for (size_t i = 0; i < nodesSub.size(); i++)
+    {
+      Node* node = nodesSub[i];
+      double diff = searchableTree_->testNNI(node->getId());
+      if (verbose_ >= 3)
+      {
+        ApplicationTools::displayResult("   Testing node " + TextTools::toString(node->getId())
+                                        + " at " + TextTools::toString(node->getFather()->getId()),
+                                        TextTools::toString(diff));
+      }
+
+      if (diff < 0.)
+      {
+        bool ok = true;
+        // Must test for incompatible NNIs...
+        for (size_t j = improving.size(); j > 0; j--)
+        {
+          if (improvingNodes[j - 1]->getFather()->getId() == node->getFather()->getId()
+              || improvingNodes[j - 1]->getFather()->getFather()->getId() == node->getFather()->getFather()->getId()
+              || improvingNodes[j - 1]->getId() == node->getFather()->getId()                           || improvingNodes[j - 1]->getFather()->getId() == node->getId()
+              || improvingNodes[j - 1]->getId() == node->getFather()->getFather()->getId()              || improvingNodes[j - 1]->getFather()->getFather()->getId() == node->getId()
+              || improvingNodes[j - 1]->getFather()->getId() == node->getFather()->getFather()->getId() || improvingNodes[j - 1]->getFather()->getFather()->getId() == node->getFather()->getId())
+          {
+            // These are incompatible NNIs. We only keep the best:
+            if (diff < improvement[j - 1])
+            { // Erase previous node
+              improvingNodes.erase(improvingNodes.begin() + j - 1);
+              improving.erase(improving.begin() + j - 1);
+              improvement.erase(improvement.begin() + j - 1);
+            } // Otherwise forget about this NNI.
+            else
+            {
+              ok = false;
+            }
+          }
+        }
+        if (ok)
+        { // We add this NNI to the list,
+          // by decreasing improvement:
+          size_t pos = improvement.size();
+          for (size_t j = 0; j < improvement.size(); j++)
+          {
+            if (diff < improvement[j])
+            {
+              pos = j; break;
+            }
+          }
+          if (pos < improvement.size())
+          {
+            improvingNodes.insert(improvingNodes.begin() + pos, node);
+            improving.insert(improving.begin() + pos, node->getId());
+            improvement.insert(improvement.begin() + pos, diff);
+          }
+          else
+          {
+            improvingNodes.insert(improvingNodes.end(), node);
+            improving.insert(improving.end(), node->getId());
+            improvement.insert(improvement.end(), diff);
+          }
+        }
+      }
+    }
+    // This array is no more useful.
+    // Moreover, if a backward movement is performed,
+    // the underlying node will not exist anymore...
+    improvingNodes.clear();
+    if (verbose_ >= 3)
+      ApplicationTools::displayTaskDone();
+    test = improving.size() > 0;
+    if (test)
+    {
+      double currentValue = searchableTree_->getTopologyValue();
+      bool test2 = true;
+      // Make a backup copy:
+      NNISearchable* backup = dynamic_cast<NNISearchable*>(searchableTree_->clone());
+      do
+      {
+        if (verbose_ >= 1)
+          ApplicationTools::displayMessage("Trying to perform " + TextTools::toString(improving.size()) + " NNI(s).");
+        for (size_t i = 0; i < improving.size(); i++)
+        {
+          int nodeId = improving[i];
+          if (verbose_ >= 2)
+          {
+            ApplicationTools::displayResult(string("   Swapping node ") + TextTools::toString(nodeId)
+                                            + string(" at ") + TextTools::toString(searchableTree_->getTopology().getFatherId(nodeId)),
+                                            TextTools::toString(improvement[i]));
+          }
+          searchableTree_->doNNI(improving[i]);
+        }
+
+        // Notify:
+        notifyAllTested(TopologyChangeEvent());
+        if (verbose_ >= 1)
+          ApplicationTools::displayResult("   Current value", TextTools::toString(searchableTree_->getTopologyValue(), 10));
+        if (searchableTree_->getTopologyValue() >= currentValue)
+        {
+          // No improvement!
+          // Restore backup:
+          delete searchableTree_;
+          searchableTree_ = dynamic_cast<NNISearchable*>(backup->clone());
+          if (verbose_ >= 1)
+          {
+            ApplicationTools::displayResult("Score >= current score! Moving backward", TextTools::toString(searchableTree_->getTopologyValue()));
+          }
+          // And try doing half of the movements:
+          if (improving.size() == 1)
+          {
+            // Problem! This should have worked!!!
+            throw Exception("NNITopologySearch::searchPhyML. Error, no improving NNI!\n This may be due to a change in parameters between testNNI and doNNI. Check your code!");
+          }
+          size_t n = (size_t)ceil((double)improving.size() / 2.);
+          improving.erase(improving.begin() + n, improving.end());
+          improvement.erase(improvement.begin() + n, improvement.end());
+        }
+        else
+        {
+          test2 = false;
+        }
+      }
+      while (test2);
+      delete backup;
+      // Notify:
+      notifyAllSuccessful(TopologyChangeEvent());
+    }
+  }
+  while (test);
+}
+
diff --git a/src/Bpp/Phyl/NNITopologySearch.h b/src/Bpp/Phyl/NNITopologySearch.h
new file mode 100755
index 0000000..b42e6d9
--- /dev/null
+++ b/src/Bpp/Phyl/NNITopologySearch.h
@@ -0,0 +1,172 @@
+//
+// File: NNITopologySearch.h
+// Created by: Julien Dutheil
+// Created on: Wed Oct 12 10:52 2005
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _NNITOPOLOGYSEARCH_H_
+#define _NNITOPOLOGYSEARCH_H_
+
+#include "TopologySearch.h"
+#include "NNISearchable.h"
+
+namespace bpp
+{
+
+/**
+ * @brief NNI topology search method.
+ *
+ * Several algorithm are implemented:
+ * - Fast algorithm: loop over all nodes, check all NNIs and perform the corresponding change if it improve the score.
+ *   When a NNI is done, reloop from the first node without checking the remaining ones.
+ * - Better algorithm: loop over all nodes, check all NNIS.
+ *   Then choose the NNI corresponding to the best improvement and perform it.
+ *   Then re-loop over all nodes.
+ * - PhyML algorithm (not fully tested, use with care): as the previous one, but perform all NNI improving the score at the same time.
+ *   Leads to faster convergence.
+ */
+class NNITopologySearch :
+  public virtual TopologySearch
+{
+	public:
+		const static std::string FAST;
+		const static std::string BETTER;
+		const static std::string PHYML;
+		
+	private:
+		NNISearchable* searchableTree_;
+    std::string algorithm_;
+		unsigned int verbose_;
+    std::vector<TopologyListener*> topoListeners_;
+		
+	public:
+		NNITopologySearch(
+        NNISearchable& tree,
+        const std::string& algorithm = FAST,
+        unsigned int verbose = 2) :
+      searchableTree_(&tree), algorithm_(algorithm), verbose_(verbose), topoListeners_()
+    {}
+
+    NNITopologySearch(const NNITopologySearch& ts) :
+      searchableTree_(ts.searchableTree_),
+      algorithm_(ts.algorithm_),
+      verbose_(ts.verbose_),
+      topoListeners_(ts.topoListeners_)
+    {
+      //Hard-copy all listeners:
+      for (unsigned int i = 0; i < topoListeners_.size(); i++)
+        topoListeners_[i] = dynamic_cast<TopologyListener*>(ts.topoListeners_[i]->clone());
+    }
+	
+    NNITopologySearch& operator=(const NNITopologySearch& ts)
+    {
+      searchableTree_ = ts.searchableTree_;
+      algorithm_      = ts.algorithm_;
+      verbose_        = ts.verbose_;
+      topoListeners_  = ts.topoListeners_;
+      //Hard-copy all listeners:
+      for (unsigned int i = 0; i < topoListeners_.size(); i++)
+        topoListeners_[i] = dynamic_cast<TopologyListener*>(ts.topoListeners_[i]->clone());
+      return *this;
+    }
+	
+	
+		virtual ~NNITopologySearch()
+    {
+      for (std::vector <TopologyListener*>::iterator it = topoListeners_.begin();
+           it != topoListeners_.end();
+           it++)
+        delete *it;
+    }
+
+	public:
+		void search() throw (Exception);
+    
+    /**
+     * @brief Add a listener to the list.
+     *
+     * All listeners will be notified in the order of the list.
+     * The first listener to be notified is the NNISearchable object itself.
+     *
+     * The listener will be owned by this instance, and copied when needed.
+     */
+    void addTopologyListener(TopologyListener* listener)
+    {
+      if (listener)
+        topoListeners_.push_back(listener);
+    }
+
+	public:
+		/**
+		 * @brief Retrieve the tree.
+		 *
+		 * @return The tree associated to this instance.
+		 */
+		const Tree& getTopology() const { return searchableTree_->getTopology(); }
+		
+    /**
+     * @return The NNISearchable object associated to this instance.
+     */
+    NNISearchable* getSearchableObject() { return searchableTree_; }
+    /**
+     * @return The NNISearchable object associated to this instance.
+     */
+    const NNISearchable* getSearchableObject() const { return searchableTree_; }
+
+	protected:
+		void searchFast()   throw (Exception);
+		void searchBetter() throw (Exception);
+		void searchPhyML()  throw (Exception);
+
+    /**
+     * @brief Process a TopologyChangeEvent to all listeners.
+     */
+    void notifyAllPerformed(const TopologyChangeEvent& event);
+    /**
+     * @brief Process a TopologyChangeEvent to all listeners.
+     */
+    void notifyAllTested(const TopologyChangeEvent& event);
+    /**
+     * @brief Process a TopologyChangeEvent to all listeners.
+     */
+    void notifyAllSuccessful(const TopologyChangeEvent& event);
+		
+};
+
+} //end of namespace bpp.
+
+#endif //_NNITOPOLOGYSEARCH_H_
+
diff --git a/src/Bpp/Phyl/Node.cpp b/src/Bpp/Phyl/Node.cpp
new file mode 100755
index 0000000..d8a50c1
--- /dev/null
+++ b/src/Bpp/Phyl/Node.cpp
@@ -0,0 +1,155 @@
+//
+// File: Node.cpp
+// Created by: Julien Dutheil
+// Created on: Thu Mar 13 12:03:18 2003
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "Node.h"
+#include "TreeTools.h"
+
+#include <Bpp/Exceptions.h>
+#include <Bpp/Text/TextTools.h>
+
+using namespace bpp;
+
+//from the STL:
+#include <algorithm>
+#include <iostream>
+
+using namespace std;
+
+/** Copy constructor: *********************************************************/
+  
+Node::Node(const Node& node):
+  id_(node.id_), name_(0),
+  sons_(), father_(0),
+  //, sons_(node.sons_), father_(node.father_),
+  distanceToFather_(0), nodeProperties_(), branchProperties_()
+{
+  name_             = node.hasName() ? new string(* node.name_) : 0;
+  distanceToFather_ = node.hasDistanceToFather() ? new double(* node.distanceToFather_) : 0;
+  for (map<string, Clonable *>::iterator i = node.nodeProperties_.begin(); i != node.nodeProperties_.end(); i++)
+    nodeProperties_[i->first] = i->second->clone();
+  for (map<string, Clonable *>::iterator i = node.branchProperties_.begin(); i != node.branchProperties_.end(); i++)
+    branchProperties_[i->first] = i->second->clone();
+}
+
+/** Assignation operator: *****************************************************/
+
+Node& Node::operator=(const Node & node)
+{
+  id_               = node.id_;
+  if(name_) delete name_;
+  name_             = node.hasName() ? new string(* node.name_) : 0;
+  //father_           = node.father_;
+  if(distanceToFather_) delete distanceToFather_;
+  distanceToFather_ = node.hasDistanceToFather() ? new double(* node.distanceToFather_) : 0;
+  //sons_             = node.sons_;
+  for(map<string, Clonable *>::iterator i = node.nodeProperties_.begin(); i != node.nodeProperties_.end(); i++)
+  {
+    Clonable * p = nodeProperties_[i->first];
+    if(p) delete p;
+    nodeProperties_[i->first] = i->second->clone();
+  }
+  for(map<string, Clonable *>::iterator i = node.branchProperties_.begin(); i != node.branchProperties_.end(); i++)
+  {
+    Clonable * p = branchProperties_[i->first];
+    if(p) delete p;
+    branchProperties_[i->first] = i->second->clone();
+  }
+  return * this;
+}
+      
+/** Sons: *********************************************************************/
+      
+void Node::swap(size_t branch1, size_t branch2) throw (IndexOutOfBoundsException)
+{
+  if (branch1 > branch2)
+  {
+    size_t tmp = branch1;
+    branch1 = branch2;
+    branch2 = tmp;
+  }
+  Node* node1 = getSon(branch1);
+  Node* node2 = getSon(branch2);
+  removeSon(node1);
+  removeSon(node2);
+  addSon(branch1, node2);
+  addSon(branch2, node1);
+}
+
+vector<const Node *> Node::getNeighbors() const
+{
+  vector<const Node *> neighbors;
+  if(hasFather()) neighbors.push_back(father_);
+  for(size_t i = 0; i < sons_.size(); i++) neighbors.push_back(sons_[i]);
+  return neighbors;
+}
+    
+vector<Node *> Node::getNeighbors()
+{
+  vector<Node *> neighbors;
+  if(hasFather()) neighbors.push_back(father_);
+  for(size_t i = 0; i < sons_.size(); i++) neighbors.push_back(sons_[i]);
+  return neighbors;
+}
+
+size_t Node::getSonPosition(const Node* son) const throw (NodeNotFoundException, NullPointerException)
+{
+  if (!son)
+    throw NullPointerException("Node::getSonPosition(). Empty node given as input.");
+  for(size_t i = 0; i < sons_.size(); i++)
+  {
+    if(sons_[i] == son) return i;
+  }
+  throw NodeNotFoundException("Son not found", TextTools::toString(son->getId()));
+}
+
+bool Node::hasBootstrapValue() const
+{
+  return hasBranchProperty(TreeTools::BOOTSTRAP);
+}
+
+double Node::getBootstrapValue() const throw (PropertyNotFoundException)
+{
+  if(hasBranchProperty(TreeTools::BOOTSTRAP))
+    return dynamic_cast<const Number<double> *>(getBranchProperty(TreeTools::BOOTSTRAP))->getValue();
+  else
+    throw PropertyNotFoundException("", TreeTools::BOOTSTRAP, this);
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Node.h b/src/Bpp/Phyl/Node.h
new file mode 100644
index 0000000..3a2f013
--- /dev/null
+++ b/src/Bpp/Phyl/Node.h
@@ -0,0 +1,697 @@
+//
+// File: Node.h
+// Created by: Julien Dutheil
+// Created on: Thu Mar 13 12:03:18 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _NODE_H_
+#define _NODE_H_
+
+#include "TreeExceptions.h"
+
+#include <Bpp/Clonable.h>
+#include <Bpp/Utils/MapTools.h>
+#include <Bpp/BppString.h>
+#include <Bpp/Numeric/Number.h>
+
+// From the STL:
+#include <string>
+#include <vector>
+#include <map>
+#include <iostream>
+#include <algorithm>
+
+namespace bpp
+{
+/**
+ * @brief The phylogenetic node class.
+ *
+ * This class is for use with the TreeTemplate class, an implementation of the Tree interface.
+ * TreeTemplates are made made of nodes, instances of this class.
+ * Since trees are oriented (rooted), each node has one <i>father node</i> and possibly
+ * many <i>son nodes</i>. Leaves are nodes without descendant and root is defined has the without
+ * father. Inner nodes will generally contain two descendants (the tree is then called
+ * <i>bifurcating</i>), but mutlifurcating trees are also allowed with this kind of description.
+ * In the rooted case, each inner node also defines a <i>subtree</i>.
+ * This allows to work recursively on trees, which is very convenient in most cases.</p>
+ *
+ * This class is made the more general as possible, while keeping it very simple. It contains:</p>
+ * - An identity tag, to identity it in the tree;
+ * - A name, necessary for leaf nodes, optionnal else;
+ * - A pointer toward the father node;
+ * - A std::vector of pointer toward son nodes;
+ * - The distance from the father node:
+ * - A property map, that may contain any information to link to each node, e.g. bootstrap
+ * value or GC content.
+ *
+ * Methods are provided to help the building of trees from scratch.
+ * Trees are more easily built from root to leaves:
+ * The addSon(Node) method adds a node to the list of direct descendants of a
+ * given node. The son node will also have its father set to the current node.
+ * It is also possible to build a tree starting from the leaves using the setFather method.
+ * Changing the parent node will automatically append the current node to the son nodes of the new father.
+ *
+ * @see Tree, TreeTemplate
+ */
+class Node
+{
+
+protected:
+  int id_;
+  std::string* name_;
+  std::vector<Node*> sons_;
+  Node* father_;
+  double* distanceToFather_;
+  mutable std::map<std::string, Clonable*> nodeProperties_;
+  mutable std::map<std::string, Clonable*> branchProperties_;
+
+public:
+  /**
+   * @brief Build a new void Node object.
+   */
+  Node() :
+    id_(0),
+    name_(0),
+    sons_(),
+    father_(0),
+    distanceToFather_(0),
+    nodeProperties_(),
+    branchProperties_()
+  {}
+
+  /**
+   * @brief Build a new Node with specified id.
+   */
+  Node(int id) :
+    id_(id),
+    name_(0),
+    sons_(),
+    father_(0),
+    distanceToFather_(0),
+    nodeProperties_(),
+    branchProperties_()
+  {}
+
+  /**
+   * @brief Build a new Node with specified name.
+   */
+  Node(const std::string& name) :
+    id_(0),
+    name_(new std::string(name)),
+    sons_(),
+    father_(0),
+    distanceToFather_(0),
+    nodeProperties_(),
+    branchProperties_()
+  {}
+
+  /**
+   * @brief Build a new Node with specified id and name.
+   */
+  Node(int id, const std::string& name) :
+    id_(id),
+    name_(new std::string(name)),
+    sons_(),
+    father_(0),
+    distanceToFather_(0),
+    nodeProperties_(),
+    branchProperties_()
+  {}
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @warning This constructor copies all fields, excepted father and son node pointers.
+   *
+   * @param node The node to copy.
+   */
+  Node(const Node& node);
+
+  /**
+   * @brief Assignation operator.
+   *
+   * @warning This operator copies all fields, excepted father and son node pointers.
+   *
+   * @param node the node to copy.
+   * @return A reference toward this node.
+   */
+  Node& operator=(const Node& node);
+
+  Node* clone() const { return new Node(*this); }
+
+public:
+  virtual ~Node()
+  {
+    if (name_) delete name_;
+    if (distanceToFather_) delete distanceToFather_;
+    for (std::map<std::string, Clonable*>::iterator i = nodeProperties_.begin(); i != nodeProperties_.end(); i++)
+    {
+      delete i->second;
+    }
+    for (std::map<std::string, Clonable*>::iterator i = branchProperties_.begin(); i != branchProperties_.end(); i++)
+    {
+      delete i->second;
+    }
+  }
+
+public:
+  /**
+   * @name Identity
+   *
+   * @{
+   */
+
+  /**
+   * @brief Get the node's id.
+   *
+   * @return The identity tag of this node.
+   */
+  virtual int getId() const { return id_; }
+
+  /**
+   * @brief Set this node's id.
+   *
+   * @param id The new identity tag.
+   */
+  virtual void setId(int id) { id_ = id; }
+
+  virtual std::vector<int> getSonsId() const
+  {
+    std::vector<int> sonsId(sons_.size());
+    for (size_t i = 0; i < sons_.size(); i++)
+    {
+      sonsId[i] = sons_[i]->getId();
+    }
+    return sonsId;
+  }
+
+  /** @} */
+
+  /**
+   * @name Name:
+   *
+   * @{
+   */
+
+  /**
+   * @brief Get the name associated to this node, if there is one,
+   * otherwise throw a NodeException.
+   *
+   * @return The name associated to this node.
+   */
+  virtual std::string getName() const throw (NodePException)
+  {
+    if (!hasName()) throw NodePException("Node::getName: no name associated to this node.", this);
+    return *name_;
+  }
+
+  /**
+   * @brief Give a name or update the name associated to the node.
+   *
+   * @param name The name to give to the node.
+   */
+  virtual void setName(const std::string& name)
+  {
+    if (name_) delete name_;
+    name_ = new std::string(name);
+  }
+
+  /**
+   * @brief Delete the name associated to this node (do nothing if there is no name).
+   */
+  virtual void deleteName()
+  {
+    if (name_) delete name_;
+    name_ = 0;
+  }
+
+  /**
+   * @brief Tell is this node has a name.
+   *
+   * @return True if name != 0.
+   */
+  virtual bool hasName() const { return name_ != 0; }
+
+  /** @} */
+
+  /**
+   * @name Distances:
+   *
+   * @{
+   */
+
+  /**
+   * @brief Get the distance to the father node is there is one,
+   * otherwise throw a NodeException.
+   *
+   * @return The distance to the father node.
+   */
+  virtual double getDistanceToFather() const
+  {
+    if (!hasDistanceToFather())
+      throw NodePException("Node::getDistanceToFather: Node has no distance.", this);
+    return *distanceToFather_;
+  }
+
+  /**
+   * @brief Set or update the distance toward the father node.
+   *
+   * Warning: a distance to the father node may be set even if no father node is specified.
+   * This is used by several tree reconstruction methods.
+   * It may also be useful for manipulating subtrees.
+   *
+   * @param distance The new distance to the father node.
+   */
+  virtual void setDistanceToFather(double distance)
+  {
+    if (distanceToFather_)
+      delete distanceToFather_;
+    distanceToFather_ = new double(distance);
+  }
+
+  /**
+   * @brief Delete the distance to the father node.
+   */
+  virtual void deleteDistanceToFather()
+  {
+    if (distanceToFather_)
+      delete distanceToFather_;
+    distanceToFather_ = 0;
+  }
+
+  /**
+   * @brief Tell is this node has a distance to the father.
+   *
+   * @return True if distanceToFather != 0.
+   */
+  virtual bool hasDistanceToFather() const
+  {
+    return distanceToFather_ != 0;
+  }
+
+  /** @} */
+
+  /**
+   * @name Father:
+   *
+   * @{
+   */
+
+  /**
+   * @brief Get the father of this node is there is one.
+   *
+   * @return A pointer toward the father node, 0 if there is not.
+   */
+  virtual const Node* getFather() const { return father_; }
+
+  /**
+   * @brief Get the father of this node is there is one.
+   *
+   * @return A pointer toward the father node, 0 if there is not.
+   */
+  virtual Node* getFather() { return father_; }
+
+  virtual int getFatherId() const { return father_->getId(); }
+
+  /**
+   * @brief Set the father node of this node.
+   *
+   * @param node The father node.
+   */
+  virtual void setFather(Node* node) throw (NullPointerException)
+  {
+    if (!node)
+      throw NullPointerException("Node::setFather(). Empty node given as input.");
+    father_ = node;
+    if (find(node->sons_.begin(), node->sons_.end(), this) == node->sons_.end())
+      node->sons_.push_back(this);
+    else // Otherwise node is already present.
+      std::cerr << "DEVEL warning: Node::setFather. Son node already registered! No pb here, but could be a bug in your implementation..." << std::endl;
+  }
+
+  /**
+   * @brief Remove the father of this node.
+   */
+  virtual Node* removeFather()
+  {
+    Node* f = father_;
+    father_ = 0;
+    return f;
+  }
+
+  /**
+   * @brief Tell if this node has a father node.
+   */
+  virtual bool hasFather() const { return father_ != 0; }
+
+  /** @} */
+
+  /**
+   * @name Sons:
+   *
+   * @{
+   */
+  virtual size_t getNumberOfSons() const { return sons_.size(); }
+
+  virtual std::vector<Node*>& getSons()
+  {
+    return sons_;
+  }
+
+  virtual const Node* getSon(size_t pos) const throw (IndexOutOfBoundsException)
+  {
+    if (pos >= sons_.size()) throw IndexOutOfBoundsException("Node::getSon().", pos, 0, sons_.size() - 1);
+    return sons_[pos];
+  }
+
+  virtual Node* getSon(size_t pos) throw (IndexOutOfBoundsException)
+  {
+    if (pos >= sons_.size()) throw IndexOutOfBoundsException("Node::getSon().", pos, 0, sons_.size() - 1);
+    return sons_[pos];
+  }
+
+  virtual void addSon(size_t pos, Node* node) throw (NullPointerException, NodePException)
+  {
+    if (!node)
+      throw NullPointerException("Node::addSon(). Empty node given as input.");
+    if (find(sons_.begin(), sons_.end(), node) == sons_.end())
+      sons_.insert(sons_.begin() + pos, node);
+    else // Otherwise node is already present.
+      std::cerr << "DEVEL warning: Node::addSon. Son node already registered! No pb here, but could be a bug in your implementation..." << std::endl;
+
+    node->father_ = this;
+  }
+
+  virtual void addSon(Node* node) throw (NullPointerException, NodePException)
+  {
+    if (!node)
+      throw NullPointerException("Node::addSon(). Empty node given as input.");
+    if (find(sons_.begin(), sons_.end(), node) == sons_.end())
+      sons_.push_back(node);
+    else // Otherwise node is already present.
+      throw NodePException("Node::addSon. Trying to add a node which is already present.");
+    node->father_ = this;
+  }
+
+  virtual void setSon(size_t pos, Node* node) throw (IndexOutOfBoundsException, NullPointerException, NodePException)
+  {
+    if (!node)
+      throw NullPointerException("Node::setSon(). Empty node given as input.");
+    if (pos >= sons_.size())
+      throw IndexOutOfBoundsException("Node::setSon(). Invalid node position.", pos, 0, sons_.size() - 1);
+    std::vector<Node*>::iterator search = find(sons_.begin(), sons_.end(), node);
+    if (search == sons_.end() || search == sons_.begin() + pos)
+      sons_[pos] = node;
+    else
+      throw NodePException("Node::setSon. Trying to set a node which is already present.");
+    node->father_ = this;
+  }
+
+  virtual Node* removeSon(size_t pos) throw (IndexOutOfBoundsException)
+  {
+    if (pos >= sons_.size())
+      throw IndexOutOfBoundsException("Node::removeSon(). Invalid node position.", pos, 0, sons_.size() - 1);
+    Node* node = sons_[pos];
+    sons_.erase(sons_.begin() + pos);
+    node->removeFather();
+    return node;
+  }
+
+  virtual void removeSon(Node* node) throw (NodeNotFoundException, NullPointerException)
+  {
+    if (!node)
+      throw NullPointerException("Node::removeSon(). Empty node given as input.");
+    for (size_t i = 0; i < sons_.size(); i++)
+    {
+      if (sons_[i] == node)
+      {
+        sons_.erase(sons_.begin() + i);
+        node->removeFather();
+        return;
+      }
+    }
+    throw NodeNotFoundException("Node::removeSon.", node->getId());
+  }
+
+  virtual void removeSons()
+  {
+    while (sons_.size() != 0)
+      removeSon(static_cast<size_t>(0));
+  }
+
+  virtual void swap(size_t branch1, size_t branch2) throw (IndexOutOfBoundsException);
+
+  virtual size_t getSonPosition(const Node* son) const throw (NodeNotFoundException, NullPointerException);
+
+  /** @} */
+
+  // These functions must not be declared as virtual!!
+
+  std::vector<const Node*> getNeighbors() const;
+
+  std::vector<Node*> getNeighbors();
+
+  virtual size_t degree() const { return getNumberOfSons() + (hasFather() ? 1 : 0); }
+
+  /**
+   * @name Operators:
+   *
+   * - a positive value send the corresponding son;
+   * - a negative value send the father.
+   *
+   * @{
+   */
+  Node* operator[](int i) { return (i < 0) ? father_ : sons_[i]; }
+
+  const Node* operator[](int i) const { return (i < 0) ? father_ : sons_[i]; }
+
+  /** @} */
+
+  /**
+   * @name Node properties:
+   *
+   * @{
+   */
+
+  /**
+   * @brief Set/add a node property.
+   *
+   * If no property with the same name is found, the new property will be added to the list.
+   * Conversely, the property will be deleted and replaced by the new one.
+   * If you want to keep a copy of the old property, consider using the removeNodeProperty function before.
+   *
+   * @param name The name of the property to set.
+   * @param property The property object (will be cloned).
+   */
+  virtual void setNodeProperty(const std::string& name, const Clonable& property)
+  {
+    if (hasNodeProperty(name))
+      delete nodeProperties_[name];
+    nodeProperties_[name] = property.clone();
+  }
+
+  virtual Clonable* getNodeProperty(const std::string& name) throw (PropertyNotFoundException)
+  {
+    if (hasNodeProperty(name))
+      return nodeProperties_[name];
+    else
+      throw PropertyNotFoundException("", name, this);
+  }
+
+  virtual const Clonable* getNodeProperty(const std::string& name) const throw (PropertyNotFoundException)
+  {
+    if (hasNodeProperty(name))
+      return const_cast<const Clonable*>(nodeProperties_[name]);
+    else
+      throw PropertyNotFoundException("", name, this);
+  }
+
+  virtual Clonable* removeNodeProperty(const std::string& name) throw (PropertyNotFoundException)
+  {
+    if (hasNodeProperty(name))
+    {
+      Clonable* removed = nodeProperties_[name];
+      nodeProperties_.erase(name);
+      return removed;
+    }
+    else
+      throw PropertyNotFoundException("", name, this);
+  }
+
+  virtual void deleteNodeProperty(const std::string& name) throw (PropertyNotFoundException)
+  {
+    if (hasNodeProperty(name))
+    {
+      delete nodeProperties_[name];
+      nodeProperties_.erase(name);
+    }
+    else
+      throw PropertyNotFoundException("", name, this);
+  }
+
+  /**
+   * @brief Remove all node properties.
+   *
+   * Attached objects will not be deleted.
+   */
+  virtual void removeNodeProperties()
+  {
+    nodeProperties_.clear();
+  }
+
+  /**
+   * @brief Delete all node properties.
+   */
+  virtual void deleteNodeProperties()
+  {
+    for (std::map<std::string, Clonable*>::iterator i = nodeProperties_.begin(); i != nodeProperties_.end(); i++)
+    {
+      delete i->second;
+    }
+    nodeProperties_.clear();
+  }
+
+  virtual bool hasNodeProperty(const std::string& name) const { return nodeProperties_.find(name) != nodeProperties_.end(); }
+
+  virtual std::vector<std::string> getNodePropertyNames() const { return MapTools::getKeys(nodeProperties_); }
+
+  /** @} */
+
+  /**
+   * @name Branch properties:
+   *
+   * @{
+   */
+
+  /**
+   * @brief Set/add a branch property.
+   *
+   * If no property with the same name is found, the new property will be added to the list.
+   * Conversely, the property will be deleted and replaced by the new one.
+   * If you want to keep a copy of the old property, consider using the removeBranchProperty function before.
+   *
+   * @param name The name of the property to set.
+   * @param property The property object (will be cloned).
+   */
+  virtual void setBranchProperty(const std::string& name, const Clonable& property)
+  {
+    if (hasBranchProperty(name))
+      delete branchProperties_[name];
+    branchProperties_[name] = property.clone();
+  }
+
+  virtual Clonable* getBranchProperty(const std::string& name) throw (PropertyNotFoundException)
+  {
+    if (hasBranchProperty(name))
+      return branchProperties_[name];
+    else
+      throw PropertyNotFoundException("", name, this);
+  }
+
+  virtual const Clonable* getBranchProperty(const std::string& name) const throw (PropertyNotFoundException)
+  {
+    if (hasBranchProperty(name))
+      return const_cast<const Clonable*>(branchProperties_[name]);
+    else
+      throw PropertyNotFoundException("", name, this);
+  }
+
+  virtual Clonable* removeBranchProperty(const std::string& name) throw (PropertyNotFoundException)
+  {
+    if (hasBranchProperty(name))
+    {
+      Clonable* removed = branchProperties_[name];
+      branchProperties_.erase(name);
+      return removed;
+    }
+    else
+      throw PropertyNotFoundException("", name, this);
+  }
+
+  virtual void deleteBranchProperty(const std::string& name) throw (PropertyNotFoundException)
+  {
+    if (hasBranchProperty(name))
+    {
+      delete branchProperties_[name];
+      branchProperties_.erase(name);
+    }
+    else
+      throw PropertyNotFoundException("", name, this);
+  }
+
+  /**
+   * @brief Remove all branch properties.
+   *
+   * Attached objects will not be deleted.
+   */
+  virtual void removeBranchProperties()
+  {
+    branchProperties_.clear();
+  }
+
+  /**
+   * @brief Delete all branch properties.
+   */
+  virtual void deleteBranchProperties()
+  {
+    for (std::map<std::string, Clonable*>::iterator i = branchProperties_.begin(); i != branchProperties_.end(); i++)
+    {
+      delete i->second;
+    }
+    branchProperties_.clear();
+  }
+
+  virtual bool hasBranchProperty(const std::string& name) const { return branchProperties_.find(name) != branchProperties_.end(); }
+
+  virtual std::vector<std::string> getBranchPropertyNames() const { return MapTools::getKeys(branchProperties_); }
+
+  virtual bool hasBootstrapValue() const;
+
+  virtual double getBootstrapValue() const throw (PropertyNotFoundException);
+  /** @} */
+  // Equality operator:
+
+  virtual bool operator==(const Node& node) const { return id_ == node.id_; }
+
+  // Tests:
+
+  virtual bool isLeaf() const { return degree() <= 1; }
+
+};
+} // end of namespace bpp.
+
+#endif  // _NODE_H_
+
diff --git a/src/Bpp/Phyl/NodeTemplate.h b/src/Bpp/Phyl/NodeTemplate.h
new file mode 100755
index 0000000..cdd1fa6
--- /dev/null
+++ b/src/Bpp/Phyl/NodeTemplate.h
@@ -0,0 +1,198 @@
+//
+// File: NodeTemplate.h
+// Created by: Vincent Ranwez
+//             Julien Dutheil
+// Created on: Thu Jun 28 18:11 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _NODETEMPLATE_H_
+#define _NODETEMPLATE_H_
+
+#include "Node.h"
+
+namespace bpp
+{
+
+/**
+ * @brief The NodeTemplate class.
+ *
+ * This class inherits from the Node class.
+ * Its is a generic way to store any information to a node.
+ * A NodeTemplate only add the setInfos and getInfos methods,
+ * which set and retrieve a NodeInfo, whose type is given as a template
+ * of the class.
+ * This class is mainly for computation conveniency, one may define a NodeInfo
+ * class with several results attached.
+ * An example is provided in the PGMA class.
+ * Another way is to use a map<Node *, NodeInfos>, with the limitation of the
+ * map access.
+ * One may also wish to use the property system of the Node class, but
+ * properties are stored as in a map<string, Clonable *>, with the drawbacks
+ * of the slow map access and the systematic use of dynamic_cast<NodeInfo *> to
+ * convert from Clonable *.
+ *
+ * This class redefines all constructors and access methods (get*) with return
+ * types as NodeTemplate and not Node (using covariant returns).
+ *
+ * @see Node, TreeTemplate
+ */
+template<class NodeInfos>
+class NodeTemplate :
+  public Node
+{
+  friend class TreeTemplateTools;
+
+	private:
+
+		NodeInfos infos_;
+
+	public:
+		
+		/**	
+		 * @brief Build a new void NodeTemplate object.
+		 */
+		NodeTemplate() : Node(), infos_() {}
+			
+		/**
+		 * @brief Build a new NodeTemplate with specified id.
+		 */
+		NodeTemplate(int id) : Node(id), infos_() {}
+
+		/**
+		 * @brief Build a new NodeTemplate with specified name.
+		 */
+		NodeTemplate(const std::string& name) : Node(name), infos_() {}
+
+		/**
+		 * @brief Build a new NodeTemplate with specified id and name.
+		 */
+		NodeTemplate(int id, const std::string& name) : Node(id, name), infos_() {}
+
+  protected:
+		/**
+		 * @brief Copy constructor.
+		 * 
+		 * @param node The node to copy.
+		 */
+		NodeTemplate(const Node& node) : Node(node), infos_() {}
+
+    /**
+		 * @brief Copy constructor.
+		 * 
+		 * @param node The node to copy.
+		 */
+		NodeTemplate(const NodeTemplate<NodeInfos>& node):
+      Node(node), infos_(node.infos_)
+    {}
+
+		/**
+		 * @brief Assignation operator.
+		 *
+		 * @param node the node to copy.
+		 * @return A reference toward this node.
+		 */
+		NodeTemplate<NodeInfos>& operator=(const NodeTemplate<NodeInfos>& node)
+		{
+      Node::operator=(node);
+			infos_ = node.infos_;
+			return *this;
+		}
+
+    NodeTemplate<NodeInfos>* clone() const { return new NodeTemplate<NodeInfos>(*this); }
+
+  public:
+		virtual ~NodeTemplate() {}
+
+  public:
+
+		const NodeTemplate<NodeInfos>* getFather() const { return dynamic_cast<const NodeTemplate<NodeInfos> *>(father_); }
+ 
+		NodeTemplate<NodeInfos>* getFather() { return dynamic_cast<NodeTemplate<NodeInfos> *>(father_); }
+				
+		NodeTemplate<NodeInfos>* removeFather() { NodeTemplate<NodeInfos>* f = dynamic_cast<NodeTemplate<NodeInfos> *>(father_); father_ = 0; return f; }
+
+		const NodeTemplate<NodeInfos>* getSon(size_t i) const throw (IndexOutOfBoundsException) { return dynamic_cast<NodeTemplate<NodeInfos> *>(sons_[i]); }
+				
+		NodeTemplate<NodeInfos>* getSon(size_t i) throw (IndexOutOfBoundsException) { return dynamic_cast<NodeTemplate<NodeInfos> *>(sons_[i]); }
+				
+    std::vector<const NodeTemplate<NodeInfos>*> getNeighbors() const
+		{
+      std::vector<const Node*> neighbors = Node::getNeighbors();
+      std::vector<const NodeTemplate<NodeInfos>*> neighbors2(neighbors.size());
+			for (size_t i = 0; i < neighbors.size(); i++)
+				neighbors2[i] = dynamic_cast<const NodeTemplate<NodeInfos>*>(neighbors[i]);
+			return neighbors2;
+		}
+		
+    std::vector<NodeTemplate<NodeInfos>*> getNeighbors()
+		{
+      std::vector<Node*> neighbors = Node::getNeighbors();
+      std::vector<NodeTemplate<NodeInfos>*> neighbors2(neighbors.size());
+			for (size_t i = 0; i < neighbors.size(); i++)
+				neighbors2[i] = dynamic_cast<NodeTemplate<NodeInfos>*>(neighbors[i]);
+			return neighbors2;
+		}
+		
+		NodeTemplate<NodeInfos>* operator[](int i) { return dynamic_cast<NodeTemplate<NodeInfos>*>((i < 0) ? father_ : sons_[i]); }
+				
+		const NodeTemplate<NodeInfos>* operator[](int i) const { return dynamic_cast<const NodeTemplate<NodeInfos> *>((i < 0) ? father_ : sons_[i]); }
+
+
+		// Specific methods:
+
+    /**
+     * @return A reference toward the information object associated to this node.
+     */
+		virtual const NodeInfos& getInfos() const { return infos_; }
+		
+    /**
+     * @return A reference toward the information object associated to this node.
+     */
+		virtual NodeInfos& getInfos() { return infos_; }
+
+    /**
+     * @brief Set the information to be associated to this node.
+     * 
+     * @param infos An information object.
+     */
+		virtual void setInfos(const NodeInfos& infos) { infos_ = infos; }
+
+};
+
+} //end of namespace bpp.
+
+#endif	//_NODETEMPLATE_H_
+
diff --git a/src/Bpp/Phyl/OptimizationTools.cpp b/src/Bpp/Phyl/OptimizationTools.cpp
new file mode 100644
index 0000000..5a7e39c
--- /dev/null
+++ b/src/Bpp/Phyl/OptimizationTools.cpp
@@ -0,0 +1,766 @@
+//
+// File: OptimizationTools.cpp
+// Created by: Julien Dutheil
+// Created on: Sun Dec 14 09:43:32 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "OptimizationTools.h"
+#include "Likelihood/PseudoNewtonOptimizer.h"
+#include "Likelihood/GlobalClockTreeLikelihoodFunctionWrapper.h"
+#include "NNISearchable.h"
+#include "NNITopologySearch.h"
+#include "Io/Newick.h"
+
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Numeric/ParameterList.h>
+#include <Bpp/Numeric/Function/BfgsMultiDimensions.h>
+#include <Bpp/Numeric/Function/ReparametrizationFunctionWrapper.h>
+#include <Bpp/Numeric/Function/ThreePointsNumericalDerivative.h>
+#include <Bpp/Numeric/Function/ConjugateGradientMultiDimensions.h>
+#include <Bpp/Numeric/Function/TwoPointsNumericalDerivative.h>
+#include <Bpp/Numeric/Function/DownhillSimplexMethod.h>
+
+// From bpp-seq:
+#include <Bpp/Seq/Io/Fasta.h>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+OptimizationTools::OptimizationTools() {}
+
+OptimizationTools::~OptimizationTools() {}
+
+/******************************************************************************/
+
+std::string OptimizationTools::OPTIMIZATION_NEWTON = "newton";
+std::string OptimizationTools::OPTIMIZATION_GRADIENT = "gradient";
+std::string OptimizationTools::OPTIMIZATION_BRENT = "Brent";
+std::string OptimizationTools::OPTIMIZATION_BFGS = "BFGS";
+
+/******************************************************************************/
+
+OptimizationTools::ScaleFunction::ScaleFunction(TreeLikelihood* tl) :
+  tl_(tl),
+  brLen_(),
+  lambda_()
+{
+  // We work only on the branch lengths:
+  brLen_ = tl->getBranchLengthsParameters();
+  if (brLen_.hasParameter("RootPosition"))
+    brLen_.deleteParameter("RootPosition");
+  lambda_.addParameter(Parameter("scale factor", 0));
+}
+
+OptimizationTools::ScaleFunction::~ScaleFunction() {}
+
+void OptimizationTools::ScaleFunction::setParameters(const ParameterList& lambda)
+throw (ParameterNotFoundException, ConstraintException)
+{
+  if (lambda.size() != 1)
+    throw Exception("OptimizationTools::ScaleFunction::f(). This is a one parameter function!");
+  lambda_.setParametersValues(lambda);
+}
+
+double OptimizationTools::ScaleFunction::getValue() const
+throw (ParameterException)
+{
+  // Scale the tree:
+  ParameterList brLen = brLen_;
+  double s = exp(lambda_[0].getValue());
+  for (unsigned int i = 0; i < brLen.size(); i++)
+  {
+    try
+    {
+      brLen[i].setValue(brLen[i].getValue() * s);
+    }
+    catch (ConstraintException& cex)
+    {
+      // Do nothing. Branch value is already at bound...
+    }
+  }
+  return tl_->f(brLen);
+}
+
+/******************************************************************************/
+
+unsigned int OptimizationTools::optimizeTreeScale(
+  TreeLikelihood* tl,
+  double tolerance,
+  int tlEvalMax,
+  OutputStream* messageHandler,
+  OutputStream* profiler,
+  unsigned int verbose)
+throw (Exception)
+{
+  ScaleFunction sf(tl);
+  BrentOneDimension bod(&sf);
+  bod.setMessageHandler(messageHandler);
+  bod.setProfiler(profiler);
+  ParameterList singleParameter;
+  singleParameter.addParameter(Parameter("scale factor", 0));
+  bod.setInitialInterval(-0.5, 0.5);
+  bod.init(singleParameter);
+  ParametersStopCondition PS(&bod, tolerance);
+  bod.setStopCondition(PS);
+  bod.setMaximumNumberOfEvaluations(tlEvalMax);
+  bod.optimize();
+  ApplicationTools::displayTaskDone();
+  if (verbose > 0)
+    ApplicationTools::displayResult("Tree scaled by", exp(sf.getParameters()[0].getValue()));
+  return bod.getNumberOfEvaluations();
+}
+
+/******************************************************************************/
+
+unsigned int OptimizationTools::optimizeNumericalParameters(
+  DiscreteRatesAcrossSitesTreeLikelihood* tl,
+  const ParameterList& parameters,
+  OptimizationListener* listener,
+  unsigned int nstep,
+  double tolerance,
+  unsigned int tlEvalMax,
+  OutputStream* messageHandler,
+  OutputStream* profiler,
+  bool reparametrization,
+  unsigned int verbose,
+  const std::string& optMethodDeriv,
+  const std::string& optMethodModel)
+throw (Exception)
+{
+  DerivableSecondOrder* f = tl;
+  ParameterList pl = parameters;
+
+  // Shall we reparametrize the function to remove constraints?
+  auto_ptr<DerivableSecondOrder> frep;
+  if (reparametrization)
+  {
+    frep.reset(new ReparametrizationDerivableSecondOrderWrapper(f, parameters));
+    f = frep.get();
+
+    // Reset parameters to remove constraints:
+    pl = f->getParameters().subList(parameters.getParameterNames());
+  }
+
+  // ///////////////
+  // Build optimizer:
+
+  // Branch lengths
+
+  MetaOptimizerInfos* desc = new MetaOptimizerInfos();
+  MetaOptimizer* poptimizer = 0;
+  AbstractNumericalDerivative* fnum = new ThreePointsNumericalDerivative(f);
+
+  if (optMethodDeriv == OPTIMIZATION_GRADIENT)
+    desc->addOptimizer("Branch length parameters", new ConjugateGradientMultiDimensions(f), tl->getBranchLengthsParameters().getParameterNames(), 2, MetaOptimizerInfos::IT_TYPE_FULL);
+  else if (optMethodDeriv == OPTIMIZATION_NEWTON)
+    desc->addOptimizer("Branch length parameters", new PseudoNewtonOptimizer(f), tl->getBranchLengthsParameters().getParameterNames(), 2, MetaOptimizerInfos::IT_TYPE_FULL);
+  else if (optMethodDeriv == OPTIMIZATION_BFGS)
+    desc->addOptimizer("Branch length parameters", new BfgsMultiDimensions(f), tl->getBranchLengthsParameters().getParameterNames(), 2, MetaOptimizerInfos::IT_TYPE_FULL);
+  else
+    throw Exception("OptimizationTools::optimizeNumericalParameters. Unknown optimization method: " + optMethodDeriv);
+
+  // Other parameters
+
+  if (optMethodModel == OPTIMIZATION_BRENT)
+  {
+    ParameterList plsm = parameters.getCommonParametersWith(tl->getSubstitutionModelParameters());
+    desc->addOptimizer("Substitution model parameter", new SimpleMultiDimensions(f), plsm.getParameterNames(), 0, MetaOptimizerInfos::IT_TYPE_STEP);
+
+
+    ParameterList plrd = parameters.getCommonParametersWith(tl->getRateDistributionParameters());
+    desc->addOptimizer("Rate distribution parameter", new SimpleMultiDimensions(f), plrd.getParameterNames(), 0, MetaOptimizerInfos::IT_TYPE_STEP);
+    poptimizer = new MetaOptimizer(f, desc, nstep);
+  }
+  else if (optMethodModel == OPTIMIZATION_BFGS)
+  {
+    vector<string> vNameDer;
+
+    ParameterList plsm = parameters.getCommonParametersWith(tl->getSubstitutionModelParameters());
+    vNameDer = plsm.getParameterNames();
+
+    ParameterList plrd = parameters.getCommonParametersWith(tl->getRateDistributionParameters());
+
+    vector<string> vNameDer2 = plrd.getParameterNames();
+
+    vNameDer.insert(vNameDer.begin(), vNameDer2.begin(), vNameDer2.end());
+    fnum->setParametersToDerivate(vNameDer);
+
+    desc->addOptimizer("Rate & model distribution parameters", new BfgsMultiDimensions(fnum), vNameDer, 1, MetaOptimizerInfos::IT_TYPE_FULL);
+    poptimizer = new MetaOptimizer(fnum, desc, nstep);
+  }
+  else
+    throw Exception("OptimizationTools::optimizeNumericalParameters. Unknown optimization method: " + optMethodModel);
+
+  poptimizer->setVerbose(verbose);
+  poptimizer->setProfiler(profiler);
+  poptimizer->setMessageHandler(messageHandler);
+  poptimizer->setMaximumNumberOfEvaluations(tlEvalMax);
+  poptimizer->getStopCondition()->setTolerance(tolerance);
+
+  // Optimize TreeLikelihood function:
+  poptimizer->setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO);
+  NaNListener* nanListener = new NaNListener(poptimizer, tl);
+  poptimizer->addOptimizationListener(nanListener);
+  if (listener)
+    poptimizer->addOptimizationListener(listener);
+  poptimizer->init(pl);
+  poptimizer->optimize();
+
+  if (verbose > 0)
+    ApplicationTools::displayMessage("\n");
+
+  // We're done.
+  int nb = poptimizer->getNumberOfEvaluations();
+  delete poptimizer;
+  return nb;
+}
+
+/******************************************************************************/
+
+unsigned int OptimizationTools::optimizeNumericalParameters2(
+  DiscreteRatesAcrossSitesTreeLikelihood* tl,
+  const ParameterList& parameters,
+  OptimizationListener* listener,
+  double tolerance,
+  unsigned int tlEvalMax,
+  OutputStream* messageHandler,
+  OutputStream* profiler,
+  bool reparametrization,
+  bool useClock,
+  unsigned int verbose,
+  const std::string& optMethodDeriv)
+throw (Exception)
+{
+  DerivableSecondOrder* f = tl;
+  ParameterList pl = parameters;
+  // Shall we use a molecular clock constraint on branch lengths?
+  auto_ptr<GlobalClockTreeLikelihoodFunctionWrapper> fclock;
+  if (useClock)
+  {
+    fclock.reset(new GlobalClockTreeLikelihoodFunctionWrapper(tl));
+    f = fclock.get();
+    if (verbose > 0)
+      ApplicationTools::displayResult("Log-likelihood after adding clock", -tl->getLogLikelihood()); 
+    
+    // Reset parameters to use new branch lengths. WARNING! 'old' branch parameters do not exist anymore and have been replaced by heights
+    pl = fclock->getParameters().getCommonParametersWith(parameters);
+    pl.addParameters(fclock->getHeightParameters());
+  }
+  // Shall we reparametrize the function to remove constraints?
+  auto_ptr<DerivableSecondOrder> frep;
+  if (reparametrization)
+  {
+    frep.reset(new ReparametrizationDerivableSecondOrderWrapper(f, pl));
+    f = frep.get();
+
+    // Reset parameters to remove constraints:
+    pl = f->getParameters().subList(pl.getParameterNames());
+  }
+
+  auto_ptr<AbstractNumericalDerivative> fnum;
+  // Build optimizer:
+  auto_ptr<Optimizer> optimizer;
+  if (optMethodDeriv == OPTIMIZATION_GRADIENT)
+  {
+    fnum.reset(new TwoPointsNumericalDerivative(f));
+    fnum->setInterval(0.0000001);
+    optimizer.reset(new ConjugateGradientMultiDimensions(reinterpret_cast<DerivableFirstOrder*>(fnum.get()))); // Removes strict-aliasing warning with gcc 4.4
+  }
+  else if (optMethodDeriv == OPTIMIZATION_NEWTON)
+  {
+    fnum.reset(new ThreePointsNumericalDerivative(f));
+    fnum->setInterval(0.0001);
+    optimizer.reset(new PseudoNewtonOptimizer(fnum.get()));
+  }
+  else if (optMethodDeriv == OPTIMIZATION_BFGS)
+  {
+    fnum.reset(new TwoPointsNumericalDerivative(f));
+    fnum->setInterval(0.0001);
+    optimizer.reset(new BfgsMultiDimensions(fnum.get()));
+  }
+  else
+    throw Exception("OptimizationTools::optimizeNumericalParameters2. Unknown optimization method: " + optMethodDeriv);
+
+  // Numerical derivatives:
+  ParameterList tmp = tl->getNonDerivableParameters(); 
+  if (useClock)
+    tmp.addParameters(fclock->getHeightParameters());
+  fnum->setParametersToDerivate(tmp.getParameterNames());
+  optimizer->setVerbose(verbose);
+  optimizer->setProfiler(profiler);
+  optimizer->setMessageHandler(messageHandler);
+  optimizer->setMaximumNumberOfEvaluations(tlEvalMax);
+  optimizer->getStopCondition()->setTolerance(tolerance);
+
+  // Optimize TreeLikelihood function:
+  optimizer->setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO);
+  NaNListener* nanListener = new NaNListener(optimizer.get(), tl);
+  optimizer->addOptimizationListener(nanListener);
+  if (listener)
+    optimizer->addOptimizationListener(listener);
+  optimizer->init(pl);
+  optimizer->optimize();
+
+  if (verbose > 0)
+    ApplicationTools::displayMessage("\n");
+
+  // We're done.
+  return optimizer->getNumberOfEvaluations();
+}
+
+/******************************************************************************/
+
+unsigned int OptimizationTools::optimizeBranchLengthsParameters(
+  DiscreteRatesAcrossSitesTreeLikelihood* tl,
+  const ParameterList& parameters,
+  OptimizationListener* listener,
+  double tolerance,
+  unsigned int tlEvalMax,
+  OutputStream* messageHandler,
+  OutputStream* profiler,
+  unsigned int verbose,
+  const std::string& optMethodDeriv)
+throw (Exception)
+{
+  // Build optimizer:
+  Optimizer* optimizer = 0;
+  if (optMethodDeriv == OPTIMIZATION_GRADIENT)
+  {
+    tl->enableFirstOrderDerivatives(true);
+    tl->enableSecondOrderDerivatives(false);
+    optimizer = new ConjugateGradientMultiDimensions(tl);
+  }
+  else if (optMethodDeriv == OPTIMIZATION_NEWTON)
+  {
+    tl->enableFirstOrderDerivatives(true);
+    tl->enableSecondOrderDerivatives(true);
+    optimizer = new PseudoNewtonOptimizer(tl);
+  }
+  else if (optMethodDeriv == OPTIMIZATION_BFGS)
+  {
+    tl->enableFirstOrderDerivatives(true);
+    tl->enableSecondOrderDerivatives(false);
+    optimizer = new BfgsMultiDimensions(tl);
+  }
+  else
+    throw Exception("OptimizationTools::optimizeBranchLengthsParameters. Unknown optimization method: " + optMethodDeriv);
+  optimizer->setVerbose(verbose);
+  optimizer->setProfiler(profiler);
+  optimizer->setMessageHandler(messageHandler);
+  optimizer->setMaximumNumberOfEvaluations(tlEvalMax);
+  optimizer->getStopCondition()->setTolerance(tolerance);
+
+  // Optimize TreeLikelihood function:
+  ParameterList pl = parameters.getCommonParametersWith(tl->getBranchLengthsParameters());
+  optimizer->setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO);
+  if (listener)
+    optimizer->addOptimizationListener(listener);
+  optimizer->init(pl);
+  optimizer->optimize();
+  if (verbose > 0)
+    ApplicationTools::displayMessage("\n");
+
+  // We're done.
+  unsigned int n = optimizer->getNumberOfEvaluations();
+  delete optimizer;
+  return n;
+}
+
+/******************************************************************************/
+
+unsigned int OptimizationTools::optimizeNumericalParametersWithGlobalClock(
+  DiscreteRatesAcrossSitesClockTreeLikelihood* cl,
+  const ParameterList& parameters,
+  OptimizationListener* listener,
+  unsigned int nstep,
+  double tolerance,
+  unsigned int tlEvalMax,
+  OutputStream* messageHandler,
+  OutputStream* profiler,
+  unsigned int verbose,
+  const std::string& optMethodDeriv)
+throw (Exception)
+{
+  AbstractNumericalDerivative* fun = 0;
+
+  // Build optimizer:
+  MetaOptimizerInfos* desc = new MetaOptimizerInfos();
+  if (optMethodDeriv == OPTIMIZATION_GRADIENT)
+  {
+    fun = new TwoPointsNumericalDerivative(cl);
+    fun->setInterval(0.0000001);
+    desc->addOptimizer("Branch length parameters", new ConjugateGradientMultiDimensions(fun), cl->getBranchLengthsParameters().getParameterNames(), 2, MetaOptimizerInfos::IT_TYPE_FULL);
+  }
+  else if (optMethodDeriv == OPTIMIZATION_NEWTON)
+  {
+    fun = new ThreePointsNumericalDerivative(cl);
+    fun->setInterval(0.0001);
+    desc->addOptimizer("Branch length parameters", new PseudoNewtonOptimizer(fun), cl->getBranchLengthsParameters().getParameterNames(), 2, MetaOptimizerInfos::IT_TYPE_FULL);
+  }
+  else
+    throw Exception("OptimizationTools::optimizeNumericalParametersWithGlobalClock. Unknown optimization method: " + optMethodDeriv);
+
+  // Numerical derivatives:
+  ParameterList tmp = parameters.getCommonParametersWith(cl->getBranchLengthsParameters());
+  fun->setParametersToDerivate(tmp.getParameterNames());
+
+  ParameterList plsm = parameters.getCommonParametersWith(cl->getSubstitutionModelParameters());
+  if (plsm.size() < 10)
+    desc->addOptimizer("Substitution model parameter", new SimpleMultiDimensions(cl), plsm.getParameterNames(), 0, MetaOptimizerInfos::IT_TYPE_STEP);
+  else
+    desc->addOptimizer("Substitution model parameters", new DownhillSimplexMethod(cl), plsm.getParameterNames(), 0, MetaOptimizerInfos::IT_TYPE_FULL);
+
+  ParameterList plrd = parameters.getCommonParametersWith(cl->getRateDistributionParameters());
+  if (plrd.size() < 10)
+    desc->addOptimizer("Rate distribution parameter", new SimpleMultiDimensions(cl), plrd.getParameterNames(), 0, MetaOptimizerInfos::IT_TYPE_STEP);
+  else
+    desc->addOptimizer("Rate dsitribution parameters", new DownhillSimplexMethod(cl), plrd.getParameterNames(), 0, MetaOptimizerInfos::IT_TYPE_FULL);
+
+  MetaOptimizer optimizer(fun, desc, nstep);
+  optimizer.setVerbose(verbose);
+  optimizer.setProfiler(profiler);
+  optimizer.setMessageHandler(messageHandler);
+  optimizer.setMaximumNumberOfEvaluations(tlEvalMax);
+  optimizer.getStopCondition()->setTolerance(tolerance);
+
+  // Optimize TreeLikelihood function:
+  optimizer.setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO);
+  if (listener)
+    optimizer.addOptimizationListener(listener);
+  optimizer.init(parameters);
+  optimizer.optimize();
+  if (verbose > 0)
+    ApplicationTools::displayMessage("\n");
+
+  // We're done.
+  return optimizer.getNumberOfEvaluations();
+}
+
+/******************************************************************************/
+
+unsigned int OptimizationTools::optimizeNumericalParametersWithGlobalClock2(
+  DiscreteRatesAcrossSitesClockTreeLikelihood* cl,
+  const ParameterList& parameters,
+  OptimizationListener* listener,
+  double tolerance,
+  unsigned int tlEvalMax,
+  OutputStream* messageHandler,
+  OutputStream* profiler,
+  unsigned int verbose,
+  const std::string& optMethodDeriv)
+throw (Exception)
+{
+  AbstractNumericalDerivative* fun = 0;
+
+  // Build optimizer:
+  Optimizer* optimizer = 0;
+  if (optMethodDeriv == OPTIMIZATION_GRADIENT)
+  {
+    fun = new TwoPointsNumericalDerivative(cl);
+    fun->setInterval(0.0000001);
+    optimizer = new ConjugateGradientMultiDimensions(fun);
+  }
+  else if (optMethodDeriv == OPTIMIZATION_NEWTON)
+  {
+    fun = new ThreePointsNumericalDerivative(cl);
+    fun->setInterval(0.0001);
+    optimizer = new PseudoNewtonOptimizer(fun);
+  }
+  else
+    throw Exception("OptimizationTools::optimizeBranchLengthsParameters. Unknown optimization method: " + optMethodDeriv);
+
+  // Numerical derivatives:
+  ParameterList tmp = parameters.getCommonParametersWith(cl->getParameters());
+  fun->setParametersToDerivate(tmp.getParameterNames());
+
+  optimizer->setVerbose(verbose);
+  optimizer->setProfiler(profiler);
+  optimizer->setMessageHandler(messageHandler);
+  optimizer->setMaximumNumberOfEvaluations(tlEvalMax);
+  optimizer->getStopCondition()->setTolerance(tolerance);
+
+  // Optimize TreeLikelihood function:
+  optimizer->setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO);
+  if (listener)
+    optimizer->addOptimizationListener(listener);
+  optimizer->init(parameters);
+  optimizer->optimize();
+  if (verbose > 0)
+    ApplicationTools::displayMessage("\n");
+
+  // We're done.
+  unsigned int n = optimizer->getNumberOfEvaluations();
+  delete optimizer;
+
+  // We're done.
+  return n;
+}
+
+/******************************************************************************/
+
+void NNITopologyListener::topologyChangeSuccessful(const TopologyChangeEvent& event)
+{
+  optimizeCounter_++;
+  if (optimizeCounter_ == optimizeNumerical_)
+  {
+    DiscreteRatesAcrossSitesTreeLikelihood* likelihood = dynamic_cast<DiscreteRatesAcrossSitesTreeLikelihood*>(topoSearch_->getSearchableObject());
+    parameters_.matchParametersValues(likelihood->getParameters());
+    OptimizationTools::optimizeNumericalParameters(likelihood, parameters_, 0, nStep_, tolerance_, 1000000, messenger_, profiler_, reparametrization_, verbose_, optMethod_);
+    optimizeCounter_ = 0;
+  }
+}
+
+/******************************************************************************/
+
+void NNITopologyListener2::topologyChangeSuccessful(const TopologyChangeEvent& event)
+{
+  optimizeCounter_++;
+  if (optimizeCounter_ == optimizeNumerical_)
+  {
+    DiscreteRatesAcrossSitesTreeLikelihood* likelihood = dynamic_cast<DiscreteRatesAcrossSitesTreeLikelihood*>(topoSearch_->getSearchableObject());
+    parameters_.matchParametersValues(likelihood->getParameters());
+    OptimizationTools::optimizeNumericalParameters2(likelihood, parameters_, 0, tolerance_, 1000000, messenger_, profiler_, reparametrization_, false, verbose_, optMethod_);
+    optimizeCounter_ = 0;
+  }
+}
+
+// ******************************************************************************/
+
+NNIHomogeneousTreeLikelihood* OptimizationTools::optimizeTreeNNI(
+  NNIHomogeneousTreeLikelihood* tl,
+  const ParameterList& parameters,
+  bool optimizeNumFirst,
+  double tolBefore,
+  double tolDuring,
+  int tlEvalMax,
+  unsigned int numStep,
+  OutputStream* messageHandler,
+  OutputStream* profiler,
+  bool reparametrization,
+  unsigned int verbose,
+  const std::string& optMethodDeriv,
+  unsigned int nStep,
+  const std::string& nniMethod)
+throw (Exception)
+{
+  // Roughly optimize parameter
+  if (optimizeNumFirst)
+  {
+    OptimizationTools::optimizeNumericalParameters(tl, parameters, NULL, nStep, tolBefore, 1000000, messageHandler, profiler, reparametrization, verbose, optMethodDeriv);
+  }
+  // Begin topo search:
+  NNITopologySearch topoSearch(*tl, nniMethod, verbose > 2 ? verbose - 2 : 0);
+  NNITopologyListener* topoListener = new NNITopologyListener(&topoSearch, parameters, tolDuring, messageHandler, profiler, verbose, optMethodDeriv, nStep, reparametrization);
+  topoListener->setNumericalOptimizationCounter(numStep);
+  topoSearch.addTopologyListener(topoListener);
+  topoSearch.search();
+  return dynamic_cast<NNIHomogeneousTreeLikelihood*>(topoSearch.getSearchableObject());
+}
+
+/******************************************************************************/
+
+NNIHomogeneousTreeLikelihood* OptimizationTools::optimizeTreeNNI2(
+  NNIHomogeneousTreeLikelihood* tl,
+  const ParameterList& parameters,
+  bool optimizeNumFirst,
+  double tolBefore,
+  double tolDuring,
+  int tlEvalMax,
+  unsigned int numStep,
+  OutputStream* messageHandler,
+  OutputStream* profiler,
+  bool reparametrization,
+  unsigned int verbose,
+  const std::string& optMethodDeriv,
+  const std::string& nniMethod)
+throw (Exception)
+{
+  // Roughly optimize parameter
+  if (optimizeNumFirst)
+  {
+    OptimizationTools::optimizeNumericalParameters2(tl, parameters, NULL, tolBefore, 1000000, messageHandler, profiler, reparametrization, false, verbose, optMethodDeriv);
+  }
+  // Begin topo search:
+  NNITopologySearch topoSearch(*tl, nniMethod, verbose > 2 ? verbose - 2 : 0);
+  NNITopologyListener2* topoListener = new NNITopologyListener2(&topoSearch, parameters, tolDuring, messageHandler, profiler, verbose, optMethodDeriv, reparametrization);
+  topoListener->setNumericalOptimizationCounter(numStep);
+  topoSearch.addTopologyListener(topoListener);
+  topoSearch.search();
+  return dynamic_cast<NNIHomogeneousTreeLikelihood*>(topoSearch.getSearchableObject());
+}
+
+/******************************************************************************/
+
+DRTreeParsimonyScore* OptimizationTools::optimizeTreeNNI(
+  DRTreeParsimonyScore* tp,
+  unsigned int verbose)
+{
+  NNISearchable* topo = dynamic_cast<NNISearchable*>(tp);
+  NNITopologySearch topoSearch(*topo, NNITopologySearch::PHYML, verbose);
+  topoSearch.search();
+  return dynamic_cast<DRTreeParsimonyScore*>(topoSearch.getSearchableObject());
+}
+
+/******************************************************************************/
+
+std::string OptimizationTools::DISTANCEMETHOD_INIT       = "init";
+std::string OptimizationTools::DISTANCEMETHOD_PAIRWISE   = "pairwise";
+std::string OptimizationTools::DISTANCEMETHOD_ITERATIONS = "iterations";
+
+/******************************************************************************/
+
+DistanceMatrix* OptimizationTools::estimateDistanceMatrix(
+  DistanceEstimation& estimationMethod,
+  const ParameterList& parametersToIgnore,
+  const std::string& param,
+  unsigned int verbose) throw (Exception)
+{
+  if (param != DISTANCEMETHOD_PAIRWISE && param != DISTANCEMETHOD_INIT)
+    throw Exception("OptimizationTools::estimateDistanceMatrix. Invalid option param=" + param + ".");
+  estimationMethod.resetAdditionalParameters();
+  estimationMethod.setVerbose(verbose);
+  if (param == DISTANCEMETHOD_PAIRWISE)
+  {
+    ParameterList tmp = estimationMethod.getSubstitutionModel().getIndependentParameters();
+    tmp.addParameters(estimationMethod.getRateDistribution().getIndependentParameters());
+    tmp.deleteParameters(parametersToIgnore.getParameterNames());
+    estimationMethod.setAdditionalParameters(tmp);
+  }
+  // Compute matrice:
+  if (verbose > 0)
+    ApplicationTools::displayTask("Estimating distance matrix", true);
+  estimationMethod.computeMatrix();
+  auto_ptr<DistanceMatrix> matrix(estimationMethod.getMatrix());
+  if (verbose > 0)
+    ApplicationTools::displayTaskDone();
+
+  return matrix.release();
+}
+
+/******************************************************************************/
+
+TreeTemplate<Node>* OptimizationTools::buildDistanceTree(
+  DistanceEstimation& estimationMethod,
+  AgglomerativeDistanceMethod& reconstructionMethod,
+  const ParameterList& parametersToIgnore,
+  bool optimizeBrLen,
+  const std::string& param,
+  double tolerance,
+  unsigned int tlEvalMax,
+  OutputStream* profiler,
+  OutputStream* messenger,
+  unsigned int verbose) throw (Exception)
+{
+  estimationMethod.resetAdditionalParameters();
+  estimationMethod.setVerbose(verbose);
+  if (param == DISTANCEMETHOD_PAIRWISE)
+  {
+    ParameterList tmp = estimationMethod.getSubstitutionModel().getIndependentParameters();
+    tmp.addParameters(estimationMethod.getRateDistribution().getIndependentParameters());
+    tmp.deleteParameters(parametersToIgnore.getParameterNames());
+    estimationMethod.setAdditionalParameters(tmp);
+  }
+  TreeTemplate<Node>* tree = NULL;
+  TreeTemplate<Node>* previousTree = NULL;
+  bool test = true;
+  while (test)
+  {
+    // Compute matrice:
+    if (verbose > 0)
+      ApplicationTools::displayTask("Estimating distance matrix", true);
+    estimationMethod.computeMatrix();
+    DistanceMatrix* matrix = estimationMethod.getMatrix();
+    if (verbose > 0)
+      ApplicationTools::displayTaskDone();
+
+    // Compute tree:
+    if (verbose > 0)
+      ApplicationTools::displayTask("Building tree");
+    reconstructionMethod.setDistanceMatrix(*matrix);
+    reconstructionMethod.computeTree();
+    previousTree = tree;
+    delete matrix;
+    tree = dynamic_cast<TreeTemplate<Node>*>(reconstructionMethod.getTree());
+    if (verbose > 0)
+      ApplicationTools::displayTaskDone();
+    if (previousTree && verbose > 0)
+    {
+      int rf = TreeTools::robinsonFouldsDistance(*previousTree, *tree, false);
+      ApplicationTools::displayResult("Topo. distance with previous iteration", TextTools::toString(rf));
+      test = (rf == 0);
+      delete previousTree;
+    }
+    if (param != DISTANCEMETHOD_ITERATIONS)
+      break;  // Ends here.
+
+    // Now, re-estimate parameters:
+    auto_ptr<SubstitutionModel> model(estimationMethod.getSubstitutionModel().clone());
+    auto_ptr<DiscreteDistribution> rdist(estimationMethod.getRateDistribution().clone());
+    DRHomogeneousTreeLikelihood tl(*tree,
+        *estimationMethod.getData(),
+        model.get(),
+        rdist.get(),
+        true, verbose > 1);
+    tl.initialize();
+    ParameterList parameters = tl.getParameters();
+    if (!optimizeBrLen)
+    {
+      vector<string> vs = tl.getBranchLengthsParameters().getParameterNames();
+      parameters.deleteParameters(vs);
+    }
+    parameters.deleteParameters(parametersToIgnore.getParameterNames());
+    optimizeNumericalParameters(&tl, parameters, NULL, 0, tolerance, tlEvalMax, messenger, profiler, verbose > 0 ? verbose - 1 : 0);
+    if (verbose > 0)
+    {
+      ParameterList tmp = tl.getSubstitutionModelParameters();
+      for (unsigned int i = 0; i < tmp.size(); i++)
+      {
+        ApplicationTools::displayResult(tmp[i].getName(), TextTools::toString(tmp[i].getValue()));
+      }
+      tmp = tl.getRateDistributionParameters();
+      for (unsigned int i = 0; i < tmp.size(); i++)
+      {
+        ApplicationTools::displayResult(tmp[i].getName(), TextTools::toString(tmp[i].getValue()));
+      }
+    }
+  }
+  return tree;
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/OptimizationTools.h b/src/Bpp/Phyl/OptimizationTools.h
new file mode 100644
index 0000000..13c2326
--- /dev/null
+++ b/src/Bpp/Phyl/OptimizationTools.h
@@ -0,0 +1,770 @@
+//
+// File: OptimizationTools.h
+// Created by: Julien Dutheil
+// Created on: Sun Dec 14 09:43:32 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _OPTIMIZATIONTOOLS_H_
+#define _OPTIMIZATIONTOOLS_H_
+
+#include "Likelihood/ClockTreeLikelihood.h"
+#include "Likelihood/NNIHomogeneousTreeLikelihood.h"
+#include "Likelihood/ClockTreeLikelihood.h"
+#include "NNITopologySearch.h"
+#include "Parsimony/DRTreeParsimonyScore.h"
+#include "TreeTemplate.h"
+#include "Distance/DistanceEstimation.h"
+#include "Distance/DistanceMethod.h"
+
+#include <Bpp/Io/OutputStream.h>
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Numeric/Function/SimpleNewtonMultiDimensions.h>
+
+namespace bpp
+{
+
+/**
+ * @brief A listener which capture NaN function values and throw an exception in case this happens.
+ */
+class NaNListener: public OptimizationListener
+{
+  private:
+    Optimizer* optimizer_;
+    Function* function_;
+
+  public:
+    NaNListener(Optimizer* optimizer, Function* function): optimizer_(optimizer), function_(function) {}
+
+    NaNListener(const NaNListener& lr):
+      optimizer_(lr.optimizer_),
+      function_(lr.function_)
+    {}
+  
+    NaNListener& operator=(const NaNListener& lr)
+    {
+      optimizer_ = lr.optimizer_;
+      function_  = lr.function_;
+      return *this;
+    }
+  
+  public:
+    void optimizationInitializationPerformed(const OptimizationEvent &event) {}
+    void optimizationStepPerformed(const OptimizationEvent &event) throw (Exception)
+    {
+      if (isnan(optimizer_->getFunction()->getValue()))
+      {
+         cerr << "Oups... something abnormal happened!" << endl;
+         function_->getParameters().printParameters(cerr);
+         throw Exception("Optimization failed because likelihood function returned NaN.");
+      }
+    }
+    bool listenerModifiesParameters () const { return false; }
+};
+
+
+
+/**
+ * @brief Listener used internally by the optimizeTreeNNI method.
+ */
+class NNITopologyListener :
+  public virtual TopologyListener
+{
+private:
+  NNITopologySearch* topoSearch_;
+  ParameterList parameters_;
+  double tolerance_;
+  OutputStream* messenger_;
+  OutputStream* profiler_;
+  unsigned int verbose_;
+  unsigned int optimizeCounter_;
+  unsigned int optimizeNumerical_;
+  std::string optMethod_;
+  unsigned int nStep_;
+  bool reparametrization_;
+
+public:
+  /**
+   * @brief Build a new NNITopologyListener object.
+   *
+   * This listener listens to a NNITopologySearch object, and optimizes numerical parameters every *n* topological movements.
+   * Optimization is performed using the optimizeNumericalParameters method (see there documentation for more details).
+   *
+   * @param ts         The NNITopologySearch object attached to this listener.
+   * @param parameters The list of parameters to optimize. Use tl->getIndependentParameters() in order to estimate all parameters.
+   * @param tolerance  Tolerance to use during optimizaton.
+   * @param messenger  Where to output messages.
+   * @param profiler   Where to output optimization steps.
+   * @param verbose    Verbose level during optimization.
+   * @param optMethod  Optimization method to use.
+   * @param nStep      The number of optimization steps to perform.
+   * @param reparametrization Tell if parameters should be transformed in order to remove constraints.
+   *                          This can improve optimization, but is a bit slower.
+   */
+  NNITopologyListener(
+    NNITopologySearch* ts,
+    const ParameterList& parameters,
+    double tolerance,
+    OutputStream* messenger,
+    OutputStream* profiler,
+    unsigned int verbose,
+    const std::string& optMethod,
+    unsigned int nStep,
+    bool reparametrization) :
+    topoSearch_(ts),
+    parameters_(parameters),
+    tolerance_(tolerance),
+    messenger_(messenger),
+    profiler_(profiler),
+    verbose_(verbose),
+    optimizeCounter_(0),
+    optimizeNumerical_(1),
+    optMethod_(optMethod),
+    nStep_(nStep),
+    reparametrization_(reparametrization) {}
+
+  NNITopologyListener(const NNITopologyListener& tl) :
+    topoSearch_(tl.topoSearch_),
+    parameters_(tl.parameters_),
+    tolerance_(tl.tolerance_),
+    messenger_(tl.messenger_),
+    profiler_(tl.profiler_),
+    verbose_(tl.verbose_),
+    optimizeCounter_(tl.optimizeCounter_),
+    optimizeNumerical_(tl.optimizeNumerical_),
+    optMethod_(tl.optMethod_),
+    nStep_(tl.nStep_),
+    reparametrization_(tl.reparametrization_)
+  {}
+
+  NNITopologyListener& operator=(const NNITopologyListener& tl)
+  {
+    topoSearch_        = tl.topoSearch_;
+    parameters_        = tl.parameters_;
+    tolerance_         = tl.tolerance_;
+    messenger_         = tl.messenger_;
+    profiler_          = tl.profiler_;
+    verbose_           = tl.verbose_;
+    optimizeCounter_   = tl.optimizeCounter_;
+    optimizeNumerical_ = tl.optimizeNumerical_;
+    optMethod_         = tl.optMethod_;
+    nStep_             = tl.nStep_;
+    reparametrization_ = tl.reparametrization_;
+    return *this;
+  }
+
+  NNITopologyListener* clone() const { return new NNITopologyListener(*this); }
+
+  virtual ~NNITopologyListener() {}
+
+public:
+  void topologyChangeTested(const TopologyChangeEvent& event) {}
+  void topologyChangeSuccessful(const TopologyChangeEvent& event);
+  void setNumericalOptimizationCounter(unsigned int c) { optimizeNumerical_ = c; }
+};
+
+/**
+ * @brief Listener used internally by the optimizeTreeNNI2 method.
+ */
+class NNITopologyListener2 :
+  public TopologyListener
+{
+private:
+  NNITopologySearch* topoSearch_;
+  ParameterList parameters_;
+  double tolerance_;
+  OutputStream* messenger_;
+  OutputStream* profiler_;
+  unsigned int verbose_;
+  unsigned int optimizeCounter_;
+  unsigned int optimizeNumerical_;
+  std::string optMethod_;
+  bool reparametrization_;
+
+public:
+  /**
+   * @brief Build a new NNITopologyListener2 object.
+   *
+   * This listener listens to a NNITopologySearch object, and optimizes numerical parameters every *n* topological movements.
+   * Optimization is performed using the optimizeNumericalParameters2 method (see there documentation for more details).
+   *
+   * @param ts         The NNITopologySearch object attached to this listener.
+   * @param parameters The list of parameters to optimize. Use ts->getIndependentParameters() in order to estimate all parameters.
+   * @param tolerance  Tolerance to use during optimizaton.
+   * @param messenger  Where to output messages.
+   * @param profiler   Where to output optimization steps.
+   * @param verbose    Verbose level during optimization.
+   * @param optMethod  Optimization method to use.
+   * @param reparametrization Tell if parameters should be transformed in order to remove constraints.
+   *                          This can improve optimization, but is a bit slower.
+   */
+  NNITopologyListener2(
+    NNITopologySearch* ts,
+    const ParameterList& parameters,
+    double tolerance,
+    OutputStream* messenger,
+    OutputStream* profiler,
+    unsigned int verbose,
+    const std::string& optMethod,
+    bool reparametrization) :
+    topoSearch_(ts),
+    parameters_(parameters),
+    tolerance_(tolerance),
+    messenger_(messenger),
+    profiler_(profiler),
+    verbose_(verbose),
+    optimizeCounter_(0),
+    optimizeNumerical_(1),
+    optMethod_(optMethod),
+    reparametrization_(reparametrization) {}
+
+  NNITopologyListener2(const NNITopologyListener2& tl) :
+    topoSearch_(tl.topoSearch_),
+    parameters_(tl.parameters_),
+    tolerance_(tl.tolerance_),
+    messenger_(tl.messenger_),
+    profiler_(tl.profiler_),
+    verbose_(tl.verbose_),
+    optimizeCounter_(tl.optimizeCounter_),
+    optimizeNumerical_(tl.optimizeNumerical_),
+    optMethod_(tl.optMethod_),
+    reparametrization_(tl.reparametrization_)
+  {}
+
+  NNITopologyListener2& operator=(const NNITopologyListener2& tl)
+  {
+    topoSearch_        = tl.topoSearch_;
+    parameters_        = tl.parameters_;
+    tolerance_         = tl.tolerance_;
+    messenger_         = tl.messenger_;
+    profiler_          = tl.profiler_;
+    verbose_           = tl.verbose_;
+    optimizeCounter_   = tl.optimizeCounter_;
+    optimizeNumerical_ = tl.optimizeNumerical_;
+    optMethod_         = tl.optMethod_;
+    reparametrization_ = tl.reparametrization_;
+    return *this;
+  }
+
+  NNITopologyListener2* clone() const { return new NNITopologyListener2(*this); }
+
+  virtual ~NNITopologyListener2() {}
+
+public:
+  void topologyChangeTested(const TopologyChangeEvent& event) {}
+  void topologyChangeSuccessful(const TopologyChangeEvent& event);
+  void setNumericalOptimizationCounter(unsigned int c) { optimizeNumerical_ = c; }
+};
+
+
+/**
+ * @brief Optimization methods for phylogenetic inference.
+ *
+ * This class provides optimization methods for phylogenetics.
+ * Parameters of the optimization methods are set to work with TreeLikelihood
+ * object. Some non trivial parameters are left to the user choice (tolerance, maximum
+ * number of function evaluation, output streams).
+ */
+class OptimizationTools
+{
+public:
+  OptimizationTools();
+  virtual ~OptimizationTools();
+
+public:
+  static std::string OPTIMIZATION_GRADIENT;
+  static std::string OPTIMIZATION_NEWTON;
+  static std::string OPTIMIZATION_BRENT;
+  static std::string OPTIMIZATION_BFGS;
+
+  /**
+   * @brief Optimize numerical parameters (branch length, substitution model & rate distribution) of a TreeLikelihood function.
+   *
+   * Uses Newton's method for branch length and Brent or BFGS one dimensional method for other parameters.
+   *
+   * A condition over function values is used as a stop condition for the algorithm.
+   *
+   * @see BrentOneDimension, BFGSMultiDimensions
+   *
+   * @param tl             A pointer toward the TreeLikelihood object to optimize.
+   * @param parameters     The list of parameters to optimize. Use tl->getIndependentParameters() in order to estimate all parameters.
+   * @param listener       A pointer toward an optimization listener, if needed.
+   * @param nstep          The number of progressive steps to perform (see NewtonBrentMetaOptimizer). 1 means full precision from start.
+   * @param tolerance      The tolerance to use in the algorithm.
+   * @param tlEvalMax      The maximum number of function evaluations.
+   * @param messageHandler The massage handler.
+   * @param profiler       The profiler.
+   * @param reparametrization Tell if parameters should be transformed in order to remove constraints.
+   *                          This can improve optimization, but is a bit slower.
+   * @param verbose        The verbose level.
+   * @param optMethodDeriv Optimization type for derivable parameters (first or second order derivatives).
+   * @see OPTIMIZATION_NEWTON, OPTIMIZATION_GRADIENT
+   * @param optMethodModel Optimization type for model parameters (Brent or BFGS).
+   * @see OPTIMIZATION_BRENT, OPTIMIZATION_BFGS
+   * @throw Exception any exception thrown by the Optimizer.
+   */
+  static unsigned int optimizeNumericalParameters(
+    DiscreteRatesAcrossSitesTreeLikelihood* tl,
+    const ParameterList& parameters,
+    OptimizationListener* listener    = 0,
+    unsigned int nstep                = 1,
+    double tolerance                  = 0.000001,
+    unsigned int tlEvalMax            = 1000000,
+    OutputStream* messageHandler      = ApplicationTools::message,
+    OutputStream* profiler            = ApplicationTools::message,
+    bool reparametrization            = false,
+    unsigned int verbose              = 1,
+    const std::string& optMethodDeriv = OPTIMIZATION_NEWTON,
+    const std::string& optMethodModel = OPTIMIZATION_BRENT)
+  throw (Exception);
+
+  /**
+   * @brief Optimize numerical parameters (branch length, substitution model & rate distribution) of a TreeLikelihood function.
+   *
+   * Uses Newton's method for all parameters, branch length derivatives are computed analytically, derivatives for other parameters numerically.
+   *
+   * @see PseudoNewtonOptimizer
+   *
+   * @param tl             A pointer toward the TreeLikelihood object to optimize.
+   * @param parameters     The list of parameters to optimize. Use tl->getIndependentParameters() in order to estimate all parameters.
+   * @param listener       A pointer toward an optimization listener, if needed.
+   * @param tolerance      The tolerance to use in the algorithm.
+   * @param tlEvalMax      The maximum number of function evaluations.
+   * @param messageHandler The massage handler.
+   * @param profiler       The profiler.
+   * @param reparametrization Tell if parameters should be transformed in order to remove constraints.
+   *                          This can improve optimization, but is a bit slower.
+   * @param useClock       Tell if branch lengths have to be optimized under a global molecular clock constraint.
+   * @param verbose        The verbose level.
+   * @param optMethodDeriv Optimization type for derivable parameters (first or second order derivatives).
+   * @see OPTIMIZATION_NEWTON, OPTIMIZATION_GRADIENT
+   * @throw Exception any exception thrown by the Optimizer.
+   */
+  static unsigned int optimizeNumericalParameters2(
+    DiscreteRatesAcrossSitesTreeLikelihood* tl,
+    const ParameterList& parameters,
+    OptimizationListener* listener     = 0,
+    double tolerance                   = 0.000001,
+    unsigned int tlEvalMax             = 1000000,
+    OutputStream* messageHandler       = ApplicationTools::message,
+    OutputStream* profiler             = ApplicationTools::message,
+    bool reparametrization             = false,
+    bool useClock                      = false,
+    unsigned int verbose               = 1,
+    const std::string& optMethodDeriv  = OPTIMIZATION_NEWTON)
+  throw (Exception);
+
+  /**
+   * @brief Optimize branch lengths parameters of a TreeLikelihood function.
+   *
+   * Uses Newton's method.
+   *
+   * A condition over function values is used as a stop condition for the algorithm.
+   *
+   * @see NewtonBrentMetaOptimizer
+   *
+   * @param tl             A pointer toward the TreeLikelihood object to optimize.
+   * @param parameters     The list of parameters to optimize. The intersection of branch length parameters and the input set will be used. Use tl->getBranchLengthsParameters() in order to estimate all branch length parameters.
+   * @param listener       A pointer toward an optimization listener, if needed.
+   * @param tolerance      The tolerance to use in the algorithm.
+   * @param tlEvalMax      The maximum number of function evaluations.
+   * @param messageHandler The massage handler.
+   * @param profiler       The profiler.
+   * @param verbose        The verbose level.
+   * @param optMethodDeriv Optimization type for derivable parameters (first or second order derivatives).
+   * @see OPTIMIZATION_NEWTON, OPTIMIZATION_GRADIENT
+   * @throw Exception any exception thrown by the Optimizer.
+   */
+  static unsigned int optimizeBranchLengthsParameters(
+    DiscreteRatesAcrossSitesTreeLikelihood* tl,
+    const ParameterList& parameters,
+    OptimizationListener* listener     = 0,
+    double tolerance                   = 0.000001,
+    unsigned int tlEvalMax             = 1000000,
+    OutputStream* messageHandler       = ApplicationTools::message,
+    OutputStream* profiler             = ApplicationTools::message,
+    unsigned int verbose               = 1,
+    const std::string& optMethodDeriv  = OPTIMIZATION_NEWTON)
+  throw (Exception);
+
+  /**
+   * @brief Optimize numerical parameters assuming a global clock (branch heights, substitution model & rate distribution) of a ClockTreeLikelihood function.
+   *
+   * Uses Newton or conjugate gradient method for branch length and Brent's one dimensional method for other parameters
+   * (NewtonBrentMetaOptimizer).
+   * Derivatives are computed analytically.
+   *
+   * A condition over function values is used as a stop condition for the algorithm.
+   *
+   * @see NewtonBrentMetaOptimizer
+   *
+   * @param cl             A pointer toward the ClockTreeLikelihood object to optimize.
+   * @param parameters     The list of parameters to optimize. Use cl->getIndependentParameters() in order to estimate all parameters.
+   * @param listener       A pointer toward an optimization listener, if needed.
+   * @param nstep          The number of progressive steps to perform (see NewtonBrentMetaOptimizer). 1 means full precision from start.
+   * @param tolerance      The tolerance to use in the algorithm.
+   * @param tlEvalMax      The maximum number of function evaluations.
+   * @param messageHandler The massage handler.
+   * @param profiler       The profiler.
+   * @param verbose        The verbose level.
+   * @param optMethodDeriv Optimization type for derivable parameters (first or second order derivatives).
+   * @see OPTIMIZATION_NEWTON, OPTIMIZATION_GRADIENT
+   * @throw Exception any exception thrown by the Optimizer.
+   * @deprecated See optimizeNumericalParameters2 as a more general replacement.
+   */
+  static unsigned int optimizeNumericalParametersWithGlobalClock(
+    DiscreteRatesAcrossSitesClockTreeLikelihood* cl,
+    const ParameterList& parameters,
+    OptimizationListener* listener    = 0,
+    unsigned int nstep                = 1,
+    double tolerance                  = 0.000001,
+    unsigned int tlEvalMax            = 1000000,
+    OutputStream* messageHandler      = ApplicationTools::message,
+    OutputStream* profiler            = ApplicationTools::message,
+    unsigned int verbose              = 1,
+    const std::string& optMethodDeriv = OPTIMIZATION_GRADIENT)
+  throw (Exception);
+
+  /**
+   * @brief Optimize numerical parameters assuming a global clock (branch heights, substitution model & rate distribution) of a ClockTreeLikelihood function.
+   *
+   * Uses Newton or conjugate gradient method for all parameters, branch length derivatives are computed analytically, derivatives for other parameters numerically.
+   *
+   * @see PseudoNewtonOptimizer
+   *
+   * @param cl             A pointer toward the ClockTreeLikelihood object to optimize.
+   * @param parameters     The list of parameters to optimize. Use cl->getIndependentParameters() in order to estimate all parameters.
+   * @param listener       A pointer toward an optimization listener, if needed.
+   * @param tolerance      The tolerance to use in the algorithm.
+   * @param tlEvalMax      The maximum number of function evaluations.
+   * @param messageHandler The massage handler.
+   * @param profiler       The profiler.
+   * @param verbose        The verbose level.
+   * @param optMethodDeriv Optimization type for derivable parameters (first or second order derivatives).
+   * @see OPTIMIZATION_NEWTON, OPTIMIZATION_GRADIENT
+   * @throw Exception any exception thrown by the Optimizer.
+   * @deprecated See optimizeNumericalParameters2 as a more general replacement.
+   */
+  static unsigned int optimizeNumericalParametersWithGlobalClock2(
+    DiscreteRatesAcrossSitesClockTreeLikelihood* cl,
+    const ParameterList& parameters,
+    OptimizationListener* listener    = 0,
+    double tolerance                  = 0.000001,
+    unsigned int tlEvalMax            = 1000000,
+    OutputStream* messageHandler      = ApplicationTools::message,
+    OutputStream* profiler            = ApplicationTools::message,
+    unsigned int verbose              = 1,
+    const std::string& optMethodDeriv = OPTIMIZATION_GRADIENT)
+  throw (Exception);
+
+private:
+  class ScaleFunction :
+    public virtual Function,
+    public ParametrizableAdapter
+  {
+private:
+    TreeLikelihood* tl_;
+    mutable ParameterList brLen_, lambda_;
+
+public:
+    ScaleFunction(TreeLikelihood* tl);
+
+    ScaleFunction(const ScaleFunction& sf) :
+      tl_(sf.tl_),
+      brLen_(sf.brLen_),
+      lambda_(sf.lambda_)
+    {}
+
+    ScaleFunction& operator=(const ScaleFunction& sf)
+    {
+      tl_     = sf.tl_;
+      brLen_  = sf.brLen_;
+      lambda_ = sf.lambda_;
+      return *this;
+    }
+
+    virtual ~ScaleFunction();
+
+#ifndef NO_VIRTUAL_COV
+    ScaleFunction*
+#else
+    Clonable*
+#endif
+    clone() const { return new ScaleFunction(*this); }
+
+public:
+    void setParameters(const ParameterList& lambda) throw (ParameterNotFoundException, ConstraintException);
+    double getValue() const throw (ParameterException);
+    const ParameterList& getParameters() const throw (Exception) { return lambda_; }
+    const Parameter& getParameter(const std::string& name) const throw (ParameterNotFoundException)
+    {
+      if (name == "lambda") return lambda_[0];
+      else throw ParameterNotFoundException("ScaleFunction::getParameter.", name);
+    }
+    double getParameterValue(const std::string& name) const throw (ParameterNotFoundException)
+    {
+      return lambda_.getParameter(name).getValue();
+    }
+    size_t getNumberOfParameters() const { return 1; }
+    size_t getNumberOfIndependentParameters() const { return 1; }
+  };
+
+public:
+  /**
+   * @brief Optimize the scale of a TreeLikelihood.
+   *
+   * This method only works on branch lengths parameters.
+   * It multiply all branch length by a factor 'x' which is optimized
+   * using Brent's algorithm in one dimension.
+   * This method may be usefull for scaling a tree whose branch lengths
+   * come from the Neighbor-Joining algorithm for instance.
+   *
+   * Practically, and contrarily to what one may expect, this does not
+   * speed up the optimization!
+   *
+   * A condition over parameters is used as a stop condition for the algorithm.
+   *
+   * @param tl             A pointer toward the TreeLikelihood object to optimize.
+   * @param tolerance      The tolerance to use in the algorithm.
+   * @param tlEvalMax      The maximum number of function evaluations.
+   * @param messageHandler The massage handler.
+   * @param profiler       The profiler.
+   * @param verbose        The verbose level.
+   * @throw Exception any exception thrown by the optimizer.
+   */
+  static unsigned int optimizeTreeScale(
+    TreeLikelihood* tl,
+    double tolerance = 0.000001,
+    int tlEvalMax = 1000000,
+    OutputStream* messageHandler = ApplicationTools::message,
+    OutputStream* profiler       = ApplicationTools::message,
+    unsigned int verbose = 1)
+  throw (Exception);
+
+  /**
+   * @brief Optimize all parameters from a TreeLikelihood object, including tree topology using Nearest Neighbor Interchanges.
+   *
+   * This function takes as input a TreeLikelihood object implementing the NNISearchable interface.
+   *
+   * Details:
+   * A NNITopologySearch object is instanciated and is associated an additional TopologyListener.
+   * This listener is used to re-estimate numerical parameters after one or several topology change.
+   * By default, the PHYML option is used for the NNITopologySearch object, and numerical parameters are re-estimated
+   * every 4 NNI runs (as in the phyml software).
+   *
+   * The optimizeNumericalParameters method is used for estimating numerical parameters.
+   * The tolerance passed to this function is specified as input parameters.
+   * They are generally very high to avoid local optima.
+   *
+   * @param tl                A pointer toward the TreeLikelihood object to optimize.
+   * @param parameters        The list of parameters to optimize. Use tl->getIndependentParameters() in order to estimate all parameters.
+   * @param optimizeNumFirst  Tell if we must optimize numerical parameters before searching topology.
+   * @param tolBefore         The tolerance to use when estimating numerical parameters before topology search (if optimizeNumFirst is set to 'true').
+   * @param tolDuring         The tolerance to use when estimating numerical parameters during the topology search.
+   * @param tlEvalMax         The maximum number of function evaluations.
+   * @param numStep           Number of NNI rounds before re-estimating numerical parameters.
+   * @param messageHandler    The massage handler.
+   * @param profiler          The profiler.
+   * @param reparametrization Tell if parameters should be transformed in order to remove constraints.
+   *                          This can improve optimization, but is a bit slower.
+   * @param verbose           The verbose level.
+   * @param optMethod         Option passed to optimizeNumericalParameters.
+   * @param nStep             Option passed to optimizeNumericalParameters.
+   * @param nniMethod         NNI algorithm to use.
+   * @return A pointer toward the final likelihood object.
+   * This pointer may be the same as passed in argument (tl), but in some cases the algorithm
+   * clone this object. We may change this bahavior in the future...
+   * You hence should write something like
+   * @code
+   * tl = OptimizationTools::optimizeTreeNNI(tl, ...);
+   * @endcode
+   * @throw Exception any exception thrown by the optimizer.
+   */
+  static NNIHomogeneousTreeLikelihood* optimizeTreeNNI(
+    NNIHomogeneousTreeLikelihood* tl,
+    const ParameterList& parameters,
+    bool optimizeNumFirst        = true,
+    double tolBefore             = 100,
+    double tolDuring             = 100,
+    int tlEvalMax                = 1000000,
+    unsigned int numStep         = 1,
+    OutputStream* messageHandler = ApplicationTools::message,
+    OutputStream* profiler       = ApplicationTools::message,
+    bool reparametrization       = false,
+    unsigned int verbose         = 1,
+    const std::string& optMethod = OptimizationTools::OPTIMIZATION_NEWTON,
+    unsigned int nStep           = 1,
+    const std::string& nniMethod = NNITopologySearch::PHYML)
+  throw (Exception);
+
+  /**
+   * @brief Optimize all parameters from a TreeLikelihood object, including tree topology using Nearest Neighbor Interchanges.
+   *
+   * This function takes as input a TreeLikelihood object implementing the NNISearchable interface.
+   *
+   * Details:
+   * A NNITopologySearch object is instanciated and is associated an additional TopologyListener.
+   * This listener is used to re-estimate numerical parameters after one or several topology change.
+   * By default, the PHYML option is used for the NNITopologySearch object, and numerical parameters are re-estimated
+   * every 4 NNI runs (as in the phyml software).
+   *
+   * The optimizeNumericalParameters2 method is used for estimating numerical parameters.
+   * The tolerance passed to this function is specified as input parameters.
+   * They are generally very high to avoid local optima.
+   *
+   * @param tl                A pointer toward the TreeLikelihood object to optimize.
+   * @param parameters        The list of parameters to optimize. Use tl->getIndependentParameters() in order to estimate all parameters.
+   * @param optimizeNumFirst  Tell if we must optimize numerical parameters before searching topology.
+   * @param tolBefore         The tolerance to use when estimating numerical parameters before topology search (if optimizeNumFirst is set to 'true').
+   * @param tolDuring         The tolerance to use when estimating numerical parameters during the topology search.
+   * @param tlEvalMax         The maximum number of function evaluations.
+   * @param numStep           Number of NNI rounds before re-estimating numerical parameters.
+   * @param messageHandler    The massage handler.
+   * @param profiler          The profiler.
+   * @param reparametrization Tell if parameters should be transformed in order to remove constraints.
+   *                          This can improve optimization, but is a bit slower.
+   * @param verbose           The verbose level.
+   * @param optMethod         Option passed to optimizeNumericalParameters2.
+   * @param nniMethod         NNI algorithm to use.
+   * @return A pointer toward the final likelihood object.
+   * This pointer may be the same as passed in argument (tl), but in some cases the algorithm
+   * clone this object. We may change this bahavior in the future...
+   * You hence should write something like
+   * @code
+   * tl = OptimizationTools::optimizeTreeNNI2(tl, ...);
+   * @endcode
+   * @throw Exception any exception thrown by the optimizer.
+   */
+  static NNIHomogeneousTreeLikelihood* optimizeTreeNNI2(
+    NNIHomogeneousTreeLikelihood* tl,
+    const ParameterList& parameters,
+    bool optimizeNumFirst        = true,
+    double tolBefore             = 100,
+    double tolDuring             = 100,
+    int tlEvalMax                = 1000000,
+    unsigned int numStep         = 1,
+    OutputStream* messageHandler = ApplicationTools::message,
+    OutputStream* profiler       = ApplicationTools::message,
+    bool reparametrization       = false,
+    unsigned int verbose         = 1,
+    const std::string& optMethod = OptimizationTools::OPTIMIZATION_NEWTON,
+    const std::string& nniMethod = NNITopologySearch::PHYML)
+  throw (Exception);
+
+  /**
+   * @brief Optimize tree topology from a DRTreeParsimonyScore using Nearest Neighbor Interchanges.
+   *
+   * @param tp               A pointer toward the DRTreeParsimonyScore object to optimize.
+   * @param verbose          The verbose level.
+   * @return A pointer toward the final parsimony score object.
+   * This pointer may be the same as passed in argument (tl), but in some cases the algorithm
+   * clone this object. We may change this bahavior in the future...
+   * You hence should write something like
+   * @code
+   * tp = OptimizationTools::optimizeTreeNNI(tp, ...);
+   * @endcode
+   */
+
+  static DRTreeParsimonyScore* optimizeTreeNNI(
+    DRTreeParsimonyScore* tp,
+    unsigned int verbose = 1);
+
+  /**
+   * @brief Estimate a distance matrix using maximum likelihood.
+   *
+   * This method estimate a distance matrix using a DistanceEstimation object.
+   * The main issue here is to estimate non-branch lengths parameters, as substitution model and rate distribution parameters.
+   * Twoe options are provideed here:
+   * - DISTANCEMETHOD_INIT (default) keep parameters to there initial value,
+   * - DISTANCEMETHOD_PAIRWISE estimated parameters in a pairwise manner, which is standard but not that satisfying...
+   *
+   * @param estimationMethod The distance estimation object to use.
+   * @param parametersToIgnore A list of parameters to ignore while optimizing parameters.
+   * @param param String describing the type of optimization to use.
+   * @param verbose Verbose level.
+   *
+   * @see buildDistanceTree for a procedure to jointly estimate the distance matrix and underlying tree.
+   */
+  static DistanceMatrix* estimateDistanceMatrix(
+    DistanceEstimation& estimationMethod,
+    const ParameterList& parametersToIgnore,
+    const std::string& param = DISTANCEMETHOD_INIT,
+    unsigned int verbose = 0) throw (Exception);
+
+  /**
+   * @brief Build a tree using a distance method.
+   *
+   * This method estimate a distance matrix using a DistanceEstimation object, and then builds the phylogenetic tree using a AgglomerativeDistanceMethod object.
+   * The main issue here is to estimate non-branch lengths parameters, as substitution model and rate distribution parameters.
+   * Three options are provideed here:
+   * - DISTANCEMETHOD_INIT (default) keep parameters to there initial value,
+   * - DISTANCEMETHOD_PAIRWISE estimated parameters in a pairwise manner, which is standard but not that satisfying...
+   * - DISTANCEMETHOD_ITERATIONS uses Ninio et al's iterative algorithm, which uses Maximum Likelihood to estimate these parameters, and then update the distance matrix.
+   * Ninio M, Privman E, Pupko T, Friedman N.
+   * Phylogeny reconstruction: increasing the accuracy of pairwise distance estimation using Bayesian inference of evolutionary rates.
+   * Bioinformatics. 2007 Jan 15;23(2):e136-41.
+   *
+   * @param estimationMethod The distance estimation object to use.
+   * @param reconstructionMethod The tree reconstruction object to use.
+   * @param parametersToIgnore A list of parameters to ignore while optimizing parameters.
+   * @param optimizeBrLen Tell if branch lengths should be optimized together with other parameters. This may lead to more accurate parameter estimation, but is slower.
+   * @param param String describing the type of optimization to use.
+   * @param tolerance Threshold on likelihood for stopping the iterative procedure. Used only with param=DISTANCEMETHOD_ITERATIONS.
+   * @param tlEvalMax Maximum number of likelihood computations to perform when optimizing parameters. Used only with param=DISTANCEMETHOD_ITERATIONS.
+   * @param profiler Output stream used by optimizer. Used only with param=DISTANCEMETHOD_ITERATIONS.
+   * @param messenger Output stream used by optimizer. Used only with param=DISTANCEMETHOD_ITERATIONS.
+   * @param verbose Verbose level.
+   */
+  static TreeTemplate<Node>* buildDistanceTree(
+    DistanceEstimation& estimationMethod,
+    AgglomerativeDistanceMethod& reconstructionMethod,
+    const ParameterList& parametersToIgnore,
+    bool optimizeBrLen = false,
+    const std::string& param = DISTANCEMETHOD_INIT,
+    double tolerance = 0.000001,
+    unsigned int tlEvalMax = 1000000,
+    OutputStream* profiler = 0,
+    OutputStream* messenger = 0,
+    unsigned int verbose = 0) throw (Exception);
+
+public:
+  static std::string DISTANCEMETHOD_INIT;
+  static std::string DISTANCEMETHOD_PAIRWISE;
+  static std::string DISTANCEMETHOD_ITERATIONS;
+};
+} // end of namespace bpp.
+
+#endif  // _OPTIMIZATIONTOOLS_H_
+
diff --git a/src/Bpp/Phyl/Parsimony/AbstractTreeParsimonyData.h b/src/Bpp/Phyl/Parsimony/AbstractTreeParsimonyData.h
new file mode 100644
index 0000000..3cb751f
--- /dev/null
+++ b/src/Bpp/Phyl/Parsimony/AbstractTreeParsimonyData.h
@@ -0,0 +1,118 @@
+//
+// File: AbstractTreeParsimonyData.h
+// Created by: Julien Dutheil
+// Created on: Tue Jan 09 17:15 2007
+// From file AbstractTreeParsimonyScore.h
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _ABSTRACTTREEPARSIMONYDATA_H_
+#define _ABSTRACTTREEPARSIMONYDATA_H_
+
+#include "TreeParsimonyData.h"
+
+namespace bpp
+{
+/**
+ * @brief Partial implementation of the TreeParsimonyData interface.
+ *
+ * This data structure provides a simple compression, by performing and storing computations
+ * only one time per identical sites.
+ *
+ * The compression is achieved by the TreeParsimonyScore object.
+ * The correspondance between sites in the dataset and the arrays in the structures is given
+ * by the rootPatternLinks_ array: the array indice for site @f$i at f$ if given by:
+ * @code
+ * rootPatternLinks_[i]
+ * @endcode
+ *
+ * Finally, the rootWeights_ array gives for each array position, the number of sites with this
+ * pattern.
+ * The global parsimony score is then given by the sum of all scores for each array position,
+ * weighted by the corresponding number of sites.
+ */
+class AbstractTreeParsimonyData :
+  public TreeParsimonyData
+{
+protected:
+  std::vector<size_t> rootPatternLinks_;
+  std::vector<unsigned int> rootWeights_;
+  const TreeTemplate<Node>* tree_;
+
+public:
+  AbstractTreeParsimonyData(const TreeTemplate<Node>* tree) :
+    rootPatternLinks_(),
+    rootWeights_(),
+    tree_(tree)
+  {}
+
+  AbstractTreeParsimonyData(const AbstractTreeParsimonyData& atpd) :
+    rootPatternLinks_(atpd.rootPatternLinks_),
+    rootWeights_(atpd.rootWeights_),
+    tree_(atpd.tree_)
+  {}
+
+  AbstractTreeParsimonyData& operator=(const AbstractTreeParsimonyData& atpd)
+  {
+    rootPatternLinks_ = atpd.rootPatternLinks_;
+    rootWeights_      = atpd.rootWeights_;
+    tree_             = atpd.tree_;
+    return *this;
+  }
+
+
+  virtual ~AbstractTreeParsimonyData() {}
+
+public:
+  size_t getRootArrayPosition(size_t site) const
+  {
+    return rootPatternLinks_[site];
+  }
+
+  unsigned int getWeight(size_t pos) const
+  {
+    return rootWeights_[pos];
+  }
+
+  const TreeTemplate<Node>* getTree() const { return tree_; }
+
+protected:
+  void setTreeP_(const TreeTemplate<Node>* tree) { tree_ = tree; }
+  const TreeTemplate<Node>* getTreeP_() const { return tree_; }
+};
+} // end of namespace bpp.
+
+#endif // _ABSTRACTTREEPARSIMONYDATA_H_
+
diff --git a/src/Bpp/Phyl/Parsimony/AbstractTreeParsimonyScore.cpp b/src/Bpp/Phyl/Parsimony/AbstractTreeParsimonyScore.cpp
new file mode 100755
index 0000000..1969c9f
--- /dev/null
+++ b/src/Bpp/Phyl/Parsimony/AbstractTreeParsimonyScore.cpp
@@ -0,0 +1,108 @@
+//
+// File: AbstractTreeParsimonyScore.cpp
+// Created by: Julien Dutheil
+// Created on: Thu Jul 29 18:11 2005
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "AbstractTreeParsimonyScore.h"
+#include "../PatternTools.h"
+#include "../TreeTemplateTools.h"
+
+#include <Bpp/App/ApplicationTools.h>
+
+using namespace bpp;
+using namespace std;
+
+AbstractTreeParsimonyScore::AbstractTreeParsimonyScore(
+  const Tree& tree,
+  const SiteContainer& data,
+  bool verbose,
+  bool includeGaps)
+throw (Exception) :
+  tree_(new TreeTemplate<Node>(tree)),
+  data_(0),
+  alphabet_(data.getAlphabet()),
+  statesMap_(0),
+  nbStates_(0)
+{
+  statesMap_ = new CanonicalStateMap(alphabet_, includeGaps);
+  nbStates_  = statesMap_->getNumberOfStates();
+  init_(data, verbose);
+}
+
+
+AbstractTreeParsimonyScore::AbstractTreeParsimonyScore(
+  const Tree& tree,
+  const SiteContainer& data,
+  const StateMap* statesMap,
+  bool verbose)
+throw (Exception) :
+  tree_(new TreeTemplate<Node>(tree)),
+  data_(0),
+  alphabet_(data.getAlphabet()),
+  statesMap_(statesMap),
+  nbStates_(statesMap->getNumberOfStates())
+{
+  init_(data, verbose);
+}
+
+void AbstractTreeParsimonyScore::init_(const SiteContainer& data, bool verbose) throw (Exception)
+{
+  if (tree_->isRooted())
+  {
+    if (verbose)
+      ApplicationTools::displayWarning("Tree has been unrooted.");
+    tree_->unroot();
+  }
+  TreeTemplateTools::deleteBranchLengths(*tree_->getRootNode());
+
+  // Sequences will be in the same order than in the tree:
+  data_ = PatternTools::getSequenceSubset(data, *tree_->getRootNode());
+  if (data_->getNumberOfSequences() == 1) throw Exception("Error, only 1 sequence!");
+  if (data_->getNumberOfSequences() == 0) throw Exception("Error, no sequence!");
+  if (data_->getAlphabet()->getSize() > 20) throw Exception("Error, only alphabet with size <= 20 are supported. See the source file of AbstractTreeParsimonyScore.");
+}
+
+std::vector<unsigned int> AbstractTreeParsimonyScore::getScoreForEachSite() const
+{
+  vector<unsigned int> scores(data_->getNumberOfSites());
+  for (size_t i = 0; i < scores.size(); i++)
+  {
+    scores[i] = getScoreForSite(i);
+  }
+  return scores;
+}
+
diff --git a/src/Bpp/Phyl/Parsimony/AbstractTreeParsimonyScore.h b/src/Bpp/Phyl/Parsimony/AbstractTreeParsimonyScore.h
new file mode 100755
index 0000000..89a3f57
--- /dev/null
+++ b/src/Bpp/Phyl/Parsimony/AbstractTreeParsimonyScore.h
@@ -0,0 +1,122 @@
+//
+// File: AbstractTreeParsimonyScore.h
+// Created by: Julien Dutheil
+// Created on: Thu Jul 28 17:25 2005
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _ABSTRACTTREEPARSIMONYSCORE_H_
+#define _ABSTRACTTREEPARSIMONYSCORE_H_
+
+#include "TreeParsimonyScore.h"
+#include "../Model/StateMap.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+namespace bpp
+{
+/**
+ * @brief Partial implementation of the TreeParsimonyScore interface.
+ */
+class AbstractTreeParsimonyScore :
+  public virtual TreeParsimonyScore
+{
+private:
+  TreeTemplate<Node>* tree_;
+  const SiteContainer* data_;
+  const Alphabet* alphabet_;
+  const StateMap* statesMap_;
+  size_t nbStates_;
+
+public:
+  AbstractTreeParsimonyScore(
+    const Tree& tree,
+    const SiteContainer& data,
+    bool verbose,
+    bool includeGaps)
+  throw (Exception);
+
+  AbstractTreeParsimonyScore(
+    const Tree& tree,
+    const SiteContainer& data,
+    const StateMap* statesMap,
+    bool verbose)
+  throw (Exception);
+
+  AbstractTreeParsimonyScore(const AbstractTreeParsimonyScore& tp) :
+    tree_(0),
+    data_(0),
+    alphabet_(tp.alphabet_),
+    statesMap_(0),
+    nbStates_(tp.nbStates_)
+  {
+    tree_      = tp.tree_->clone();
+    data_      = dynamic_cast<SiteContainer*>(tp.data_->clone());
+    statesMap_ = tp.statesMap_->clone();
+  }
+
+  AbstractTreeParsimonyScore& operator=(const AbstractTreeParsimonyScore& tp)
+  {
+    tree_      = dynamic_cast<TreeTemplate<Node>*>(tp.tree_->clone());
+    data_      = dynamic_cast<SiteContainer*>(tp.data_->clone());
+    alphabet_  = tp.alphabet_;
+    statesMap_ = tp.statesMap_->clone();
+    nbStates_  = tp.nbStates_;
+    return *this;
+  }
+
+  virtual ~AbstractTreeParsimonyScore()
+  {
+    delete tree_;
+    if (data_) delete data_;
+  }
+
+private:
+  void init_(const SiteContainer& data, bool verbose) throw (Exception);
+
+public:
+  virtual const Tree& getTree() const { return *tree_; }
+  virtual std::vector<unsigned int> getScoreForEachSite() const;
+  virtual const StateMap& getStateMap() const { return *statesMap_; }
+
+protected:
+  const TreeTemplate<Node>* getTreeP_() const { return tree_; }
+  TreeTemplate<Node>* getTreeP_() { return tree_; }
+};
+} // end of namespace bpp.
+
+#endif // _ABSTRACTTREEPARSIMONYSCORE_H_
+
diff --git a/src/Bpp/Phyl/Parsimony/DRTreeParsimonyData.cpp b/src/Bpp/Phyl/Parsimony/DRTreeParsimonyData.cpp
new file mode 100644
index 0000000..fc19e0d
--- /dev/null
+++ b/src/Bpp/Phyl/Parsimony/DRTreeParsimonyData.cpp
@@ -0,0 +1,219 @@
+//
+// File: DRTreeParsimonyData.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Jan O9 17:38 2007
+// From file: DRHTreeParsimonyScore.cpp
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "DRTreeParsimonyData.h"
+#include "../SitePatterns.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Container/AlignedSequenceContainer.h>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+DRTreeParsimonyData::DRTreeParsimonyData(const DRTreeParsimonyData& data) :
+  AbstractTreeParsimonyData(data),
+  nodeData_(data.nodeData_),
+  leafData_(data.leafData_),
+  rootBitsets_(data.rootBitsets_),
+  rootScores_(data.rootScores_),
+  shrunkData_(0),
+  nbSites_(data.nbSites_),
+  nbStates_(data.nbStates_),
+  nbDistinctSites_(data.nbDistinctSites_)
+{
+  if (data.shrunkData_)
+    shrunkData_ = dynamic_cast<SiteContainer*>(data.shrunkData_->clone());
+  else
+    shrunkData_ = 0;
+}
+
+/******************************************************************************/
+
+DRTreeParsimonyData& DRTreeParsimonyData::operator=(const DRTreeParsimonyData& data)
+{
+  AbstractTreeParsimonyData::operator=(data);
+  nodeData_        = data.nodeData_;
+  leafData_        = data.leafData_;
+  rootBitsets_     = data.rootBitsets_;
+  rootScores_      = data.rootScores_;
+  if (shrunkData_) delete shrunkData_;
+  if (data.shrunkData_)
+    shrunkData_ = dynamic_cast<SiteContainer*>(data.shrunkData_->clone());
+  else
+    shrunkData_ = 0;
+  nbSites_         = data.nbSites_;
+  nbStates_        = data.nbStates_;
+  nbDistinctSites_ = data.nbDistinctSites_;
+  return *this;
+}
+
+/******************************************************************************/
+void DRTreeParsimonyData::init(const SiteContainer& sites, const StateMap& stateMap) throw (Exception)
+{
+  nbStates_         = stateMap.getNumberOfStates();
+  nbSites_          = sites.getNumberOfSites();
+  SitePatterns pattern(&sites);
+  shrunkData_       = pattern.getSites();
+  rootWeights_      = pattern.getWeights();
+  rootPatternLinks_ = pattern.getIndices();
+  nbDistinctSites_  = shrunkData_->getNumberOfSites();
+
+  // Init data:
+  // Clone data for more efficiency on sequences access:
+  const SiteContainer* sequences = new AlignedSequenceContainer(*shrunkData_);
+  init(getTreeP_()->getRootNode(), *sequences, stateMap);
+  delete sequences;
+
+  // Now initialize root arrays:
+  rootBitsets_.resize(nbDistinctSites_);
+  rootScores_.resize(nbDistinctSites_);
+}
+
+/******************************************************************************/
+void DRTreeParsimonyData::init(const Node* node, const SiteContainer& sites, const StateMap& stateMap) throw (Exception)
+{
+  const Alphabet* alphabet = sites.getAlphabet();
+  if (node->isLeaf())
+  {
+    const Sequence* seq;
+    try
+    {
+      seq = &sites.getSequence(node->getName());
+    }
+    catch (SequenceNotFoundException& snfe)
+    {
+      throw SequenceNotFoundException("DRTreeParsimonyData:init(node, sites). Leaf name in tree not found in site container: ", (node->getName()));
+    }
+    DRTreeParsimonyLeafData* leafData    = &leafData_[node->getId()];
+    vector<Bitset>* leafData_bitsets     = &leafData->getBitsetsArray();
+    leafData->setNode(node);
+
+    leafData_bitsets->resize(nbDistinctSites_);
+
+    for (unsigned int i = 0; i < nbDistinctSites_; i++)
+    {
+      Bitset* leafData_bitsets_i = &(*leafData_bitsets)[i];
+      for (unsigned int s = 0; s < nbStates_; s++)
+      {
+        // Leaves bitset are set to 1 if the char correspond to the site in the sequence,
+        // otherwise value set to 0:
+        int state = seq->getValue(i);
+        vector<int> states = alphabet->getAlias(state);
+        for (unsigned int j = 0; j < states.size(); j++)
+        {
+          if (stateMap.stateAsInt(s) == states[j])
+            (*leafData_bitsets_i)[s].flip();
+        }
+      }
+    }
+  }
+  else
+  {
+    DRTreeParsimonyNodeData* nodeData = &nodeData_[node->getId()];
+    nodeData->setNode(node);
+    nodeData->eraseNeighborArrays();
+
+    int nbSons = static_cast<int>(node->getNumberOfSons());
+
+    for (int n = (node->hasFather() ? -1 : 0); n < nbSons; n++)
+    {
+      const Node* neighbor = (*node)[n];
+      vector<Bitset>* neighborData_bitsets       = &nodeData->getBitsetsArrayForNeighbor(neighbor->getId());
+      vector<unsigned int>* neighborData_scores  = &nodeData->getScoresArrayForNeighbor(neighbor->getId());
+
+      neighborData_bitsets->resize(nbDistinctSites_);
+      neighborData_scores->resize(nbDistinctSites_);
+    }
+  }
+
+  // We initialize each son node:
+  size_t nbSonNodes = node->getNumberOfSons();
+  for (unsigned int l = 0; l < nbSonNodes; l++)
+  {
+    // For each son node,
+    init(node->getSon(l), sites, stateMap);
+  }
+}
+
+/******************************************************************************/
+void DRTreeParsimonyData::reInit() throw (Exception)
+{
+  reInit(getTreeP_()->getRootNode());
+}
+
+/******************************************************************************/
+void DRTreeParsimonyData::reInit(const Node* node) throw (Exception)
+{
+  if (node->isLeaf())
+  {
+    return;
+  }
+  else
+  {
+    DRTreeParsimonyNodeData* nodeData = &nodeData_[node->getId()];
+    nodeData->setNode(node);
+    nodeData->eraseNeighborArrays();
+
+    int nbSons = static_cast<int>(node->getNumberOfSons());
+
+    for (int n = (node->hasFather() ? -1 : 0); n < nbSons; n++)
+    {
+      const Node* neighbor = (*node)[n];
+      vector<Bitset>* neighborData_bitsets       = &nodeData->getBitsetsArrayForNeighbor(neighbor->getId());
+      vector<unsigned int>* neighborData_scores  = &nodeData->getScoresArrayForNeighbor(neighbor->getId());
+
+      neighborData_bitsets->resize(nbDistinctSites_);
+      neighborData_scores->resize(nbDistinctSites_);
+    }
+  }
+
+  // We initialize each son node:
+  size_t nbSonNodes = node->getNumberOfSons();
+  for (unsigned int l = 0; l < nbSonNodes; l++)
+  {
+    // For each son node,
+    reInit(node->getSon(l));
+  }
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Parsimony/DRTreeParsimonyData.h b/src/Bpp/Phyl/Parsimony/DRTreeParsimonyData.h
new file mode 100644
index 0000000..5658f29
--- /dev/null
+++ b/src/Bpp/Phyl/Parsimony/DRTreeParsimonyData.h
@@ -0,0 +1,317 @@
+//
+// File: DRTreeParsimonyData.h
+// Created by: Julien Dutheil
+// Created on: Tue Jan 09 17:15 2007
+// From file DRTreeParsimonyScore.h
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _DRTREEPARSIMONYDATA_H_
+#define _DRTREEPARSIMONYDATA_H_
+
+#include "AbstractTreeParsimonyData.h"
+#include "../Model/StateMap.h"
+
+// From SeqLib
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+// From the STL:
+#include <bitset>
+
+namespace bpp
+{
+typedef std::bitset<21> Bitset; // 20AA + gaps, codon not lalowed so far :s
+
+/**
+ * @brief Parsimony data structure for a node.
+ *
+ * This class is for use with the DRTreeParsimonyData class.
+ *
+ * Store for each neighbor node
+ * - a vector of bitsets,
+ * - a vector of score for the corresponding subtree.
+ *
+ * @see DRTreeParsimonyData
+ */
+class DRTreeParsimonyNodeData :
+  public TreeParsimonyNodeData
+{
+private:
+  mutable std::map<int, std::vector<Bitset> > nodeBitsets_;
+  mutable std::map<int, std::vector<unsigned int> > nodeScores_;
+  const Node* node_;
+
+public:
+  DRTreeParsimonyNodeData() :
+    nodeBitsets_(),
+    nodeScores_(),
+    node_(0)
+  {}
+
+  DRTreeParsimonyNodeData(const DRTreeParsimonyNodeData& tpnd) :
+    nodeBitsets_(tpnd.nodeBitsets_),
+    nodeScores_(tpnd.nodeScores_),
+    node_(tpnd.node_)
+  {}
+
+  DRTreeParsimonyNodeData& operator=(const DRTreeParsimonyNodeData& tpnd)
+  {
+    nodeBitsets_ = tpnd.nodeBitsets_;
+    nodeScores_  = tpnd.nodeScores_;
+    node_        = tpnd.node_;
+    return *this;
+  }
+
+  DRTreeParsimonyNodeData* clone() const { return new DRTreeParsimonyNodeData(*this); }
+
+public:
+  const Node* getNode() const { return node_; }
+
+  void setNode(const Node* node) { node_ = node; }
+
+  std::vector<Bitset>& getBitsetsArrayForNeighbor(int neighborId)
+  {
+    return nodeBitsets_[neighborId];
+  }
+  const std::vector<Bitset>& getBitsetsArrayForNeighbor(int neighborId) const
+  {
+    return nodeBitsets_[neighborId];
+  }
+  std::vector<unsigned int>& getScoresArrayForNeighbor(int neighborId)
+  {
+    return nodeScores_[neighborId];
+  }
+  const std::vector<unsigned int>& getScoresArrayForNeighbor(int neighborId) const
+  {
+    return nodeScores_[neighborId];
+  }
+
+  bool isNeighbor(int neighborId) const
+  {
+    return nodeBitsets_.find(neighborId) != nodeBitsets_.end();
+  }
+
+  void eraseNeighborArrays()
+  {
+    nodeBitsets_.erase(nodeBitsets_.begin(), nodeBitsets_.end());
+    nodeScores_.erase(nodeScores_.begin(), nodeScores_.end());
+  }
+};
+
+/**
+ * @brief Parsimony data structure for a leaf.
+ *
+ * This class is for use with the DRTreeParsimonyData class.
+ *
+ * Store the vector of bitsets associated to a leaf.
+ *
+ * @see DRTreeParsimonyData
+ */
+class DRTreeParsimonyLeafData :
+  public TreeParsimonyNodeData
+{
+private:
+  mutable std::vector<Bitset> leafBitsets_;
+  const Node* leaf_;
+
+public:
+  DRTreeParsimonyLeafData() :
+    leafBitsets_(),
+    leaf_(0)
+  {}
+
+  DRTreeParsimonyLeafData(const DRTreeParsimonyLeafData& tpld) :
+    leafBitsets_(tpld.leafBitsets_),
+    leaf_(tpld.leaf_)
+  {}
+
+  DRTreeParsimonyLeafData& operator=(const DRTreeParsimonyLeafData& tpld)
+  {
+    leafBitsets_ = tpld.leafBitsets_;
+    leaf_        = tpld.leaf_;
+    return *this;
+  }
+
+
+  DRTreeParsimonyLeafData* clone() const { return new DRTreeParsimonyLeafData(*this); }
+
+public:
+  const Node* getNode() const { return leaf_; }
+  void setNode(const Node* node) { leaf_ = node; }
+
+  std::vector<Bitset>& getBitsetsArray()
+  {
+    return leafBitsets_;
+  }
+  const std::vector<Bitset>& getBitsetsArray() const
+  {
+    return leafBitsets_;
+  }
+};
+
+/**
+ * @brief Parsimony data structure for double-recursive (DR) algorithm.
+ *
+ * States are coded using bitsets for faster computing (@see AbstractTreeParsimonyData).
+ * For each inner node in the tree, we store a DRTreeParsimonyNodeData object in nodeData_.
+ * For each leaf node in the tree, we store a DRTreeParsimonyLeafData object in leafData_.
+ *
+ * The dataset is first compressed, removing all identical sites.
+ * The resulting dataset is stored in shrunkData_.
+ * The corresponding positions are stored in rootPatternLinks_, inherited from AbstractTreeParsimonyData.
+ */
+class DRTreeParsimonyData :
+  public AbstractTreeParsimonyData
+{
+private:
+  mutable std::map<int, DRTreeParsimonyNodeData> nodeData_;
+  mutable std::map<int, DRTreeParsimonyLeafData> leafData_;
+  mutable std::vector<Bitset> rootBitsets_;
+  mutable std::vector<unsigned int> rootScores_;
+  SiteContainer* shrunkData_;
+  size_t nbSites_;
+  size_t nbStates_;
+  size_t nbDistinctSites_;
+
+public:
+  DRTreeParsimonyData(const TreeTemplate<Node>* tree) :
+    AbstractTreeParsimonyData(tree),
+    nodeData_(),
+    leafData_(),
+    rootBitsets_(),
+    rootScores_(),
+    shrunkData_(0),
+    nbSites_(0),
+    nbStates_(0),
+    nbDistinctSites_(0)
+  {}
+
+  DRTreeParsimonyData(const DRTreeParsimonyData& data);
+
+  DRTreeParsimonyData& operator=(const DRTreeParsimonyData& data);
+
+  virtual ~DRTreeParsimonyData() { delete shrunkData_; }
+
+  DRTreeParsimonyData* clone() const { return new DRTreeParsimonyData(*this); }
+
+public:
+  /**
+   * @brief Set the tree associated to the data.
+   *
+   * All node data will be actualized accordingly by calling the setNode() method on the corresponding nodes.
+   * @warning: the old tree and the new tree must be two clones! And particularly, they have to share the
+   * same topology and nodes id.
+   *
+   * @param tree The tree to be associated to this data.
+   */
+  void setTree(const TreeTemplate<Node>* tree)
+  {
+    AbstractTreeParsimonyData::setTreeP_(tree);
+    for (std::map<int, DRTreeParsimonyNodeData>::iterator it = nodeData_.begin(); it != nodeData_.end(); it++)
+    {
+      int id = it->second.getNode()->getId();
+      it->second.setNode(tree_->getNode(id));
+    }
+    for (std::map<int, DRTreeParsimonyLeafData>::iterator it = leafData_.begin(); it != leafData_.end(); it++)
+    {
+      int id = it->second.getNode()->getId();
+      it->second.setNode(tree_->getNode(id));
+    }
+  }
+
+  DRTreeParsimonyNodeData& getNodeData(int nodeId)
+  {
+    return nodeData_[nodeId];
+  }
+  const DRTreeParsimonyNodeData& getNodeData(int nodeId) const
+  {
+    return nodeData_[nodeId];
+  }
+
+  DRTreeParsimonyLeafData& getLeafData(int nodeId)
+  {
+    return leafData_[nodeId];
+  }
+  const DRTreeParsimonyLeafData& getLeafData(int nodeId) const
+  {
+    return leafData_[nodeId];
+  }
+
+  std::vector<Bitset>& getBitsetsArray(int nodeId, int neighborId)
+  {
+    return nodeData_[nodeId].getBitsetsArrayForNeighbor(neighborId);
+  }
+  const std::vector<Bitset>& getBitsetsArray(int nodeId, int neighborId) const
+  {
+    return nodeData_[nodeId].getBitsetsArrayForNeighbor(neighborId);
+  }
+
+  std::vector<unsigned int>& getScoresArray(int nodeId, int neighborId)
+  {
+    return nodeData_[nodeId].getScoresArrayForNeighbor(neighborId);
+  }
+  const std::vector<unsigned int>& getScoresArray(int nodeId, int neighborId) const
+  {
+    return nodeData_[nodeId].getScoresArrayForNeighbor(neighborId);
+  }
+
+  size_t getArrayPosition(int parentId, int sonId, size_t currentPosition) const
+  {
+    return currentPosition;
+  }
+
+  std::vector<Bitset>& getRootBitsets() { return rootBitsets_; }
+  const std::vector<Bitset>& getRootBitsets() const { return rootBitsets_; }
+  const Bitset& getRootBitset(size_t i) const { return rootBitsets_[i]; }
+
+  std::vector<unsigned int>& getRootScores() { return rootScores_; }
+  const std::vector<unsigned int>& getRootScores() const { return rootScores_; }
+  unsigned int getRootScore(size_t i) const { return rootScores_[i]; }
+
+  size_t getNumberOfDistinctSites() const { return nbDistinctSites_; }
+  size_t getNumberOfSites() const { return nbSites_; }
+  size_t getNumberOfStates() const { return nbStates_; }
+
+  void init(const SiteContainer& sites, const StateMap& stateMap) throw (Exception);
+  void reInit() throw (Exception);
+
+protected:
+  void init(const Node* node, const SiteContainer& sites, const StateMap& stateMap) throw (Exception);
+  void reInit(const Node* node) throw (Exception);
+};
+} // end of namespace bpp.
+
+#endif // _DRTREEPARSIMONYDATA_H_
+
diff --git a/src/Bpp/Phyl/Parsimony/DRTreeParsimonyScore.cpp b/src/Bpp/Phyl/Parsimony/DRTreeParsimonyScore.cpp
new file mode 100755
index 0000000..55280ec
--- /dev/null
+++ b/src/Bpp/Phyl/Parsimony/DRTreeParsimonyScore.cpp
@@ -0,0 +1,405 @@
+//
+// File: DRTreeParsimonyScore.cpp
+// Created by: Julien Dutheil
+// Created on: Thu Jul 28 17:25 2005
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "DRTreeParsimonyScore.h"
+#include "../PatternTools.h"
+#include "../TreeTemplateTools.h" // Needed for NNIs
+
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+DRTreeParsimonyScore::DRTreeParsimonyScore(
+  const Tree& tree,
+  const SiteContainer& data,
+  bool verbose,
+  bool includeGaps)
+throw (Exception) :
+  AbstractTreeParsimonyScore(tree, data, verbose, includeGaps),
+  parsimonyData_(new DRTreeParsimonyData(getTreeP_())),
+  nbDistinctSites_()
+{
+  init_(data, verbose);
+}
+
+DRTreeParsimonyScore::DRTreeParsimonyScore(
+  const Tree& tree,
+  const SiteContainer& data,
+  const StateMap* statesMap,
+  bool verbose)
+throw (Exception) :
+  AbstractTreeParsimonyScore(tree, data, statesMap, verbose),
+  parsimonyData_(new DRTreeParsimonyData(getTreeP_())),
+  nbDistinctSites_()
+{
+  init_(data, verbose);
+}
+
+void DRTreeParsimonyScore::init_(const SiteContainer& data, bool verbose)
+{
+  if (verbose)
+    ApplicationTools::displayTask("Initializing data structure");
+  parsimonyData_->init(data, getStateMap());
+  nbDistinctSites_ = parsimonyData_->getNumberOfDistinctSites();
+  computeScores();
+  if (verbose)
+    ApplicationTools::displayTaskDone();
+  if (verbose)
+    ApplicationTools::displayResult("Number of distinct sites",
+                                    TextTools::toString(nbDistinctSites_));
+}
+
+/******************************************************************************/
+
+DRTreeParsimonyScore::DRTreeParsimonyScore(const DRTreeParsimonyScore& tp) :
+  AbstractTreeParsimonyScore(tp),
+  parsimonyData_(dynamic_cast<DRTreeParsimonyData*>(tp.parsimonyData_->clone())),
+  nbDistinctSites_(tp.nbDistinctSites_)
+{
+  parsimonyData_->setTree(getTreeP_());
+}
+
+/******************************************************************************/
+
+DRTreeParsimonyScore& DRTreeParsimonyScore::operator=(const DRTreeParsimonyScore& tp)
+{
+  AbstractTreeParsimonyScore::operator=(tp);
+  parsimonyData_ = dynamic_cast<DRTreeParsimonyData*>(tp.parsimonyData_->clone());
+  parsimonyData_->setTree(getTreeP_());
+  nbDistinctSites_ = tp.nbDistinctSites_;
+  return *this;
+}
+
+/******************************************************************************/
+
+DRTreeParsimonyScore::~DRTreeParsimonyScore()
+{
+  delete parsimonyData_;
+}
+
+/******************************************************************************/
+void DRTreeParsimonyScore::computeScores()
+{
+  computeScoresPostorder(getTreeP_()->getRootNode());
+  computeScoresPreorder(getTreeP_()->getRootNode());
+  computeScoresForNode(
+    parsimonyData_->getNodeData(getTree().getRootId()),
+    parsimonyData_->getRootBitsets(),
+    parsimonyData_->getRootScores());
+}
+
+void DRTreeParsimonyScore::computeScoresPostorder(const Node* node)
+{
+  if (node->isLeaf()) return;
+  DRTreeParsimonyNodeData* pData = &parsimonyData_->getNodeData(node->getId());
+  for (unsigned int k = 0; k < node->getNumberOfSons(); k++)
+  {
+    const Node* son = node->getSon(k);
+    computeScoresPostorder(son);
+    vector<Bitset>* bitsets      = &pData->getBitsetsArrayForNeighbor(son->getId());
+    vector<unsigned int>* scores = &pData->getScoresArrayForNeighbor(son->getId());
+    if (son->isLeaf())
+    {
+      // son has no NodeData associated, must use LeafData instead
+      vector<Bitset>* sonBitsets = &parsimonyData_->getLeafData(son->getId()).getBitsetsArray();
+      for (unsigned int i = 0; i < sonBitsets->size(); i++)
+      {
+        (*bitsets)[i] = (*sonBitsets)[i];
+        (*scores)[i]  = 0;
+      }
+    }
+    else
+    {
+      computeScoresPostorderForNode(
+        parsimonyData_->getNodeData(son->getId()),
+        *bitsets,
+        *scores);
+    }
+  }
+}
+
+void DRTreeParsimonyScore::computeScoresPostorderForNode(const DRTreeParsimonyNodeData& pData, vector<Bitset>& rBitsets, vector<unsigned int>& rScores)
+{
+  // First initialize the vectors from input:
+  const Node* node = pData.getNode();
+  const Node* source = node->getFather();
+  vector<const Node*> neighbors = node->getNeighbors();
+  size_t nbNeighbors = node->degree();
+  vector< const vector<Bitset>*> iBitsets;
+  vector< const vector<unsigned int>*> iScores;
+  for (unsigned int k = 0; k < nbNeighbors; k++)
+  {
+    const Node* n = neighbors[k];
+    if (n != source)
+    {
+      iBitsets.push_back(&pData.getBitsetsArrayForNeighbor(n->getId()));
+      iScores.push_back(&pData.getScoresArrayForNeighbor(n->getId()));
+    }
+  }
+  // Then call the general method on these arrays:
+  computeScoresFromArrays(iBitsets, iScores, rBitsets, rScores);
+}
+
+void DRTreeParsimonyScore::computeScoresPreorder(const Node* node)
+{
+  if (node->getNumberOfSons() == 0) return;
+  DRTreeParsimonyNodeData* pData = &parsimonyData_->getNodeData(node->getId());
+  if (node->hasFather())
+  {
+    const Node* father = node->getFather();
+    vector<Bitset>* bitsets      = &pData->getBitsetsArrayForNeighbor(father->getId());
+    vector<unsigned int>* scores = &pData->getScoresArrayForNeighbor(father->getId());
+    if (father->isLeaf())
+    { // Means that the tree is rooted by a leaf... dunno if we must allow that! Let it be for now.
+      // son has no NodeData associated, must use LeafData instead
+      vector<Bitset>* sonBitsets = &parsimonyData_->getLeafData(father->getId()).getBitsetsArray();
+      for (unsigned int i = 0; i < sonBitsets->size(); i++)
+      {
+        (*bitsets)[i] = (*sonBitsets)[i];
+        (*scores)[i]  = 0;
+      }
+    }
+    else
+    {
+      computeScoresPreorderForNode(
+        parsimonyData_->getNodeData(father->getId()),
+        node,
+        *bitsets,
+        *scores);
+    }
+  }
+  // Recurse call:
+  for (unsigned int k = 0; k < node->getNumberOfSons(); k++)
+  {
+    computeScoresPreorder(node->getSon(k));
+  }
+}
+
+void DRTreeParsimonyScore::computeScoresPreorderForNode(const DRTreeParsimonyNodeData& pData, const Node* source, std::vector<Bitset>& rBitsets, std::vector<unsigned int>& rScores)
+{
+  // First initialize the vectors from input:
+  const Node* node = pData.getNode();
+  vector<const Node*> neighbors = node->getNeighbors();
+  size_t nbNeighbors = node->degree();
+  vector< const vector<Bitset>*> iBitsets;
+  vector< const vector<unsigned int>*> iScores;
+  for (unsigned int k = 0; k < nbNeighbors; k++)
+  {
+    const Node* n = neighbors[k];
+    if (n != source)
+    {
+      iBitsets.push_back(&pData.getBitsetsArrayForNeighbor(n->getId()));
+      iScores.push_back(&pData.getScoresArrayForNeighbor(n->getId()));
+    }
+  }
+  // Then call the general method on these arrays:
+  computeScoresFromArrays(iBitsets, iScores, rBitsets, rScores);
+}
+
+void DRTreeParsimonyScore::computeScoresForNode(const DRTreeParsimonyNodeData& pData, std::vector<Bitset>& rBitsets, std::vector<unsigned int>& rScores)
+{
+  const Node* node = pData.getNode();
+  size_t nbNeighbors = node->degree();
+  vector<const Node*> neighbors = node->getNeighbors();
+  // First initialize the vectors fro input:
+  vector< const vector<Bitset>*> iBitsets(nbNeighbors);
+  vector< const vector<unsigned int>*> iScores(nbNeighbors);
+  for (unsigned int k = 0; k < nbNeighbors; k++)
+  {
+    const Node* n = neighbors[k];
+    iBitsets[k] =  &pData.getBitsetsArrayForNeighbor(n->getId());
+    iScores [k] =  &pData.getScoresArrayForNeighbor(n->getId());
+  }
+  // Then call the general method on these arrays:
+  computeScoresFromArrays(iBitsets, iScores, rBitsets, rScores);
+}
+
+/******************************************************************************/
+unsigned int DRTreeParsimonyScore::getScore() const
+{
+  unsigned int score = 0;
+  for (unsigned int i = 0; i < nbDistinctSites_; i++)
+  {
+    score += parsimonyData_->getRootScore(i) * parsimonyData_->getWeight(i);
+  }
+  return score;
+}
+
+/******************************************************************************/
+unsigned int DRTreeParsimonyScore::getScoreForSite(size_t site) const
+{
+  return parsimonyData_->getRootScore(parsimonyData_->getRootArrayPosition(site));
+}
+
+/******************************************************************************/
+void DRTreeParsimonyScore::computeScoresFromArrays(
+  const vector< const vector<Bitset>*>& iBitsets,
+  const vector< const vector<unsigned int>*>& iScores,
+  vector<Bitset>& oBitsets,
+  vector<unsigned int>& oScores)
+{
+  size_t nbPos  = oBitsets.size();
+  size_t nbNodes = iBitsets.size();
+  if (iScores.size() != nbNodes)
+    throw Exception("DRTreeParsimonyScore::computeScores(); Error, input arrays must have the same length.");
+  if (nbNodes < 1)
+    throw Exception("DRTreeParsimonyScore::computeScores(); Error, input arrays must have a size >= 1.");
+  const vector<Bitset>* bitsets0 = iBitsets[0];
+  const vector<unsigned int>* scores0 = iScores[0];
+  for (size_t i = 0; i < nbPos; i++)
+  {
+    oBitsets[i] = (*bitsets0)[i];
+    oScores[i]  = (*scores0)[i];
+  }
+  for (size_t k = 1; k < nbNodes; k++)
+  {
+    const vector<Bitset>* bitsetsk = iBitsets[k];
+    const vector<unsigned int>* scoresk = iScores[k];
+    for (unsigned int i = 0; i < nbPos; i++)
+    {
+      Bitset bs = oBitsets[i] & (*bitsetsk)[i];
+      oScores[i] += (*scoresk)[i];
+      if (bs == 0)
+      {
+        bs = oBitsets[i] | (*bitsetsk)[i];
+        oScores[i] += 1;
+      }
+      oBitsets[i] = bs;
+    }
+  }
+}
+
+/******************************************************************************/
+double DRTreeParsimonyScore::testNNI(int nodeId) const throw (NodeException)
+{
+  const Node* son = getTreeP_()->getNode(nodeId);
+  if (!son->hasFather()) throw NodePException("DRTreeParsimonyScore::testNNI(). Node 'son' must not be the root node.", son);
+  const Node* parent = son->getFather();
+  if (!parent->hasFather()) throw NodePException("DRTreeParsimonyScore::testNNI(). Node 'parent' must not be the root node.", parent);
+  const Node* grandFather = parent->getFather();
+  // From here: Bifurcation assumed.
+  // In case of multifurcation, an arbitrary uncle is chosen.
+  // If we are at root node with a trifurcation, this does not matter, since 2 NNI are possible (see doc of the NNISearchable interface).
+  size_t parentPosition = grandFather->getSonPosition(parent);
+  const Node* uncle = grandFather->getSon(parentPosition > 1 ? parentPosition - 1 : 1 - parentPosition);
+
+  // Retrieving arrays of interest:
+  const DRTreeParsimonyNodeData* parentData = &parsimonyData_->getNodeData(parent->getId());
+  const vector<Bitset>* sonBitsets = &parentData->getBitsetsArrayForNeighbor(son->getId());
+  const vector<unsigned int>* sonScores  = &parentData->getScoresArrayForNeighbor(son->getId());
+  vector<const Node*> parentNeighbors = TreeTemplateTools::getRemainingNeighbors(parent, grandFather, son);
+  size_t nbParentNeighbors = parentNeighbors.size();
+  vector< const vector<Bitset>*> parentBitsets(nbParentNeighbors);
+  vector< const vector<unsigned int>*> parentScores(nbParentNeighbors);
+  for (unsigned int k = 0; k < nbParentNeighbors; k++)
+  {
+    const Node* n = parentNeighbors[k]; // This neighbor
+    parentBitsets[k] = &parentData->getBitsetsArrayForNeighbor(n->getId());
+    parentScores[k] = &parentData->getScoresArrayForNeighbor(n->getId());
+  }
+
+  const DRTreeParsimonyNodeData* grandFatherData = &parsimonyData_->getNodeData(grandFather->getId());
+  const vector<Bitset>* uncleBitsets = &grandFatherData->getBitsetsArrayForNeighbor(uncle->getId());
+  const vector<unsigned int>* uncleScores  = &grandFatherData->getScoresArrayForNeighbor(uncle->getId());
+  vector<const Node*> grandFatherNeighbors = TreeTemplateTools::getRemainingNeighbors(grandFather, parent, uncle);
+  size_t nbGrandFatherNeighbors = grandFatherNeighbors.size();
+  vector< const vector<Bitset>*> grandFatherBitsets(nbGrandFatherNeighbors);
+  vector< const vector<unsigned int>*> grandFatherScores(nbGrandFatherNeighbors);
+  for (unsigned int k = 0; k < nbGrandFatherNeighbors; k++)
+  {
+    const Node* n = grandFatherNeighbors[k]; // This neighbor
+    grandFatherBitsets[k] = &grandFatherData->getBitsetsArrayForNeighbor(n->getId());
+    grandFatherScores[k] = &grandFatherData->getScoresArrayForNeighbor(n->getId());
+  }
+
+  // Compute arrays and scores for grand-father node:
+  grandFatherBitsets.push_back(sonBitsets);
+  grandFatherScores.push_back(sonScores);
+  // Init arrays:
+  vector<Bitset> gfBitsets(sonBitsets->size()); // All arrays supposed to have the same size!
+  vector<unsigned int> gfScores(sonScores->size());
+  // Fill arrays:
+  computeScoresFromArrays(grandFatherBitsets, grandFatherScores, gfBitsets, gfScores);
+
+  // Now computes arrays and scores for parent node:
+  parentBitsets.push_back(uncleBitsets);
+  parentScores.push_back(uncleScores);
+  parentBitsets.push_back(&gfBitsets);
+  parentScores.push_back(&gfScores);
+  // Init arrays:
+  vector<Bitset> pBitsets(sonBitsets->size()); // All arrays supposed to have the same size!
+  vector<unsigned int> pScores(sonScores->size());
+  // Fill arrays:
+  computeScoresFromArrays(parentBitsets, parentScores, pBitsets, pScores);
+
+  // Final computation:
+  unsigned int score = 0;
+  for (unsigned int i = 0; i < nbDistinctSites_; i++)
+  {
+    score += pScores[i] * parsimonyData_->getWeight(i);
+  }
+  return (double)score - (double)getScore();
+}
+
+/******************************************************************************/
+void DRTreeParsimonyScore::doNNI(int nodeId) throw (NodeException)
+{
+  Node* son = getTreeP_()->getNode(nodeId);
+  if (!son->hasFather()) throw NodePException("DRTreeParsimonyScore::doNNI(). Node 'son' must not be the root node.", son);
+  Node* parent = son->getFather();
+  if (!parent->hasFather()) throw NodePException("DRTreeParsimonyScore::doNNI(). Node 'parent' must not be the root node.", parent);
+  Node* grandFather = parent->getFather();
+  // From here: Bifurcation assumed.
+  // In case of multifurcation, an arbitrary uncle is chosen.
+  // If we are at root node with a trifurcation, this does not matter, since 2 NNI are possible (see doc of the NNISearchable interface).
+  size_t parentPosition = grandFather->getSonPosition(parent);
+  Node* uncle = grandFather->getSon(parentPosition > 1 ? parentPosition - 1 : 1 - parentPosition);
+  // Swap nodes:
+  parent->removeSon(son);
+  grandFather->removeSon(uncle);
+  parent->addSon(uncle);
+  grandFather->addSon(son);
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Parsimony/DRTreeParsimonyScore.h b/src/Bpp/Phyl/Parsimony/DRTreeParsimonyScore.h
new file mode 100755
index 0000000..690b44a
--- /dev/null
+++ b/src/Bpp/Phyl/Parsimony/DRTreeParsimonyScore.h
@@ -0,0 +1,195 @@
+//
+// File: DRTreeParsimonyScore.h
+// Created by: Julien Dutheil
+// Created on: Thu Jul 28 18:31 2005
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _DRTREEPARSIMONYSCORE_H_
+#define _DRTREEPARSIMONYSCORE_H_
+
+#include "AbstractTreeParsimonyScore.h"
+#include "DRTreeParsimonyData.h"
+#include "../NNISearchable.h"
+#include "../TreeTools.h"
+
+namespace bpp
+{
+/**
+ * @brief Double recursive implementation of interface TreeParsimonyScore.
+ *
+ * Uses a DRTreeParsimonyData object for data storage.
+ */
+class DRTreeParsimonyScore :
+  public AbstractTreeParsimonyScore,
+  public virtual NNISearchable
+{
+private:
+  DRTreeParsimonyData* parsimonyData_;
+  size_t nbDistinctSites_;
+
+public:
+  DRTreeParsimonyScore(
+    const Tree& tree,
+    const SiteContainer& data,
+    bool verbose = true,
+    bool includeGaps = false)
+  throw (Exception);
+
+  DRTreeParsimonyScore(
+    const Tree& tree,
+    const SiteContainer& data,
+    const StateMap* statesMap,
+    bool verbose = true)
+  throw (Exception);
+
+  DRTreeParsimonyScore(const DRTreeParsimonyScore& tp);
+
+  DRTreeParsimonyScore& operator=(const DRTreeParsimonyScore& tp);
+
+  virtual ~DRTreeParsimonyScore();
+
+#ifndef NO_VIRTUAL_COV
+  DRTreeParsimonyScore*
+#else
+  Clonable*
+#endif
+  clone() const { return new DRTreeParsimonyScore(*this); }
+
+private:
+  void init_(const SiteContainer& data, bool verbose);
+
+protected:
+  /**
+   * @brief Compute all scores.
+   *
+   * Call the computeScoresPreorder and computeScoresPostorder methods, and then initialize rootBitsets_ and rootScores_.
+   */
+  virtual void computeScores();
+  /**
+   * @brief Compute scores (preorder algorithm).
+   */
+  virtual void computeScoresPreorder(const Node*);
+  /**
+   * @brief Compute scores (postorder algorithm).
+   */
+  virtual void computeScoresPostorder(const Node*);
+
+public:
+  unsigned int getScore() const;
+  unsigned int getScoreForSite(size_t site) const;
+
+  /**
+   * @brief Compute bitsets and scores for each site for a node, in postorder.
+   *
+   * @param pData    The node data to use.
+   * @param rBitsets The bitset array where to store the resulting bitsets.
+   * @param rScores  The score array where to write the resulting scores.
+   */
+  static void computeScoresPostorderForNode(
+    const DRTreeParsimonyNodeData& pData,
+    std::vector<Bitset>& rBitsets,
+    std::vector<unsigned int>& rScores);
+
+  /**
+   * @brief Compute bitsets and scores for each site for a node, in preorder.
+   *
+   * @param pData    The node data to use.
+   * @param source   The node where we are coming from.
+   * @param rBitsets The bitset array where to store the resulting bitsets.
+   * @param rScores  The score array where to write the resulting scores.
+   */
+  static void computeScoresPreorderForNode(
+    const DRTreeParsimonyNodeData& pData,
+    const Node* source,
+    std::vector<Bitset>& rBitsets,
+    std::vector<unsigned int>& rScores);
+
+  /**
+   * @brief Compute bitsets and scores for each site for a node, in all directions.
+   *
+   * @param pData    The node data to use.
+   * @param rBitsets The bitset array where to store the resulting bitsets.
+   * @param rScores  The score array where to write the resulting scores.
+   */
+  static void computeScoresForNode(
+    const DRTreeParsimonyNodeData& pData, std::vector<Bitset>& rBitsets,
+    std::vector<unsigned int>& rScores);
+
+  /**
+   * @brief Compute bitsets and scores from an array of arrays.
+   *
+   * This method is the more general score computation.
+   * Depending on what is passed as input, it may computes scroes fo a subtree
+   * or the whole tree.
+   *
+   * @param iBitsets The vector of bitset arrays to use.
+   * @param iScores  The vector of score arrays to use.
+   * @param oBitsets The bitset array where to store the resulting bitsets.
+   * @param oScores  The score array where to write the resulting scores.
+   */
+  static void computeScoresFromArrays(
+    const std::vector<const std::vector<Bitset>*>& iBitsets,
+    const std::vector<const std::vector<unsigned int>*>& iScores,
+    std::vector<Bitset>& oBitsets,
+    std::vector<unsigned int>& oScores);
+
+  /**
+   * @name Thee NNISearchable interface.
+   *
+   * @{
+   */
+  double getTopologyValue() const throw (Exception) { return getScore(); }
+
+  double testNNI(int nodeId) const throw (NodeException);
+
+  void doNNI(int nodeId) throw (NodeException);
+
+  // Tree& getTopology() { return getTree(); } do we realy need this one?
+  const Tree& getTopology() const { return getTree(); }
+
+  void topologyChangeTested(const TopologyChangeEvent& event)
+  {
+    parsimonyData_->reInit();
+    computeScores();
+  }
+
+  void topologyChangeSuccessful(const TopologyChangeEvent& event) {}
+  /**@} */
+};
+} // end of namespace bpp.
+
+#endif // _DRTREEPARSIMONYSCORE_H_
+
diff --git a/src/Bpp/Phyl/Parsimony/TreeParsimonyData.h b/src/Bpp/Phyl/Parsimony/TreeParsimonyData.h
new file mode 100644
index 0000000..71b7c66
--- /dev/null
+++ b/src/Bpp/Phyl/Parsimony/TreeParsimonyData.h
@@ -0,0 +1,115 @@
+//
+// File: TreeParsimonyData.h
+// Created by: Julien Dutheil
+// Created on: Tue Jan 09 17:15 2007
+// From file AbstractTreeParsimonyScore.h
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _TREEPARSIMONYDATA_H_
+#define _TREEPARSIMONYDATA_H_
+
+#include "../Node.h"
+#include "../TreeTemplate.h"
+
+#include <Bpp/Clonable.h>
+
+namespace bpp
+{
+/**
+ * @brief TreeParsimonyScore node data structure.
+ *
+ * Stores inner computation for a given node.
+ *
+ * @see TreeParsimonyData
+ */
+class TreeParsimonyNodeData :
+  public virtual Clonable
+{
+public:
+  TreeParsimonyNodeData() {}
+  virtual ~TreeParsimonyNodeData() {}
+
+#ifndef NO_VIRTUAL_COV
+  TreeParsimonyNodeData* clone() const = 0;
+#endif
+
+public:
+  /**
+   * @brief Get the node associated to this data structure.
+   *
+   * @return The node associated to this structure.
+   */
+  virtual const Node* getNode() const = 0;
+
+  /**
+   * @brief Set the node associated to this data
+   *
+   * @param node A pointer toward the node to be associated to this data.
+   */
+  virtual void setNode(const Node* node) = 0;
+};
+
+/**
+ * @brief TreeParsimonyScore data structure.
+ *
+ * Stores all the inner computations:
+ * - subtree scores and ancestral states for each node,
+ * - correspondance between sites in the dataset and array indices.
+ *
+ * @see TreeParsimonyNodeData
+ */
+class TreeParsimonyData :
+  public virtual Clonable
+{
+public:
+  TreeParsimonyData() {}
+  virtual ~TreeParsimonyData() {}
+
+#ifndef NO_VIRTUAL_COV
+  TreeParsimonyData* clone() const = 0;
+#endif
+
+public:
+  virtual const TreeTemplate<Node>* getTree() const = 0;
+  virtual size_t getArrayPosition(int parentId, int sonId, size_t currentPosition) const = 0;
+  virtual size_t getRootArrayPosition(size_t site) const = 0;
+  virtual TreeParsimonyNodeData& getNodeData(int nodeId) = 0;
+  virtual const TreeParsimonyNodeData& getNodeData(int nodeId) const = 0;
+};
+} // end of namespace bpp.
+
+#endif // _TREEPARSIMONYDATA_H_
+
diff --git a/src/Bpp/Phyl/Parsimony/TreeParsimonyScore.h b/src/Bpp/Phyl/Parsimony/TreeParsimonyScore.h
new file mode 100755
index 0000000..6e60ade
--- /dev/null
+++ b/src/Bpp/Phyl/Parsimony/TreeParsimonyScore.h
@@ -0,0 +1,102 @@
+//
+// File: TreeParsimonyScore.h
+// Created by: Julien Dutheil
+// Created on: Thu Jul 28 17:15 2005
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _TREEPARSIMONYSCORE_H_
+#define _TREEPARSIMONYSCORE_H_
+
+#include "../TreeTemplate.h"
+
+#include <Bpp/Clonable.h>
+
+// From the STL:
+#include <vector>
+
+namespace bpp
+{
+/**
+ * @brief Compute a parsimony score.
+ */
+class TreeParsimonyScore :
+  public virtual Clonable
+{
+public:
+  TreeParsimonyScore() {}
+  virtual ~TreeParsimonyScore() {}
+
+#if defined(NO_VIRTUAL_COV)
+  Clonable* clone() const = 0;
+#else
+  TreeParsimonyScore* clone() const = 0;
+#endif
+
+public:
+  /**
+   * @brief Get the score for the current tree, i.e. the total minimum number of changes in the tree.
+   *
+   * @return The minimum total number of changes in the tree.
+   */
+  virtual unsigned int getScore() const = 0;
+
+  /**
+   * @brief Get the score for a given site for the current tree, i.e. the total minimum number of changes in the tree for this site.
+   *
+   * @param site The corresponding site.
+   * @return The minimum total number of changes in the tree for site 'site'.
+   */
+  virtual unsigned int getScoreForSite(size_t site) const = 0;
+
+  /**
+   * @brief Get the score for each site for the current tree, i.e. the total minimum number of changes in the tree for each site.
+   *
+   * @return The minimum total number of changes in the tree for each site.
+   */
+  virtual std::vector<unsigned int> getScoreForEachSite() const = 0;
+
+  /**
+   * @brief Get the tree for wich scores are computed.
+   *
+   * @return The tree associated to this object.
+   */
+  virtual const Tree& getTree() const = 0;
+};
+} // end of namespace bpp.
+
+#endif // _TREEPARSIMONYSCORE_H_
+
+
diff --git a/src/Bpp/Phyl/PatternTools.cpp b/src/Bpp/Phyl/PatternTools.cpp
new file mode 100755
index 0000000..37c4b29
--- /dev/null
+++ b/src/Bpp/Phyl/PatternTools.cpp
@@ -0,0 +1,130 @@
+//
+// File: PatternTools.cpp
+// Created by: Julien Dutheil
+// Created on: Thu Mar 20 13:36:54 2003
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "PatternTools.h"
+
+#include "TreeTemplateTools.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Container/VectorSiteContainer.h>
+#include <Bpp/Seq/SiteTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+#include <map>
+#include <algorithm>
+
+using namespace std;
+
+/******************************************************************************/
+
+SiteContainer* PatternTools::getSequenceSubset(const SiteContainer& sequenceSet, const Node& node) throw (Exception)
+{
+	VectorSiteContainer * sequenceSubset = new VectorSiteContainer(sequenceSet.getAlphabet());
+	vector<const Node *> leaves = TreeTemplateTools::getLeaves(node);
+	for (vector<const Node *>::iterator i = leaves.begin(); i < leaves.end(); i++)
+  {
+		const Sequence* newSeq = &sequenceSet.getSequence((* i)->getName());
+		if (newSeq == NULL) throw SequenceNotFoundException("PatternToolsERROR: leaf name not found in sequence file: ", (* i) -> getName());
+		sequenceSubset -> addSequence(* newSeq);
+	}
+	return sequenceSubset;
+}
+
+/******************************************************************************/
+
+SiteContainer* PatternTools::getSequenceSubset(const SiteContainer& sequenceSet, const vector<string>& names) throw (Exception)
+{
+	VectorSiteContainer* sequenceSubset = new VectorSiteContainer(sequenceSet.getAlphabet());
+	for (unsigned int i = 0; i < names.size(); i++)
+  {
+		const Sequence* newSeq = &sequenceSet.getSequence(names[i]);
+		if (!newSeq) throw SequenceNotFoundException("PatternTools ERROR: name not found in sequence file: ", names[i]);
+		sequenceSubset->addSequence(*newSeq);
+	}
+	return sequenceSubset;
+}
+
+/******************************************************************************/
+
+SiteContainer* PatternTools::shrinkSiteSet(const SiteContainer& siteSet) throw (Exception)
+{
+	if (siteSet.getNumberOfSites() == 0) throw Exception("PatternTools::shrinkSiteSet siteSet is void.");
+	vector<const Site *> sites;
+	for (unsigned int i = 0; i < siteSet.getNumberOfSites(); i++)
+  {
+		const Site* currentSite = &siteSet.getSite(i);
+		bool siteExists = false;
+		for (unsigned int j = 0; !siteExists && j < sites.size(); j++)
+    {
+			if (SiteTools::areSitesIdentical(* currentSite, * sites[j])) siteExists = true;
+		}
+		if (!siteExists)	sites.push_back(currentSite);
+	}
+	SiteContainer* result = new VectorSiteContainer(sites, siteSet.getAlphabet(), false); //We do not check positions here.
+	result->setSequencesNames(siteSet.getSequencesNames(), false);
+	return result;
+}
+
+/******************************************************************************/
+
+Vint PatternTools::getIndexes(const SiteContainer& sequences1, const SiteContainer& sequences2)
+{
+	size_t nbSites = sequences1.getNumberOfSites(); 
+	Vint indexes(nbSites);
+	for (size_t i = 0; i < nbSites; i++) {
+		//For each site in sequences1,
+		indexes[i] = -1;
+		const Site* site = &sequences1.getSite(i);
+		for (size_t j = 0; j < sequences2.getNumberOfSites(); j++)
+    {
+			if (SiteTools::areSitesIdentical(*site, sequences2.getSite(j)))
+      {
+				indexes[i] = static_cast<int>(j);
+				break;
+			}
+		}
+	}
+	return indexes;
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/PatternTools.h b/src/Bpp/Phyl/PatternTools.h
new file mode 100755
index 0000000..d63fe3f
--- /dev/null
+++ b/src/Bpp/Phyl/PatternTools.h
@@ -0,0 +1,108 @@
+//
+// File: PatternTools.h
+// Created by: Julien Dutheil
+// Created on: Thu Mar 20 13:36:53 2003
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+ 
+#ifndef _PATTERNTOOLS_H_
+#define _PATTERNTOOLS_H_
+
+#include "Tree.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+
+//From SeqLib:
+#include <Bpp/Seq/Site.h>
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+// From the STL:
+#include <map>
+
+namespace bpp
+{
+
+/**
+ * @brief Utilitary methods to compute site patterns.
+ *
+ * Theses methods are mainly designed to save computation in likelihood
+ * and parsimony methods.
+ */
+class PatternTools
+{
+	public:
+    /**
+     * @brief Extract the sequences corresponding to a given subtree.
+     *
+     * @param sequenceSet The container to look in.
+     * @param node        The root node of the subtree to check.
+     * @return A new site container with corresponding sequences.
+     * @throw Exception if an error occured.
+     */
+		static SiteContainer* getSequenceSubset(const SiteContainer& sequenceSet, const Node& node) throw (Exception);
+    /**
+     * @brief Extract the sequences corresponding to a given set of names.
+     *
+     * @param sequenceSet The container to look in.
+     * @param names       The names of the sequences to look for.
+     * @return A new site container with corresponding sequences.
+     * @throw Exception if an error occured.
+     */
+		static SiteContainer* getSequenceSubset(const SiteContainer& sequenceSet, const std::vector<std::string>& names) throw (Exception);
+		/**
+     * @brief Compress a site container by removing duplicated sites.
+     *
+     * @param sequenceSet The container to look in.
+     * @return A new site container with unique sites.
+     * @throw Exception if an error occured.
+     */
+    static SiteContainer* shrinkSiteSet(const SiteContainer& sequenceSet) throw (Exception);
+
+		/**
+     * @brief Look for the occurence of each site in sequences1 in sequences2 and send the
+     * position of the first occurence, or -1 if not found.
+     *
+     * @param sequences1 First container.
+     * @param sequences2 Second container.
+     * @return A vecotr of positions.
+     */
+		static Vint getIndexes(const SiteContainer& sequences1, const SiteContainer& sequences2);
+};
+
+
+} //end of namespace bpp.
+
+#endif	//_PATTERNTOOLS_H_
+
diff --git a/src/Bpp/Phyl/PhyloStatistics.cpp b/src/Bpp/Phyl/PhyloStatistics.cpp
new file mode 100644
index 0000000..e1079c1
--- /dev/null
+++ b/src/Bpp/Phyl/PhyloStatistics.cpp
@@ -0,0 +1,108 @@
+//
+// File: PHyloStatistics.cpp
+// Created by: Julien Dutheil
+// Created on: Sat Aug 08 07:29 2009
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include "PhyloStatistics.h"
+#include "TreeTemplate.h"
+#include "Node.h"
+
+using namespace bpp;
+using namespace std;
+
+void PhyloStatistics::setTree(const Tree& tree)
+{
+  const Tree* treeP = &tree;
+  const TreeTemplate<Node>* ttreeP = dynamic_cast<const TreeTemplate<Node>*>(treeP);
+  bool copy = false;
+  if (!ttreeP) 
+  {
+    ttreeP = new TreeTemplate<Node>(tree);
+    copy = true;
+  }
+
+  //Perform computations:
+  numberOfLeaves_ = 0;
+  numberOfAncestors_ = 0;
+  branchLengths_.clear();
+  nodeHeights_.clear();
+  nodeDepths_.clear();
+  nodeNumberOfSons_.clear();
+  nodeIds_.clear();
+  double h;
+  size_t d;
+  computeForSubtree_(ttreeP->getRootNode(), h, d);
+
+  if (copy) delete ttreeP;
+}
+
+void PhyloStatistics::computeForSubtree_(const Node* node, double& height, size_t& depth)
+{
+  if (node->isLeaf())
+    numberOfLeaves_++;
+  else
+    numberOfAncestors_++;
+
+  nodeNumberOfSons_.push_back(node->getNumberOfSons());
+  
+  height = 0;
+  depth = 0;
+  for (size_t i = 0; i < node->getNumberOfSons(); i++)
+  {
+    const Node* son = (*node)[static_cast<int>(i)];
+    double dist = 0;
+    if (son->hasDistanceToFather()) dist = son->getDistanceToFather();
+    else dist = 0;
+    double subHeight;
+    size_t subDepth;
+    computeForSubtree_(son, subHeight, subDepth);
+    subHeight += dist;
+    subDepth++;
+    if (subHeight > height) height = subHeight;
+    if (subDepth  > depth ) depth  = subDepth ;
+  }
+
+  if (node->hasDistanceToFather())
+    branchLengths_.push_back(node->getDistanceToFather());
+  else 
+    branchLengths_.push_back(log(0)); //-Inf if no branch length.
+
+  nodeHeights_.push_back(height);
+  nodeDepths_.push_back(depth);
+}
+
+
diff --git a/src/Bpp/Phyl/PhyloStatistics.h b/src/Bpp/Phyl/PhyloStatistics.h
new file mode 100644
index 0000000..4acc217
--- /dev/null
+++ b/src/Bpp/Phyl/PhyloStatistics.h
@@ -0,0 +1,109 @@
+//
+// File: PHyloStatistics.h
+// Created by: Julien Dutheil
+// Created on: Sat Aug 08 07:29 2009
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _PHYLOSTATISTICS_H_
+#define _PHYLOSTATISTICS_H_
+
+#include "Tree.h"
+
+#include <Bpp/Clonable.h>
+
+//From the STL:
+#include <vector>
+
+namespace bpp
+{
+  /**
+   *  @brief Compute several quantities on a tree simulateously, optimizing the recursions on the tree.
+   *  
+   *  This class uses a TreeTemplate. If the input tree is not a TreeTemplate, then a copy is performed
+   *  before any computation.
+   *
+   *  @see TreeTools, TreeTemplateTools.
+   */
+  class PhyloStatistics:
+    public virtual Clonable
+  {
+    private:
+      size_t numberOfLeaves_;
+      size_t numberOfAncestors_;
+      std::vector<double> branchLengths_;
+      std::vector<double> nodeHeights_;
+      std::vector<size_t> nodeDepths_;
+      std::vector<size_t> nodeNumberOfSons_;
+      std::vector<int> nodeIds_;
+
+    public:
+      PhyloStatistics() : 
+        numberOfLeaves_(0), numberOfAncestors_(0),
+        branchLengths_(), nodeHeights_(), nodeDepths_(), nodeNumberOfSons_(), nodeIds_()
+      {}
+      virtual ~PhyloStatistics() {}
+
+#ifndef NO_VIRTUAL_COV
+      Clonable*
+#else
+      PhyloStatistics*
+#endif
+      clone() const { return new PhyloStatistics(*this); }
+
+      /**
+       * @brief Compute statistics for a given input tree.
+       *
+       * @param tree The tree for which the statistics should be computed.
+       */
+      void setTree(const Tree& tree);
+
+      size_t getNumberOfLeaves() const { return numberOfLeaves_; }
+      size_t getNumberOfAncestors() const { return numberOfAncestors_; }
+      const std::vector<double>& getBranchLengths() const { return branchLengths_; }
+      const std::vector<double>& getNodeHeights() const { return nodeHeights_; }
+      const std::vector<size_t>& getNodeDepths() const { return nodeDepths_; }
+      const std::vector<size_t>& getNodeNumberOfSons() const { return nodeNumberOfSons_; }
+      const std::vector<int>& getNodeIds() const { return nodeIds_; }
+
+    private:
+      void computeForSubtree_(const Node* node, double& height, size_t& depth);
+
+  };
+
+} //end of namespace bpp.
+
+#endif //_PHYLOSTATISTICS_H_
+
diff --git a/src/Bpp/Phyl/Simulation/DetailedSiteSimulator.h b/src/Bpp/Phyl/Simulation/DetailedSiteSimulator.h
new file mode 100644
index 0000000..2a659cc
--- /dev/null
+++ b/src/Bpp/Phyl/Simulation/DetailedSiteSimulator.h
@@ -0,0 +1,250 @@
+//
+// File: DetailedSiteSimulator.h
+// Created by: Julien Dutheil
+// Created on: Tue Mar  14 10:51 2006
+// from old file DetailedSequenceSimulator.h
+// Created on: Wed Aug  24 15:20 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _DETAILEDSITESIMULATOR_H_
+#define _DETAILEDSITESIMULATOR_H_
+
+#include "SiteSimulator.h"
+#include "MutationProcess.h"
+#include "../TreeTemplate.h"
+
+// From the STL:
+#include <map>
+#include <vector>
+
+namespace bpp
+{
+
+/**
+ * @brief Data structure to store the result of a DetailedSiteSimulator.
+ *
+ * This data structure stores each transitional state, and the time when it occured.
+ */
+class SiteSimulationResult
+{
+  private:
+    mutable std::map<int, size_t> indexes_;
+    size_t currentIndex_;
+    std::vector<MutationPath> paths_;
+    std::vector<int> ancestralStates_;
+    const Tree* tree_;
+    std::vector<int> leavesId_;
+    const Alphabet* alphabet_;
+    
+  public:
+    SiteSimulationResult(const Tree* tree, const Alphabet* alphabet, int ancestralState) :
+      indexes_        (),
+      currentIndex_   (0),
+      paths_          (),
+      ancestralStates_(),
+      tree_           (tree),
+      leavesId_       (tree->getLeavesId()),
+      alphabet_       (alphabet)
+    {
+      indexes_[tree->getRootId()] = 0;
+      //Warning, watch out the indices there!
+      ancestralStates_.push_back(ancestralState);
+    }
+
+    SiteSimulationResult(const SiteSimulationResult& ssr) :
+      indexes_        (ssr.indexes_),
+      currentIndex_   (ssr.currentIndex_),
+      paths_          (ssr.paths_),
+      ancestralStates_(ssr.ancestralStates_),
+      tree_           (ssr.tree_),
+      leavesId_       (ssr.leavesId_),
+      alphabet_       (ssr.alphabet_)
+    {}
+ 
+    SiteSimulationResult& operator=(const SiteSimulationResult& ssr)
+    {
+      indexes_         = ssr.indexes_;
+      currentIndex_    = ssr.currentIndex_;
+      paths_           = ssr.paths_;
+      ancestralStates_ = ssr.ancestralStates_;
+      tree_            = ssr.tree_;
+      leavesId_        = ssr.leavesId_;
+      alphabet_        = ssr.alphabet_;
+      return *this;
+    }
+
+    virtual ~SiteSimulationResult() {}
+  
+  public:
+    /**
+     * @return The alphabet associated to this simulation.
+     */
+    virtual const Alphabet* getAlphabet() const { return alphabet_; }
+    
+    virtual void addNode(int nodeId, MutationPath path)
+    {
+      indexes_[nodeId] = currentIndex_;
+      currentIndex_++;
+      paths_.push_back(path);
+      ancestralStates_.push_back(path.getFinalState());
+    }
+
+    virtual int getAncestralState(size_t i)    const { return ancestralStates_[i]; }
+
+    virtual int getAncestralState(int nodeId) const { return ancestralStates_[1 + indexes_[nodeId]]; }
+
+    virtual const MutationPath& getMutationPath(size_t i) const { return paths_[i]; }
+
+    virtual const MutationPath& getMutationPath(int nodeId) const { return paths_[indexes_[nodeId]]; }
+
+    virtual size_t getSubstitutionCount(size_t i) const { return paths_[i].getNumberOfEvents(); }
+    
+    virtual void getSubstitutionCount(size_t i, const SubstitutionRegister& reg, std::vector<double>& counts) const {
+      paths_[i].getEventCounts(counts, reg);
+    }
+    
+    virtual size_t getSubstitutionCount(int nodeId) const { return paths_[indexes_[nodeId]].getNumberOfEvents(); }
+    
+    virtual void getSubstitutionCount(int nodeId, const SubstitutionRegister& reg, std::vector<double>& counts) const {
+      paths_[indexes_[nodeId]].getEventCounts(counts, reg);
+    }
+    
+    virtual VVdouble getSubstitutionVector(const SubstitutionRegister& reg) const
+    {
+      size_t n = paths_.size();
+      VVdouble counts(n);
+      for (size_t i = 0; i < n; ++i) {
+        counts[i].resize(reg.getNumberOfSubstitutionTypes());
+        paths_[i].getEventCounts(counts[i], reg);
+      }
+      return counts;
+    }
+
+    /**
+     * @return The states at the leaves.
+     */
+    virtual std::vector<int> getFinalStates() const
+    {
+      size_t n = leavesId_.size(); 
+      std::vector<int> states(n);
+      for (size_t i = 0; i < n; i++)
+      {
+        states[i] = ancestralStates_[1 + indexes_[leavesId_[i]]];
+      }
+      return states;
+    }
+
+    /**
+     * @return The site corresponding to this simulation.
+     */
+    virtual Site* getSite() const { return new Site(getFinalStates(), alphabet_); }
+
+    /**
+     * @return A vector with the leaves names.
+     */
+    virtual std::vector<std::string> getLeaveNames() const
+    {
+      size_t n = leavesId_.size(); 
+      std::vector<std::string> names(n);
+      for (size_t i = 0; i < n; i++)
+      {
+        names[i] = tree_->getNodeName(leavesId_[i]);
+      }
+      return names;
+    }
+
+};
+
+//---------------------------------------------------------------------------
+
+/**
+ * @brief Data structure to store the result of a DetailedSiteSimulator.
+ *
+ * This sructure inherits from the SequenceSimulationResult class, and add support for
+ * rate variation across sites.
+ */
+class RASiteSimulationResult:
+  public SiteSimulationResult
+{
+  protected:
+    double rate_;
+    
+  public:
+    RASiteSimulationResult(const Tree* tree, const Alphabet * alphabet, int ancestralState, double rate):
+      SiteSimulationResult(tree, alphabet, ancestralState),
+      rate_(rate) {}
+
+    virtual ~RASiteSimulationResult() {}
+  
+  public:
+    /**
+     * @return The rate of this simulation.
+     */
+    virtual double getRate() const { return rate_; }
+};
+
+//---------------------------------------------------------------------------
+
+/**
+ * @brief This interface adds the dSimulate method to the SiteSimulator interface.
+ *
+ * Instances of this class should be used when a detailed output of the simulation is needed.
+ */
+class DetailedSiteSimulator:
+  public virtual SiteSimulator
+{
+  public:
+    DetailedSiteSimulator() {}
+    virtual ~DetailedSiteSimulator() {}
+  
+  public:
+    /**
+     * @brief Get a detailed simulation result for one site.
+     *
+     * @return A SiteSimulationResult object with all ancestral
+     * states for all nodes and branches.
+     */
+    virtual SiteSimulationResult* dSimulate() const = 0;
+    virtual SiteSimulationResult* dSimulate(int ancestralState) const = 0;
+    virtual SiteSimulationResult* dSimulate(int ancestralState, double rate) const = 0;
+    virtual SiteSimulationResult* dSimulate(double rate) const = 0;
+    
+};
+
+} //end of namespace bpp.
+
+#endif // _DETAILEDSITESIMULATOR_H_
+
diff --git a/src/Bpp/Phyl/Simulation/HomogeneousSequenceSimulator.h b/src/Bpp/Phyl/Simulation/HomogeneousSequenceSimulator.h
new file mode 100644
index 0000000..52fa405
--- /dev/null
+++ b/src/Bpp/Phyl/Simulation/HomogeneousSequenceSimulator.h
@@ -0,0 +1,77 @@
+//
+// File: HomogeneousSequenceSimulator.h
+// Created by: Julien Dutheil
+// Created on: Wed Aug  24 15:20 2005
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _HOMOGENEOUSSEQUENCESIMULATOR_H_
+#define _HOMOGENEOUSSEQUENCESIMULATOR_H_
+
+#include "NonHomogeneousSequenceSimulator.h"
+
+namespace bpp
+{
+
+/**
+ * @brief Site and sequences simulation under homogeneous models.
+ *
+ * This is an alias class, for clarity and backward compatibility.
+ */
+class HomogeneousSequenceSimulator:
+  public NonHomogeneousSequenceSimulator
+{
+	public:
+		
+		HomogeneousSequenceSimulator(
+			const SubstitutionModel* model,
+			const DiscreteDistribution* rate,
+			const Tree* tree
+		) : NonHomogeneousSequenceSimulator(model, rate, tree) {}
+			
+		virtual ~HomogeneousSequenceSimulator() {}
+
+	public:
+    const SubstitutionModel* getSubstitutionModel() const
+    {
+      return getSubstitutionModelSet()->getModel(0);
+    }
+	
+};
+
+} //end of namespace bpp.
+
+#endif //_HOMOGENEOUSSEQUENCESIMULATOR_H_
+
diff --git a/src/Bpp/Phyl/Simulation/MutationProcess.cpp b/src/Bpp/Phyl/Simulation/MutationProcess.cpp
new file mode 100644
index 0000000..cdd0621
--- /dev/null
+++ b/src/Bpp/Phyl/Simulation/MutationProcess.cpp
@@ -0,0 +1,193 @@
+//
+// File: MutationProcess.cpp
+// Created by: Julien Dutheil
+// Created on: Wed Mar 12 16:11:44 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "MutationProcess.h"
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Numeric/Random/RandomTools.h>
+
+using namespace bpp;
+
+/******************************************************************************/
+int AbstractMutationProcess::mutate(int state) const
+{
+  double alea = RandomTools::giveRandomNumberBetweenZeroAndEntry(1.0);
+  for (unsigned int j = 0; j < size_; j++)
+  {
+    if (alea < repartition_[state][j]) return j;
+  }
+  throw Exception("AbstractMutationProcess::mutate. Repartition function is incomplete for state " + TextTools::toString(state));
+}
+
+/******************************************************************************/
+int AbstractMutationProcess::mutate(int state, unsigned int n) const
+{
+  int s = state;
+  for (unsigned int k = 0; k < n; k++)
+  {
+    double alea = RandomTools::giveRandomNumberBetweenZeroAndEntry(1.0);
+    for (unsigned int j = 1; j < size_ + 1; j++)
+    {
+      if (alea < repartition_[s][j])
+      {
+        s = j;
+        break;
+      }
+    }
+  }
+  return s;
+}
+
+/******************************************************************************/
+double AbstractMutationProcess::getTimeBeforeNextMutationEvent(int state) const
+{
+  return RandomTools::randExponential(-1./model_->Qij(state, state));
+}
+
+/******************************************************************************/
+int AbstractMutationProcess::evolve(int initialState, double time) const
+{
+  double t = 0;
+  int currentState = initialState;
+  t += getTimeBeforeNextMutationEvent(currentState);
+  while (t < time)
+  {
+    currentState = mutate(currentState);
+    t += getTimeBeforeNextMutationEvent(currentState);
+  }
+  return currentState;
+}
+
+/******************************************************************************/
+MutationPath AbstractMutationProcess::detailedEvolve(int initialState, double time) const
+{
+  MutationPath mp(model_->getAlphabet(), initialState, time);
+  double t = 0;
+  int currentState = initialState;
+  t += getTimeBeforeNextMutationEvent(currentState);
+  while (t < time)
+  {
+    currentState = mutate(currentState);
+    mp.addEvent(currentState, t);
+    t += getTimeBeforeNextMutationEvent(currentState);
+  }
+  return mp;
+}
+
+/******************************************************************************/
+
+SimpleMutationProcess::SimpleMutationProcess(const SubstitutionModel* model) :
+  AbstractMutationProcess(model)
+{
+  size_ = model->getNumberOfStates();
+  repartition_ = VVdouble(size_);
+  // Each element contains the probabilities concerning each character in the alphabet.
+
+  // We will now initiate each of these probability vector.
+  RowMatrix<double> Q = model->getGenerator();
+  for (unsigned int i = 0; i < size_; i++)
+  {
+    repartition_[i] = Vdouble(size_);
+    double cum = 0;
+    double sum_Q = 0;
+    for (unsigned int j = 0; j < size_; j++)
+    {
+      if (j != i) sum_Q += Q(i, j);
+    }
+    for (unsigned int j = 0; j < size_; j++)
+    {
+      if (j != i)
+      {
+        cum += model->Qij(i, j) / sum_Q;
+        repartition_[i][j] = cum;
+      }
+      else repartition_[i][j] = -1;
+      // Forbiden value: does not correspond to a change.
+    }
+  }
+  // Note that I use cumulative probabilities in repartition_ (hence the name).
+  // These cumulative probabilities are useful for the 'mutate(...)' function.
+}
+
+SimpleMutationProcess::~SimpleMutationProcess() {}
+
+/******************************************************************************/
+int SimpleMutationProcess::evolve(int initialState, double time) const
+{
+  // Compute all cumulative pijt:
+  Vdouble pijt(size_);
+  pijt[0] = model_->Pij_t(initialState, 0, time);
+  for (unsigned int i = 1; i < size_; i++)
+  {
+    pijt[i] = pijt[i - 1] + model_->Pij_t(initialState, i, time);
+  }
+  double rand = RandomTools::giveRandomNumberBetweenZeroAndEntry(1);
+  for (unsigned int i = 0; i < size_; i++)
+  {
+    if (rand < pijt[i]) return i;
+  }
+  throw Exception("SimpleSimulationProcess::evolve(intialState, time): error all pijt do not sum to one (total sum = " + TextTools::toString(pijt[size_ - 1]) + ").");
+}
+
+/******************************************************************************/
+
+SelfMutationProcess::SelfMutationProcess(int alphabetSize) :
+  AbstractMutationProcess(0)
+{
+  size_ = alphabetSize;
+  repartition_ = VVdouble(size_);
+  // Each element contains the probabilities concerning each character in the alphabet.
+
+  // We will now initiate each of these probability vector.
+  for (size_t i = 0; i < size_; i++)
+  {
+    repartition_[i] = Vdouble(size_);
+    for (size_t j = 0; j < size_; j++)
+    {
+      repartition_[i][j] = static_cast<double>(j + 1) / static_cast<double>(size_);
+    }
+  }
+  // Note that I use cumulative probabilities in repartition_ (hence the name).
+  // These cumulative probabilities are useful for the 'mutate(...)' function.
+}
+
+SelfMutationProcess::~SelfMutationProcess() {}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Simulation/MutationProcess.h b/src/Bpp/Phyl/Simulation/MutationProcess.h
new file mode 100644
index 0000000..060e7be
--- /dev/null
+++ b/src/Bpp/Phyl/Simulation/MutationProcess.h
@@ -0,0 +1,379 @@
+//
+// File: MutationProcess.h
+// Created by: Julien Dutheil
+// Created on: Wed Mar 12 16:11:44 2003
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+ 
+#ifndef _MUTATIONPROCESS_H_
+#define _MUTATIONPROCESS_H_
+
+#include "../Model/SubstitutionModel.h"
+#include "../Mapping/SubstitutionRegister.h"
+
+#include <Bpp/Numeric/VectorTools.h>
+
+namespace bpp
+{
+
+/**
+ * @brief This class is used by MutationProcess to store detailed results of simulations.
+ *
+ * @author Julien Dutheil
+ */
+class MutationPath
+{
+	private:
+
+    const Alphabet* alphabet_;
+
+		/**
+		 * @brief The states taken, without intiial state.
+		 */
+    std::vector<int> states_;
+
+		/**
+		 * @brief Times between states.
+		 * The first element in array is the time between the initial state and the first state in states_.
+		 */
+    std::vector<double> times_;
+		
+		/**
+		 * @brief The initial state.
+		 */
+		int initialState_;
+
+		/**
+		 * @brief Total time of evolution.
+		 * Typically, this is a branch length.
+		 */
+		double totalTime_;
+
+	public:
+
+		/**
+		 * @brief Builds a new MutationPath object with initial state 'initialState' and total time 'time'.
+		 *
+     * @param alphabet     The alphabet associated to the states in this path.
+		 * @param initialState The initial state.
+		 * @param time         The total time of evolution.
+		 */
+		MutationPath(const Alphabet* alphabet, int initialState, double time) :
+      alphabet_(alphabet), states_(), times_(), initialState_(initialState), totalTime_(time) {};
+		
+    MutationPath(const MutationPath& path) :
+      alphabet_(path.alphabet_), states_(path.states_), times_(path.times_), initialState_(path.initialState_), totalTime_(path.totalTime_) {};
+
+    MutationPath& operator=(const MutationPath& path) {
+      alphabet_     = path.alphabet_;
+      states_       = path.states_;
+      times_        = path.times_;
+      initialState_ = path.initialState_;
+      totalTime_    = path.totalTime_;
+      return *this;
+    }
+
+		virtual ~MutationPath() {};
+
+	public:
+	
+    /**
+     * @return A pointer toward the alphabet associated to this path.
+     */
+    const Alphabet* getAlphabet() const { return alphabet_; }
+		
+    /**
+		 * @brief Add a new mutation event.
+		 *
+		 * @param state The new state after mutation event.
+		 * @param time  The time between this mutation and previous mutation (or initial state).
+		 */
+		void addEvent(int state, double time) {
+			states_.push_back(state);
+			times_.push_back(time);
+		}
+
+		/**
+		 * @brief Retrieve the initial state.
+		 *
+		 * @return The initial state of this path.
+		 */
+		int getInitialState() const { return initialState_; }
+
+		/**
+		 * @brief Retrieve the total time of evolution.
+		 *
+		 * @return The total time of evolution.
+		 */
+		double getTotalTime() const { return totalTime_; }
+		
+		/**
+		 * @brief Retrieve the number of substitution events.
+		 *
+		 * @return The number of substitution events, i.e. the number of states (without initial state).
+		 */
+		size_t getNumberOfEvents() const { return states_.size(); }
+
+    /**
+     * @brief Retrieve the number of substitution events per type of substitution.
+     *
+     * @param counts A matrix with the same size as the alphabet. The substitution counts will be incremented according to the mutation path, which allows to efficiently sum various mutation paths with a look.
+     */
+    template<class Scalar>
+    void getEventCounts(Matrix<Scalar>& counts) const {
+      if (counts.getNumberOfRows()    != alphabet_->getSize()
+       || counts.getNumberOfColumns() != alphabet_->getSize())
+        throw Exception("MutationPath::getEventCounts. Incorrect input matrix, does not match alphabet size.");
+      int currentState = initialState_;
+      for (size_t i = 0; i < states_.size(); ++i) {
+        int newState = states_[i];
+        counts(currentState, newState)++;
+        currentState = newState;
+      }
+    }
+
+    /**
+     * @brief Retrieve the number of substitution events per type of substitution, defined by a SubstitutionRegister object.
+     *
+     * @param counts A vector with the appropriate size, as defined by SubstitutionRegister::getNumberOfSubstitutionTypes(). The substitution counts will be incremented according to the mutation path, which allows to efficiently sum various mutation paths with a look.
+     * @param reg The substitution register to use to categorize substitutions.
+     */
+    template<class Scalar>
+    void getEventCounts(std::vector<Scalar>& counts, const SubstitutionRegister& reg) const {
+      if (counts.size() != reg.getNumberOfSubstitutionTypes())
+        throw Exception("MutationPath::getEventCounts. Incorrect input vector, does not match alphabet size.");
+      int currentState = initialState_;
+      for (size_t i = 0; i < states_.size(); ++i) {
+        int newState = states_[i];
+        size_t type = reg.getType(currentState, newState);
+        if (type > 0) counts[type - 1]++;
+        currentState = newState;
+      }
+    }
+
+		/**
+		 * @brief Retrieve the final state of this path.
+		 *
+		 * @return The initial state if no mutation occured, otherwise sends the state after last mutation event.
+		 */
+		int getFinalState() const {
+			if (states_.size() == 0) return initialState_;
+			else return states_[states_.size() - 1];
+		}
+};
+
+/**
+ * @brief Interface for simulations.
+ *
+ * A mutation process defines the rules for mutations to occure.
+ * The MutationProcess interface provides two methods, one for mutating a character in
+ * state i in another character, another for achieving this task n times.
+ */
+class MutationProcess
+{
+	public:
+		MutationProcess() {};
+		virtual ~MutationProcess() {};
+	
+	public:
+		
+    /**
+     * @brief Mutate a character in state i.
+		 *
+		 * @param state The current state of the character.
+     */
+    virtual int mutate(int state) const = 0;
+
+    /**
+     * @brief Mutate a character in state i n times.
+     * 
+		 * @param state The current state of the character.
+		 * @param n The number of mutations to perform.
+     */
+    virtual int mutate(int state, unsigned int n) const = 0;
+	
+		/**
+		 * @brief Get the time before next mutation event.
+		 *
+		 * @param state The actual state of the chain;
+		 * @return A random time before next mutation event.
+		 */
+		virtual double getTimeBeforeNextMutationEvent(int state) const = 0;
+		
+		/**
+		 * @brief Simulation a character evolution during a specified time
+		 * according to the given substitution model and send the final state.
+		 *
+		 * @param initialState The state before beginning evolution.
+		 * @param time         The time during which evolution must occure.
+		 * @return The resulting state after evolution is completed.
+		 */
+		virtual int evolve(int initialState, double time) const = 0;
+	
+		/**
+		 * @brief Simulation a character evolution during a specified time
+		 * according to the given substitution model and send the total path
+		 * with all intermediate states and times between mutation events.
+		 *
+		 * @param initialState The state before beginning evolution.
+		 * @param time         The time during which evolution must occure.
+		 * @return The resulting mutation path.
+		 */
+		virtual MutationPath detailedEvolve(int initialState, double time) const = 0;
+
+		/**
+		 * @brief Get the substitution model associated to the mutation process.
+		 *
+		 * @return The SubstitutionModel associated to this instance.
+		 */
+		virtual const SubstitutionModel* getSubstitutionModel() const = 0;
+};
+
+/**
+ * @brief Partial implmentation of the MutationProcess interface.
+ *
+ * This class provides an implementation of the MutationProcess interface.
+ * It assumes that there are size_ states allowed for the character of interest,
+ * and that the distribution of probabilities are in repartition_.
+ * As a matter of facts, probabilities must be cumulative, so that repartition_
+ * contains values of the repartition function.
+ * The mutate function hence draws a random number between 0 and 1 and gives the
+ * corresponding character using the bijection of the repartition function.
+ *
+ * All derived classes must initialize the repartition_ and size_ fields.
+ */
+class AbstractMutationProcess :
+  public virtual MutationProcess
+{
+	protected:
+		
+		/**
+		 * @brief The substitution model to use:
+		 */
+		const SubstitutionModel* model_;
+	
+		/**
+		 * @brief The number of states allowed for the character to mutate.
+		 */
+    size_t size_;
+	
+		/**
+		 * @brief The repartition function for states probabilities.
+		 *
+		 * repartition_[i][j] = probability that, being in state i at time t,
+		 * we'll be in state <= j at time t+1.
+		 */
+    VVdouble repartition_;
+	
+	public:
+		AbstractMutationProcess(const SubstitutionModel* model) :
+      model_(model), size_(), repartition_()
+    {}
+
+    AbstractMutationProcess(const AbstractMutationProcess& amp) :
+      model_(amp.model_), size_(amp.size_), repartition_(amp.repartition_)
+    {}
+
+    AbstractMutationProcess& operator=(const AbstractMutationProcess& amp)
+    {
+      model_       = amp.model_;
+      size_        = amp.size_;
+      repartition_ = amp.repartition_;
+      return *this;
+    }
+
+		virtual ~AbstractMutationProcess() {}
+	
+	public:
+    int mutate(int state) const;
+    int mutate(int state, unsigned int n) const;
+		double getTimeBeforeNextMutationEvent(int state) const;
+		int evolve(int initialState, double time) const;
+		MutationPath detailedEvolve(int initialState, double time) const;
+		const SubstitutionModel* getSubstitutionModel() const { return model_; }
+};
+
+/**
+ * @brief Generally used mutation process model.
+ *
+ * This builds a MutationProcess according to a given SubstitutionModel.
+ * The underlying mutation process is the following:
+ * <ol>
+ * <li>Draw a random time @f$ t @f$ from an exponential law with parameter
+ * @f$ - \lambda_i @f$,</li>
+ * <li> Mutate the initial state. The probability of mutating state @f$i at f$ 
+ * to state @f$j at f$ is:
+ * @f[ \frac{Q_{i,j}}{\sum_k Q_{i,k}}. @f]</li>
+ * </ol>
+ */
+class SimpleMutationProcess : public AbstractMutationProcess
+{
+	public: // Constructor and destructor:
+		
+		/**
+		 * @brief Build a new SimpleMutationProcess object.
+		 *
+		 * @param model The substitution model to use.
+		 */
+  	SimpleMutationProcess(const SubstitutionModel* model);
+	
+		virtual ~SimpleMutationProcess();
+
+    /**
+     * @brief Method redefinition for better performance.
+     *
+		 * @param initialState The state before beginning evolution.
+		 * @param time         The time during which evolution must occure.
+		 * @return The resulting state after evolution is completed.
+		 */
+		int evolve(int initialState, double time) const;
+};
+
+/**
+ * @brief This class is mainly for testing purpose.
+ * It allow "self" mutation of the kind i->i;
+ */
+class SelfMutationProcess : public AbstractMutationProcess
+{
+  	public:
+  		SelfMutationProcess(int alphabetSize);
+	
+			virtual ~SelfMutationProcess();
+};
+
+} //end of namespace bpp.
+
+#endif	//_MUTATIONPROCESS_H_
+
diff --git a/src/Bpp/Phyl/Simulation/NonHomogeneousSequenceSimulator.cpp b/src/Bpp/Phyl/Simulation/NonHomogeneousSequenceSimulator.cpp
new file mode 100644
index 0000000..527d5d0
--- /dev/null
+++ b/src/Bpp/Phyl/Simulation/NonHomogeneousSequenceSimulator.cpp
@@ -0,0 +1,526 @@
+//
+// File: NonHomogeneousSequenceSimulator.cpp
+//       (previously SequenceSimulator.cpp, then HomogeneousSequenceSimulator.cpp)
+// Created by: Julien Dutheil
+//             Bastien Boussau
+// Created on: Wed Feb  4 16:30:51 2004
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "NonHomogeneousSequenceSimulator.h"
+#include "../Model/SubstitutionModelSetTools.h"
+
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/VectorSiteContainer.h>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+NonHomogeneousSequenceSimulator::NonHomogeneousSequenceSimulator(
+  const SubstitutionModelSet* modelSet,
+  const DiscreteDistribution* rate,
+  const Tree* tree) throw (Exception) :
+  modelSet_(modelSet),
+  alphabet_(modelSet_->getAlphabet()),
+  rate_(rate),
+  templateTree_(tree),
+  tree_(*tree),
+  ownModelSet_(false),
+  leaves_(tree_.getLeaves()),
+  seqNames_(),
+  nbNodes_(),
+  nbClasses_(rate_->getNumberOfCategories()),
+  nbStates_(modelSet_->getNumberOfStates()),
+  continuousRates_(false)
+{
+  if (!modelSet->isFullySetUpFor(*tree))
+    throw Exception("NonHomogeneousSequenceSimulator(constructor). Model set is not fully specified.");
+  init();
+}
+
+/******************************************************************************/
+
+NonHomogeneousSequenceSimulator::NonHomogeneousSequenceSimulator(
+  const SubstitutionModel* model,
+  const DiscreteDistribution* rate,
+  const Tree* tree) :
+  modelSet_(0),
+  alphabet_(model->getAlphabet()),
+  rate_(rate),
+  templateTree_(tree),
+  tree_(*tree),
+  ownModelSet_(true),
+  leaves_(tree_.getLeaves()),
+  seqNames_(),
+  nbNodes_(),
+  nbClasses_(rate_->getNumberOfCategories()),
+  nbStates_(model->getNumberOfStates()),
+  continuousRates_(false)
+{
+  FixedFrequenciesSet* fSet = new FixedFrequenciesSet(model->getAlphabet(), model->getFrequencies());
+  fSet->setNamespace("anc.");
+  modelSet_ = SubstitutionModelSetTools::createHomogeneousModelSet(dynamic_cast<SubstitutionModel*>(model->clone()), fSet, templateTree_);
+  init();
+}
+
+/******************************************************************************/
+void NonHomogeneousSequenceSimulator::init()
+{
+  seqNames_.resize(leaves_.size());
+  for (size_t i = 0; i < seqNames_.size(); i++)
+  {
+    seqNames_[i] = leaves_[i]->getName();
+  }
+  // Initialize cumulative pxy:
+  vector<SNode*> nodes = tree_.getNodes();
+  nodes.pop_back(); // remove root
+  nbNodes_ = nodes.size();
+
+  for (size_t i = 0; i < nodes.size(); i++)
+  {
+    SNode* node = nodes[i];
+    node->getInfos().model = modelSet_->getModelForNode(node->getId());
+    double d = node->getDistanceToFather();
+    VVVdouble* cumpxy_node_ = &node->getInfos().cumpxy;
+    cumpxy_node_->resize(nbClasses_);
+    for (size_t c = 0; c < nbClasses_; c++)
+    {
+      VVdouble* cumpxy_node_c_ = &(*cumpxy_node_)[c];
+      cumpxy_node_c_->resize(nbStates_);
+      RowMatrix<double> P = node->getInfos().model->getPij_t(d * rate_->getCategory(c));
+      for (size_t x = 0; x < nbStates_; x++)
+      {
+        Vdouble* cumpxy_node_c_x_ = &(*cumpxy_node_c_)[x];
+        cumpxy_node_c_x_->resize(nbStates_);
+        (*cumpxy_node_c_x_)[0] = P(x, 0);
+        for (size_t y = 1; y < nbStates_; y++)
+        {
+          (*cumpxy_node_c_x_)[y] = (*cumpxy_node_c_x_)[y - 1] + P(x, y);
+        }
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+Site* NonHomogeneousSequenceSimulator::simulate() const
+{
+  // Draw an initial state randomly according to equilibrum frequencies:
+  int initialState = 0;
+  double r = RandomTools::giveRandomNumberBetweenZeroAndEntry(1.);
+  double cumprob = 0;
+  vector<double> freqs = modelSet_->getRootFrequencies();
+  for (size_t i = 0; i < nbStates_; i++)
+  {
+    cumprob += freqs[i];
+    if (r <= cumprob)
+    {
+      initialState = static_cast<int>(i);
+      break;
+    }
+  }
+  return simulate(initialState);
+}
+
+/******************************************************************************/
+Site* NonHomogeneousSequenceSimulator::simulate(int initialState) const
+{
+  if (continuousRates_)
+  {
+    // Draw a random rate:
+    double rate = rate_->randC();
+    // Make this state evolve:
+    return simulate(initialState, rate);
+  }
+  else
+  {
+    // Draw a random rate:
+    size_t rateClass = static_cast<size_t>(RandomTools::giveIntRandomNumberBetweenZeroAndEntry(static_cast<int>(rate_->getNumberOfCategories())));
+    // Make this state evolve:
+    return simulate(initialState, rateClass);
+  }
+}
+
+/******************************************************************************/
+Site* NonHomogeneousSequenceSimulator::simulate(int initialState, size_t rateClass) const
+{
+  // Launch recursion:
+  SNode* root = tree_.getRootNode();
+  root->getInfos().state = initialState;
+  for (size_t i = 0; i < root->getNumberOfSons(); i++)
+  {
+    evolveInternal(root->getSon(i), rateClass);
+  }
+  // Now create a Site object:
+  Vint site(leaves_.size());
+  for (size_t i = 0; i < leaves_.size(); i++)
+  {
+    site[i] = leaves_[i]->getInfos().model->getAlphabetChar(leaves_[i]->getInfos().state);
+  }
+  return new Site(site, alphabet_);
+}
+
+/******************************************************************************/
+Site* NonHomogeneousSequenceSimulator::simulate(int initialState, double rate) const
+{
+  // Launch recursion:
+  SNode* root = tree_.getRootNode();
+  root->getInfos().state = initialState;
+  for (size_t i = 0; i < root->getNumberOfSons(); i++)
+  {
+    evolveInternal(root->getSon(i), rate);
+  }
+  // Now create a Site object:
+  Vint site(leaves_.size());
+  for (size_t i = 0; i < leaves_.size(); i++)
+  {
+    site[i] = leaves_[i]->getInfos().model->getAlphabetChar(leaves_[i]->getInfos().state);
+  }
+  return new Site(site, alphabet_);
+}
+
+/******************************************************************************/
+Site* NonHomogeneousSequenceSimulator::simulate(double rate) const
+{
+  // Draw an initial state randomly according to equilibrum frequencies:
+  int initialState = 0;
+  double r = RandomTools::giveRandomNumberBetweenZeroAndEntry(1.);
+  double cumprob = 0;
+  vector<double> freqs = modelSet_->getRootFrequencies();
+  for (size_t i = 0; i < nbStates_; i++)
+  {
+    cumprob += freqs[i];
+    if (r <= cumprob)
+    {
+      initialState = (int)i;
+      break;
+    }
+  }
+  // Make this state evolve:
+  return simulate(initialState, rate);
+}
+
+/******************************************************************************/
+SiteContainer* NonHomogeneousSequenceSimulator::simulate(size_t numberOfSites) const
+{
+  Vint initialStates(numberOfSites, 0);
+  for (size_t j = 0; j < numberOfSites; j++)
+  {
+    double r = RandomTools::giveRandomNumberBetweenZeroAndEntry(1.);
+    double cumprob = 0;
+    vector<double> freqs = modelSet_->getRootFrequencies();
+    for (size_t i = 0; i < nbStates_; i++)
+    {
+      cumprob += freqs[i];
+      if (r <= cumprob)
+      {
+        initialStates[j] = (int)i;
+        break;
+      }
+    }
+  }
+  if (continuousRates_)
+  {
+    VectorSiteContainer* sites = new VectorSiteContainer(seqNames_.size(), alphabet_);
+    sites->setSequencesNames(seqNames_);
+    for (size_t j = 0; j < numberOfSites; j++)
+    {
+      Site* site = simulate();
+      site->setPosition(static_cast<int>(j));
+      sites->addSite(*site);
+      delete site;
+    }
+    return sites;
+  }
+  else
+  {
+    // More efficient to do site this way:
+    // Draw random rates:
+    vector<size_t> rateClasses(numberOfSites);
+    size_t nCat = rate_->getNumberOfCategories();
+    for (size_t j = 0; j < numberOfSites; j++)
+    {
+      rateClasses[j] = static_cast<size_t>(RandomTools::giveIntRandomNumberBetweenZeroAndEntry(static_cast<int>(nCat)));
+    }
+    // Make these states evolve:
+    SiteContainer* sites = multipleEvolve(initialStates, rateClasses);
+    return sites;
+  }
+}
+
+/******************************************************************************/
+RASiteSimulationResult* NonHomogeneousSequenceSimulator::dSimulate() const
+{
+  // Draw an initial state randomly according to equilibrum frequencies:
+  int initialState = 0;
+  double r = RandomTools::giveRandomNumberBetweenZeroAndEntry(1.);
+  double cumprob = 0;
+  vector<double> freqs = modelSet_->getRootFrequencies();
+  for (size_t i = 0; i < nbStates_; i++)
+  {
+    cumprob += freqs[i];
+    if (r <= cumprob)
+    {
+      initialState = static_cast<int>(i);
+      break;
+    }
+  }
+
+  return dSimulate(initialState);
+}
+
+/******************************************************************************/
+RASiteSimulationResult* NonHomogeneousSequenceSimulator::dSimulate(int initialState) const
+{
+  // Draw a random rate:
+  if (continuousRates_)
+  {
+    double rate = rate_->randC();
+    return dSimulate(initialState, rate);
+  }
+  else
+  {
+    size_t rateClass = static_cast<size_t>(RandomTools::giveIntRandomNumberBetweenZeroAndEntry(static_cast<int>(rate_->getNumberOfCategories())));
+    return dSimulate(initialState, rateClass);
+    // NB: this is more efficient than dSimulate(initialState, rDist_->rand())
+  }
+}
+
+/******************************************************************************/
+RASiteSimulationResult* NonHomogeneousSequenceSimulator::dSimulate(int initialState, double rate) const
+{
+  // Make this state evolve:
+  RASiteSimulationResult* hssr = new RASiteSimulationResult(templateTree_, modelSet_->getAlphabet(), initialState, rate);
+  dEvolve(initialState, rate, *hssr);
+  return hssr;
+}
+
+/******************************************************************************/
+RASiteSimulationResult* NonHomogeneousSequenceSimulator::dSimulate(int initialState, size_t rateClass) const
+{
+  return dSimulate(initialState, rate_->getCategory(rateClass));
+}
+
+/******************************************************************************/
+RASiteSimulationResult* NonHomogeneousSequenceSimulator::dSimulate(double rate) const
+{
+  // Draw an initial state randomly according to equilibrum frequencies:
+  int initialState = 0;
+  double r = RandomTools::giveRandomNumberBetweenZeroAndEntry(1.);
+  double cumprob = 0;
+  vector<double> freqs = modelSet_->getRootFrequencies();
+  for (size_t i = 0; i < nbStates_; i++)
+  {
+    cumprob += freqs[i];
+    if (r <= cumprob)
+    {
+      initialState = static_cast<int>(i);
+      break;
+    }
+  }
+  return dSimulate(initialState, rate);
+}
+
+/******************************************************************************/
+int NonHomogeneousSequenceSimulator::evolve(const SNode* node, int initialState, size_t rateClass) const
+{
+  const Vdouble* cumpxy_node_c_x_ = &node->getInfos().cumpxy[rateClass][initialState];
+  double rand = RandomTools::giveRandomNumberBetweenZeroAndEntry(1.);
+  for (int y = 0; y < static_cast<int>(nbStates_); y++)
+  {
+    if (rand < (*cumpxy_node_c_x_)[y]) return y;
+  }
+  cerr << "DEBUG: This message should never happen! (HomogeneousSequenceSimulator::evolve)" << endl;
+  cout << "   rand = " << rand << endl;
+  return -1;
+}
+
+/******************************************************************************/
+int NonHomogeneousSequenceSimulator::evolve(const SNode* node, int initialState, double rate) const
+{
+  double cumpxy = 0;
+  double rand = RandomTools::giveRandomNumberBetweenZeroAndEntry(1.);
+  double l = rate * node->getDistanceToFather();
+  const SubstitutionModel* model = node->getInfos().model;
+  for (int y = 0; y < static_cast<int>(nbStates_); y++)
+  {
+    cumpxy += model->Pij_t(initialState, y, l);
+    if (rand < cumpxy) return y;
+  }
+  cerr << "DEBUG: This message should never happen! (NonHomogeneousSequenceSimulator::evolve)" << endl;
+  cout << "  rand = " << rand << endl;
+  cout << "cumpxy = " << cumpxy << endl;
+  MatrixTools::print(model->getPij_t(l));
+  return -1;
+}
+
+/******************************************************************************/
+void NonHomogeneousSequenceSimulator::multipleEvolve(const SNode* node, const Vint& initialStates, const vector<size_t>& rateClasses, Vint& finalStates) const
+{
+  const VVVdouble* cumpxy_node_ = &node->getInfos().cumpxy;
+  for (size_t i = 0; i < initialStates.size(); i++)
+  {
+    const Vdouble* cumpxy_node_c_x_ = &(*cumpxy_node_)[rateClasses[i]][initialStates[i]];
+    double rand = RandomTools::giveRandomNumberBetweenZeroAndEntry(1.);
+    for (size_t y = 0; y < nbStates_; y++)
+    {
+      if (rand < (*cumpxy_node_c_x_)[y])
+      {
+        finalStates[i] = (int)y;
+        break;
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+void NonHomogeneousSequenceSimulator::evolveInternal(SNode* node, size_t rateClass) const
+{
+  if (!node->hasFather())
+  {
+    cerr << "DEBUG: NonHomogeneousSequenceSimulator::evolveInternal. Forbidden call of method on root node." << endl;
+    return;
+  }
+  node->getInfos().state = evolve(node, node->getFather()->getInfos().state, rateClass);
+  for (size_t i = 0; i < node->getNumberOfSons(); i++)
+  {
+    evolveInternal(node->getSon(i), rateClass);
+  }
+}
+
+/******************************************************************************/
+void NonHomogeneousSequenceSimulator::evolveInternal(SNode* node, double rate) const
+{
+  if (!node->hasFather())
+  {
+    cerr << "DEBUG: NonHomogeneousSequenceSimulator::evolveInternal. Forbidden call of method on root node." << endl;
+    return;
+  }
+  node->getInfos().state = evolve(node, node->getFather()->getInfos().state, rate);
+  for (size_t i = 0; i < node->getNumberOfSons(); i++)
+  {
+    evolveInternal(node->getSon(i), rate);
+  }
+}
+
+/******************************************************************************/
+void NonHomogeneousSequenceSimulator::multipleEvolveInternal(SNode* node, const vector<size_t>& rateClasses) const
+{
+  if (!node->hasFather())
+  {
+    cerr << "DEBUG: NonHomogeneousSequenceSimulator::multipleEvolveInternal. Forbidden call of method on root node." << endl;
+    return;
+  }
+  const vector<int>* initialStates = &node->getFather()->getInfos().states;
+  size_t n = initialStates->size();
+  node->getInfos().states.resize(n); // allocation.
+  multipleEvolve(node, node->getFather()->getInfos().states, rateClasses, node->getInfos().states);
+  for (size_t i = 0; i < node->getNumberOfSons(); i++)
+  {
+    multipleEvolveInternal(node->getSon(i), rateClasses);
+  }
+}
+
+/******************************************************************************/
+SiteContainer* NonHomogeneousSequenceSimulator::multipleEvolve(const Vint& initialStates, const vector<size_t>& rateClasses) const
+{
+  // Launch recursion:
+  SNode* root = tree_.getRootNode();
+  root->getInfos().states = initialStates;
+  for (size_t i = 0; i < root->getNumberOfSons(); i++)
+  {
+    multipleEvolveInternal(root->getSon(i), rateClasses);
+  }
+  // Now create a SiteContainer object:
+  AlignedSequenceContainer* sites = new AlignedSequenceContainer(alphabet_);
+  size_t n = leaves_.size();
+  size_t nbSites = initialStates.size();
+  const SubstitutionModel* model = 0;
+  for (size_t i = 0; i < n; i++)
+  {
+    vector<int> content(nbSites);
+    vector<int>* states = &leaves_[i]->getInfos().states;
+    model = leaves_[i]->getInfos().model;
+    for (size_t j = 0; j < nbSites; j++)
+    {
+      content[j] = model->getAlphabetChar((*states)[j]);
+    }
+    sites->addSequence(BasicSequence(leaves_[i]->getName(), content, alphabet_), false);
+  }
+  return sites;
+}
+
+/******************************************************************************/
+void NonHomogeneousSequenceSimulator::dEvolve(int initialState, double rate, RASiteSimulationResult& rassr) const
+{
+  // Launch recursion:
+  SNode* root = tree_.getRootNode();
+  root->getInfos().state = initialState;
+  for (size_t i = 0; i < root->getNumberOfSons(); i++)
+  {
+    dEvolveInternal(root->getSon(i), rate, rassr);
+  }
+}
+
+/******************************************************************************/
+void NonHomogeneousSequenceSimulator::dEvolveInternal(SNode* node, double rate, RASiteSimulationResult& rassr) const
+{
+  if (!node->hasFather())
+  {
+    cerr << "DEBUG: NonHomogeneousSequenceSimulator::evolveInternal. Forbidden call of method on root node." << endl;
+    return;
+  }
+  SimpleMutationProcess process(node->getInfos().model);
+  MutationPath mp = process.detailedEvolve(node->getFather()->getInfos().state, node->getDistanceToFather() * rate);
+  node->getInfos().state = mp.getFinalState();
+
+  // Now append infos in rassr:
+  rassr.addNode(node->getId(), mp);
+
+  // Now jump to son nodes:
+  for (size_t i = 0; i < node->getNumberOfSons(); i++)
+  {
+    dEvolveInternal(node->getSon(i), rate, rassr);
+  }
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/Simulation/NonHomogeneousSequenceSimulator.h b/src/Bpp/Phyl/Simulation/NonHomogeneousSequenceSimulator.h
new file mode 100644
index 0000000..08890bc
--- /dev/null
+++ b/src/Bpp/Phyl/Simulation/NonHomogeneousSequenceSimulator.h
@@ -0,0 +1,335 @@
+//
+// File: NonHomogeneousSequenceSimulator.h
+// Created by: Julien Dutheil
+//             Bastien Boussau
+// Created on: Wed Aug  24 15:20 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _NONHOMOGENEOUSSEQUENCESIMULATOR_H_
+#define _NONHOMOGENEOUSSEQUENCESIMULATOR_H_
+
+#include "DetailedSiteSimulator.h"
+#include "SequenceSimulator.h"
+#include "../TreeTemplate.h"
+#include "../NodeTemplate.h"
+#include "../Model/SubstitutionModel.h"
+
+#include <Bpp/Numeric/Random/RandomTools.h>
+#include <Bpp/Numeric/Prob/DiscreteDistribution.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/Alphabet.h>
+#include <Bpp/Seq/Site.h>
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+// From the STL:
+#include <map>
+#include <vector>
+
+#include "../Model/SubstitutionModelSet.h"
+
+namespace bpp
+{
+
+class SimData
+{
+  public:
+    int state;
+    std::vector<int> states;
+    VVVdouble cumpxy;
+    const SubstitutionModel* model;
+
+  public:
+    SimData(): state(), states(), cumpxy(), model(0) {}
+    SimData(const SimData& sd): state(sd.state), states(sd.states), cumpxy(), model(sd.model) {}
+    SimData& operator=(const SimData& sd)
+    {
+      state  = sd.state;
+      states = sd.states;
+      cumpxy = sd.cumpxy;
+      model  = sd.model;
+      return *this;
+    }
+};
+
+typedef NodeTemplate<SimData> SNode;
+
+/**
+ * @brief Site and sequences simulation under non-homogeneous models.
+ *
+ * Rate across sites variation is supported, using a DiscreteDistribution object or by specifying explicitely the rate of the sites to simulate.
+ */
+class NonHomogeneousSequenceSimulator:
+  public DetailedSiteSimulator,
+  public virtual SequenceSimulator
+{
+	private:
+		const SubstitutionModelSet* modelSet_;
+		const Alphabet            * alphabet_;
+		const DiscreteDistribution* rate_;
+		const Tree                * templateTree_;
+		mutable TreeTemplate<SNode> tree_;
+    bool ownModelSet_;
+	
+		/**
+		 * @brief This stores once for all all leaves in a given order.
+		 * This order will be used during site creation.
+		 */
+    std::vector<SNode*> leaves_;
+	
+    std::vector<std::string> seqNames_;
+
+		size_t nbNodes_;
+		size_t nbClasses_;
+		size_t nbStates_;
+
+    bool continuousRates_;
+	
+		/**
+		 * @name Stores intermediate results.
+     *
+     * @{
+		 */
+
+	public:		
+		NonHomogeneousSequenceSimulator(
+			const SubstitutionModelSet* modelSet,
+			const DiscreteDistribution* rate,
+			const Tree* tree
+		) throw (Exception);
+
+    NonHomogeneousSequenceSimulator(
+			const SubstitutionModel* model,
+			const DiscreteDistribution* rate,
+			const Tree* tree
+		);
+			
+		virtual ~NonHomogeneousSequenceSimulator()
+    {
+      if (ownModelSet_ && modelSet_) delete modelSet_;
+    }
+
+    NonHomogeneousSequenceSimulator(const NonHomogeneousSequenceSimulator& nhss) :
+      modelSet_       (nhss.modelSet_),
+      alphabet_       (nhss.alphabet_),
+      rate_           (nhss.rate_),
+      templateTree_   (nhss.templateTree_),
+      tree_           (nhss.tree_),
+      ownModelSet_    (nhss.ownModelSet_),
+      leaves_         (nhss.leaves_),
+      seqNames_       (nhss.seqNames_),
+      nbNodes_        (nhss.nbNodes_),
+      nbClasses_      (nhss.nbClasses_),
+      nbStates_       (nhss.nbStates_),
+      continuousRates_(nhss.continuousRates_)
+    {}
+
+    NonHomogeneousSequenceSimulator& operator=(const NonHomogeneousSequenceSimulator& nhss)
+    {
+      modelSet_        = nhss.modelSet_;
+      alphabet_        = nhss.alphabet_;
+      rate_            = nhss.rate_;
+      templateTree_    = nhss.templateTree_;
+      tree_            = nhss.tree_;
+      ownModelSet_     = nhss.ownModelSet_;
+      leaves_          = nhss.leaves_;
+      seqNames_        = nhss.seqNames_;
+      nbNodes_         = nhss.nbNodes_;
+      nbClasses_       = nhss.nbClasses_;
+      nbStates_        = nhss.nbStates_;
+      continuousRates_ = nhss.continuousRates_;
+      return *this;
+    }
+
+#ifndef NO_VIRTUAL_COV
+    NonHomogeneousSequenceSimulator*
+#else
+    Clonable*
+#endif
+    clone() const { return new NonHomogeneousSequenceSimulator(*this); }
+
+  private:
+    /**
+     * @brief Init all probabilities.
+     *
+     * Method called by constructors.
+     */
+    void init();
+
+	public:
+	
+		/**
+		 * @name The SiteSimulator interface
+		 *
+		 * @{
+		 */
+		Site* simulate() const;
+		Site* simulate(int ancestralState) const;
+		Site* simulate(int ancestralState, double rate) const;
+		Site* simulate(double rate) const;
+    std::vector<std::string> getSequencesNames() const { return seqNames_; }
+		/** @} */
+    
+		/**
+		 * @name The PreciseSiteSimulator interface.
+		 *
+		 * @{
+		 */
+    RASiteSimulationResult* dSimulate() const;
+    
+    RASiteSimulationResult* dSimulate(int ancestralState) const;
+    
+    RASiteSimulationResult* dSimulate(int ancestralState, double rate) const;
+
+    RASiteSimulationResult* dSimulate(double rate) const;
+		/** @} */
+
+    /**
+		 * @name The SequenceSimulator interface
+		 *
+		 * @{
+		 */
+		SiteContainer* simulate(size_t numberOfSites) const;
+		/** @} */
+    
+		/**
+		 * @name SiteSimulator and SequenceSimulator interface
+		 *
+		 * @{
+		 */
+		const Alphabet* getAlphabet() const { return alphabet_; }
+		/** @} */
+
+    /**
+     * @name Functions with rate classes instead of absolute rates.
+     *
+     * @{
+     */
+		virtual Site* simulate(int ancestralState, size_t rateClass) const;
+    virtual	RASiteSimulationResult* dSimulate(int ancestralState, size_t rateClass) const;
+    /** @} */
+	
+		/**
+		 * @brief Get the mutation process associated to this instance.
+		 *
+		 * @return The MutationProcess object associated to this instance.
+		 */
+		const SubstitutionModelSet* getSubstitutionModelSet() const { return modelSet_; }
+		
+	
+		
+		/**
+		 * @brief Get the rate distribution associated to this instance.
+		 *
+		 * @return The DiscreteDistribution object associated to this instance.
+		 */
+		const DiscreteDistribution* getRateDistribution() const { return rate_; }
+
+		/**
+		 * @brief Get the tree associated to this instance.
+		 *
+		 * @return The Tree object associated to this instance.
+		 */
+		const Tree* getTree() const { return templateTree_; }
+
+    /**
+     * @brief Enable the use of continuous rates instead of discrete rates.
+     *
+     * To work, the DiscreteDistribution object used should implement the randC method.
+     *
+     * @param yn Tell if we should use continuous rates.
+     */
+    void enableContinuousRates(bool yn) { continuousRates_ = yn; }
+	
+	protected:
+		
+		/**
+		 * @brief Evolve from an initial state along a branch, knowing the evolutionary rate class.
+		 *
+		 * This method is fast since all pijt have been computed in the constructor of the class.
+     * This method is used for the implementation of the SiteSimulator interface.
+		 */
+		int evolve(const SNode * node, int initialState, size_t rateClass) const;
+		
+		/**
+		 * @brief Evolve from an initial state along a branch, knowing the evolutionary rate.
+		 *
+		 * This method is slower than the previous one since exponential terms must be computed.
+     * This method is used for the implementation of the SiteSimulator interface.
+		 */
+		int evolve(const SNode * node, int initialState, double rate) const;
+		
+    /**
+     * @brief The same as the evolve(initialState, rateClass) function, but for several sites at a time.
+     *
+     * This method is used for the implementation of the SequenceSimulator interface.
+     */
+		void multipleEvolve(const SNode* node, const Vint& initialState, const std::vector<size_t>& rateClasses, Vint& finalStates) const;
+		SiteContainer* multipleEvolve(const Vint& initialStates, const std::vector<size_t>& rateClasses) const;
+		
+    void dEvolve(int initialState, double rate, RASiteSimulationResult& rassr) const;
+		
+    /**
+     * @name The 'Internal' methods.
+     *
+     * @{
+     */
+
+    /**
+     * This method uses the states_ variable for saving ancestral states.
+     */
+    void evolveInternal(SNode* node, size_t rateClass) const;
+    /**
+     * This method uses the states_ variable for saving ancestral states.
+     */
+		void evolveInternal(SNode* node, double rate) const;
+    /**
+     * This method uses the multipleStates_ variable for saving ancestral states.
+     */
+ 		void multipleEvolveInternal(SNode* node, const std::vector<size_t>& rateClasses) const;
+
+    /**
+     * This method uses the states_ variable for saving ancestral states.
+     */
+		void dEvolveInternal(SNode * node, double rate, RASiteSimulationResult & rassr) const;
+    /** @} */
+
+};
+
+} //end of namespace bpp.
+
+#endif //_NONHOMOGENEOUSSEQUENCESIMULATOR_H_
+
diff --git a/src/Bpp/Phyl/Simulation/SequenceSimulationTools.cpp b/src/Bpp/Phyl/Simulation/SequenceSimulationTools.cpp
new file mode 100644
index 0000000..6ae1b44
--- /dev/null
+++ b/src/Bpp/Phyl/Simulation/SequenceSimulationTools.cpp
@@ -0,0 +1,92 @@
+//
+// File: SequenceSimulationTools.cpp
+// Created by: Julien Dutheil
+// Created on: Wed Aug  24 16:25 2005
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "SequenceSimulationTools.h"
+
+// From SeqLib:
+#include <Bpp/Seq/Container/VectorSiteContainer.h>
+
+using namespace bpp;
+using namespace std;
+
+SiteContainer* SequenceSimulationTools::simulateSites(const SiteSimulator& simulator, const vector<double>& rates)
+{
+  size_t numberOfSites = rates.size();
+  vector<const Site*> vs(numberOfSites);
+  for (size_t i = 0; i < numberOfSites; i++)
+  {
+    Site* s = simulator.simulate(rates[i]);
+    s->setPosition((int)i);
+    vs[i] = s;
+  }
+  SiteContainer* sites = new VectorSiteContainer(vs, simulator.getAlphabet());
+  sites->setSequencesNames(simulator.getSequencesNames(), false);
+  // Freeing memory:
+  for (size_t i = 0; i < numberOfSites; i++)
+  {
+    delete vs[i];
+  }
+
+  return sites;
+}
+
+SiteContainer* SequenceSimulationTools::simulateSites(const SiteSimulator& simulator, const vector<double>& rates, const vector<int>& states)
+throw (Exception)
+{
+  size_t numberOfSites = rates.size();
+  if (states.size() != numberOfSites)
+    throw Exception("SequenceSimulationTools::simulateSites., 'rates' and 'states' must have the same length.");
+  vector<const Site*> vs(numberOfSites);
+  for (size_t i = 0; i < numberOfSites; i++)
+  {
+    Site* s = simulator.simulate(states[i], rates[i]);
+    s->setPosition((int)i);
+    vs[i] = s;
+  }
+  SiteContainer* sites = new VectorSiteContainer(vs, simulator.getAlphabet());
+  sites->setSequencesNames(simulator.getSequencesNames(), false);
+  // Freeing memory:
+  for (size_t i = 0; i < numberOfSites; i++)
+  {
+    delete vs[i];
+  }
+
+  return sites;
+}
+
diff --git a/src/Bpp/Phyl/Simulation/SequenceSimulationTools.h b/src/Bpp/Phyl/Simulation/SequenceSimulationTools.h
new file mode 100755
index 0000000..867dc4d
--- /dev/null
+++ b/src/Bpp/Phyl/Simulation/SequenceSimulationTools.h
@@ -0,0 +1,103 @@
+//
+// File: SequenceSimulationTools.h
+// Created by: Julien Dutheil
+// Created on: Wed Aug  24 16:25 2005
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _SEQUENCESIMULATIONTOOLS_H_
+#define _SEQUENCESIMULATIONTOOLS_H_
+
+#include "SiteSimulator.h"
+
+//From Seqlib:
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+//From the STL:
+#include <vector>
+
+namespace bpp
+{
+
+/**
+ * @brief Tools for sites and sequences simulation.
+ */
+class SequenceSimulationTools
+{
+	public:
+		SequenceSimulationTools() {}
+		~SequenceSimulationTools() {}
+
+	public:
+		
+		/**
+		 * @brief Simulate a set of sites knowing their rate.
+		 *
+		 * This method is rather slow.
+		 * consider using a discrete rate distribution and a SequenceSimulator,
+		 * which is realy faster.
+		 * This method should be used only for continuous rate distribution, or
+		 * as estimated from posterior rates for instance.
+		 *
+		 * @see SequenceSimulator
+		 * @param simulator A SiteSimulator object to use to simulate sites.
+		 * @param rates     the rates to use, one for each site to simulate.
+		 * @return          A container with all simulated sites.
+		 */
+		static SiteContainer * simulateSites(const SiteSimulator & simulator, const std::vector<double> & rates);
+
+		/**
+		 * @brief Simulate a set of sites knowing their rate and ancestral state.
+		 *
+		 * This method is rather slow.
+		 * consider using a discrete rate distribution and a SequenceSimulator,
+		 * which is realy faster.
+		 * This method should be used only for continuous rate distribution, or
+		 * as estimated from posterior rates for instance.
+		 *
+		 * @see SequenceSimulator
+		 * @param simulator A SiteSimulator object to use to simulate sites.
+		 * @param rates     the rates to use, one for each site to simulate.
+		 * @param states    the ancestral states to use, one for each site to simulate.
+		 * @return          A container with all simulated sites.
+		 */
+		static SiteContainer * simulateSites(const SiteSimulator & simulator, const std::vector<double> & rates, const std::vector<int> & states)
+			throw (Exception);
+};
+
+} //end of namespace bpp.
+
+#endif //_SEQUENCESIMULATIONTOOLS_H_
+
diff --git a/src/Bpp/Phyl/Simulation/SequenceSimulator.h b/src/Bpp/Phyl/Simulation/SequenceSimulator.h
new file mode 100755
index 0000000..599c3db
--- /dev/null
+++ b/src/Bpp/Phyl/Simulation/SequenceSimulator.h
@@ -0,0 +1,74 @@
+//
+// File: SequenceSimulator.h
+// Created by: Julien Dutheil
+// Created on: Wed Feb  4 16:30:51 2004
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _SEQUENCESIMULATOR_H_
+#define _SEQUENCESIMULATOR_H_
+
+#include <Bpp/Clonable.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The SequenceSimulator interface.
+ * SequenceSimulator classes can simulate whole datasets.
+ */
+class SequenceSimulator:
+  public virtual Clonable
+{
+  public:
+    SequenceSimulator() {}
+    virtual ~SequenceSimulator() {}
+
+#ifndef NO_VIRTUAL_COV
+    SequenceSimulator * clone() const = 0;
+#endif
+  
+  public:
+    virtual SiteContainer * simulate(size_t numberOfSites) const = 0;
+    virtual const Alphabet * getAlphabet() const = 0;  
+};
+
+} //end of namespace bpp.
+
+#endif  //_SEQUENCESIMULATOR_H_
+
diff --git a/src/Bpp/Phyl/Simulation/SiteSimulator.h b/src/Bpp/Phyl/Simulation/SiteSimulator.h
new file mode 100755
index 0000000..e5c5361
--- /dev/null
+++ b/src/Bpp/Phyl/Simulation/SiteSimulator.h
@@ -0,0 +1,73 @@
+//
+// File: SiteSimulator.h
+// Created by: Julien Dutheil
+// created on: wed aug  24 15:20 2005
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _SITESIMULATOR_H_
+#define _SITESIMULATOR_H_
+
+// From SeqLib:
+#include <Bpp/Seq/Site.h>
+
+namespace bpp
+{
+
+/**
+ * @brief The SiteSimulator interface.
+ * SiteSimulator classes can simulate single sites.
+ *
+ * @see SequenceSimulator interface for simulating whole sequence sets.
+ */
+class SiteSimulator
+{
+  public:
+    SiteSimulator() {}
+    virtual ~SiteSimulator() {}
+    
+  public:
+    virtual Site * simulate() const = 0;
+    virtual Site * simulate(int ancestralState) const = 0;
+    virtual Site * simulate(int ancestralState, double rate) const = 0;
+    virtual Site * simulate(double rate) const = 0;
+    virtual std::vector<std::string> getSequencesNames() const = 0;
+    virtual const Alphabet * getAlphabet() const = 0;
+};
+
+} //end of namespace bpp.
+
+#endif // _SITESIMULATOR_H_
+
diff --git a/src/Bpp/Phyl/SitePatterns.cpp b/src/Bpp/Phyl/SitePatterns.cpp
new file mode 100644
index 0000000..904c2e8
--- /dev/null
+++ b/src/Bpp/Phyl/SitePatterns.cpp
@@ -0,0 +1,118 @@
+//
+// File: SitePatterns.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Nov 29 15:37 2005
+//  from file PatternTools.cpp
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "SitePatterns.h"
+
+// From the SeqLib library:
+#include <Bpp/Seq/SiteTools.h>
+#include <Bpp/Seq/Container/VectorSiteContainer.h>
+
+using namespace bpp;
+using namespace std;
+
+/******************************************************************************/
+
+SitePatterns::SitePatterns(const SiteContainer* sequences, bool own) :
+  names_(sequences->getSequencesNames()),
+  sites_(),
+  weights_(),
+  indices_(),
+  sequences_(sequences),
+  alpha_(sequences->getAlphabet()),
+  own_(own)
+{
+  size_t nbSites = sequences->getNumberOfSites();
+  vector<SortableSite> ss(nbSites);
+  for (size_t i = 0; i < nbSites; i++)
+  {
+    const Site* currentSite = &sequences->getSite(i);
+    SortableSite* ssi = &ss[i];
+    ssi->siteS = currentSite->toString();
+    ssi->siteP = currentSite;
+    ssi->originalPosition = i;
+  }
+
+  if (nbSites > 0)
+  {
+    // Quick sort according to site contents:
+    sort(ss.begin(), ss.end());
+
+    // Now build patterns:
+
+    SortableSite* ss0 = &ss[0];
+    const Site* previousSite = ss0->siteP;
+    indices_.resize(nbSites);
+    indices_[ss0->originalPosition] = 0;
+    sites_.push_back(previousSite);
+    weights_.push_back(1);
+
+    unsigned int currentPos = 0;
+    for (unsigned int i = 1; i < nbSites; i++)
+    {
+      SortableSite* ssi = &ss[i];
+      const Site* currentSite = ssi->siteP;
+      bool siteExists = SiteTools::areSitesIdentical(*currentSite, *previousSite);
+      if (siteExists)
+      {
+        weights_[currentPos]++;
+      }
+      else
+      {
+        sites_.push_back(currentSite);
+        weights_.push_back(1);
+        currentPos++;
+      }
+      indices_[ssi->originalPosition] = currentPos;
+      previousSite = currentSite;
+    }
+  }
+}
+
+/******************************************************************************/
+
+SiteContainer* SitePatterns::getSites() const
+{
+  SiteContainer* sites = new VectorSiteContainer(sites_, alpha_);
+  sites->setSequencesNames(names_, false);
+  return sites;
+}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/SitePatterns.h b/src/Bpp/Phyl/SitePatterns.h
new file mode 100755
index 0000000..f177a6e
--- /dev/null
+++ b/src/Bpp/Phyl/SitePatterns.h
@@ -0,0 +1,187 @@
+//
+// File: SitePatterns.h
+// Created by: Julien Dutheil
+// Created on: Tue Nov 29 15:37 2005
+//  from file PatternTools.h
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+ 
+#ifndef _SITEPATTERNS_H_
+#define _SITEPATTERNS_H_
+
+#include "Tree.h"
+
+#include <Bpp/Clonable.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+//From bpp-seq:
+#include <Bpp/Seq/Site.h>
+#include <Bpp/Seq/Container/SiteContainer.h>
+
+// From the STL:
+#include <map>
+#include <vector>
+#include <string>
+
+namespace bpp
+{
+
+/**
+ * @brief Data structure for site patterns.
+ * 
+ * 'names' are the sequence names
+ * 'sites' points toward a unique site
+ * 'weights' is the number of sites identical to this sites
+ * 'indices' are the positions in the original container
+ */
+class SitePatterns :
+  public virtual Clonable
+{
+  private:
+    /**
+     * @brief Class used for site pattern sorting.
+     */
+    class SortableSite
+    {
+	    public:
+        std::string siteS; 
+		    const Site* siteP;
+		    size_t originalPosition;
+	    
+      public:
+		    SortableSite() : siteS(), siteP(0), originalPosition(0) {}
+        SortableSite(const SortableSite& ss) : siteS(ss.siteS), siteP(ss.siteP), originalPosition(ss.originalPosition) {}
+        SortableSite& operator=(const SortableSite& ss)
+        {
+          siteS = ss.siteS;
+          siteP = ss.siteP;
+          originalPosition = ss.originalPosition;
+          return *this;
+        }
+
+        bool operator<(const SortableSite& ss) const { return siteS < ss.siteS; }
+
+		    virtual ~SortableSite() {}
+    };
+
+    ///**
+    // * @brief Class used for site pattern sorting.
+    // */
+    //struct SSComparator :
+    //  std::binary_function<SortableSite, SortableSite, bool>
+    //{
+	  //  bool operator()(const SortableSite& ss1, const SortableSite& ss2) const { return ss1.siteS < ss2.siteS; }
+    //};
+
+  private: 
+    std::vector<std::string> names_;
+    std::vector<const Site *> sites_;
+    std::vector<unsigned int> weights_;
+    std::vector<size_t> indices_;
+    const SiteContainer* sequences_;
+    const Alphabet* alpha_;
+    bool own_;
+
+  public:
+   /**
+     * @brief Build a new SitePattern object.
+     *
+     * Look for patterns (unique sites) within a site container.
+     *
+     * @param sequences The container to look in.
+     * @param own       Tel is the class own the sequence container.
+     * If yes, the sequences wll be deleted together with this instance.
+     */
+    SitePatterns(const SiteContainer* sequences, bool own = false);
+
+    virtual ~SitePatterns()
+    {
+      if(own_) delete sequences_;
+    }
+
+    SitePatterns(const SitePatterns& patterns) :
+  	  names_(patterns.names_),
+	    sites_(patterns.sites_),
+	    weights_(patterns.weights_),
+	    indices_(patterns.indices_),
+      sequences_(0),
+      alpha_(patterns.alpha_),
+      own_(patterns.own_)
+    {
+      if(!patterns.own_) sequences_ = patterns.sequences_;
+      else               sequences_ = dynamic_cast<SiteContainer*>(patterns.sequences_->clone());
+    }
+
+    SitePatterns& operator=(const SitePatterns& patterns)
+    {
+  	  names_     = patterns.names_;
+	    sites_     = patterns.sites_;
+	    weights_   = patterns.weights_;
+	    indices_   = patterns.indices_;
+      if(!patterns.own_) sequences_ = patterns.sequences_;
+      else               sequences_ = dynamic_cast<SiteContainer*>(patterns.sequences_->clone());
+      alpha_     = patterns.alpha_;
+      own_       = patterns.own_;
+      return *this;
+    }
+
+#ifdef NO_VIRTUAL_COV
+    Clonable*
+#else
+    SitePatterns *
+#endif
+    clone() const { return new SitePatterns(*this); }
+
+  public:
+    /**
+     * @return The number of times each unique site was found.
+     */
+		const std::vector<unsigned int>& getWeights() const { return weights_; }
+    /**
+     * @return The position of each unique site.
+     */
+		const std::vector<size_t>& getIndices() const { return indices_; }
+
+    /**
+     * @return A new container with each unique site.
+     */
+		SiteContainer* getSites() const;
+    
+};
+
+} //end of namespace bpp.
+
+#endif // _SITEPATTERNS_H_
+
diff --git a/src/Bpp/Phyl/TopologySearch.h b/src/Bpp/Phyl/TopologySearch.h
new file mode 100755
index 0000000..c95f628
--- /dev/null
+++ b/src/Bpp/Phyl/TopologySearch.h
@@ -0,0 +1,157 @@
+//
+// File: TopologySearch.h
+// Created by: Julien Dutheil
+// Created on: Wed Oct 12 10:18 2005
+//
+
+/*
+Copyright or © or Copr. CNRS, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _TOPOLOGYSEARCH_H_
+#define _TOPOLOGYSEARCH_H_
+
+#include <Bpp/Exceptions.h>
+#include <Bpp/Clonable.h>
+
+// From the STL:
+#include <string>
+#include <vector>
+
+namespace bpp
+{
+
+/**
+ * @brief Class for notifying new toplogy change events.
+ */
+class TopologyChangeEvent
+{
+	protected:
+    std::string message_;
+		
+	public:
+		TopologyChangeEvent(): message_("") {}
+		TopologyChangeEvent(const std::string& message): message_(message) {}
+		virtual ~TopologyChangeEvent() {}
+
+	public:
+		/**
+		 * @brief Get the message associated to this event.
+		 *
+		 * @return The message associated to this event.
+		 */
+		virtual const std::string& getMessage() const { return message_; }
+
+};
+
+class TopologySearch;
+
+/**
+ * @brief Implement this interface to be notified when the topology of a tree
+ * has changed during topology search.
+ */
+class TopologyListener :
+  public virtual Clonable
+{
+  public:
+    TopologyListener() {}
+    virtual ~TopologyListener() {}
+
+#ifndef NO_VIRTUAL_COV
+    TopologyListener* clone() const = 0;
+#endif
+
+  public:
+		/**
+		 * @brief Notify a topology change event.
+		 *
+		 * This method is to be invoked after one or several NNI are performed.
+		 * It allows appropriate recomputations.
+     *
+     * In most case, this is the same as
+     * topologyChangeTested() + topologyChangeSuccessful().
+		 *
+		 * @param event The topology change event.
+		 */
+    virtual void topologyChangePerformed(const TopologyChangeEvent& event)
+    {
+      topologyChangeTested(event);
+      topologyChangeSuccessful(event);
+    }
+		/**
+		 * @brief Notify a topology change event.
+		 *
+		 * @param event The topology change event.
+		 */
+    virtual void topologyChangeTested(const TopologyChangeEvent& event) = 0;
+
+    /**
+     * @brief Tell that a topology change is definitive.
+     *
+     * This method is called after the topologyChangeTested() method.
+     *
+		 * @param event The topology change event.
+     */
+    virtual void topologyChangeSuccessful(const TopologyChangeEvent& event) = 0;
+
+};
+
+
+
+/**
+ * @brief Interface for topology search methods.
+ */
+class TopologySearch
+{
+	public:
+		TopologySearch() {}
+		virtual ~TopologySearch() {}
+
+	public:
+
+		/**
+		 * @brief Performs the search.
+		 */
+		virtual void search() throw (Exception) = 0;
+
+    /**
+     * @brief Add a topology listener to this class.
+     *
+     * TopologyListeners will be notified when the topology of the tree is modified. 
+     */
+    virtual void addTopologyListener(TopologyListener* listener) = 0;			
+};
+
+} //end of namespace bpp.
+
+#endif //_TOPOLOGYSEARCH_H_
+
diff --git a/src/Bpp/Phyl/Tree.h b/src/Bpp/Phyl/Tree.h
new file mode 100755
index 0000000..a37e3d7
--- /dev/null
+++ b/src/Bpp/Phyl/Tree.h
@@ -0,0 +1,410 @@
+//
+// File: Tree.h
+// Created by: Julien Dutheil
+// Created on: Thu Mar 13 12:03:18 2003
+//
+
+/*
+  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+  This software is a computer program whose purpose is to provide classes
+  for phylogenetic data analysis.
+
+  This software is governed by the CeCILL  license under French law and
+  abiding by the rules of distribution of free software.  You can  use, 
+  modify and/ or redistribute the software under the terms of the CeCILL
+  license as circulated by CEA, CNRS and INRIA at the following URL
+  "http://www.cecill.info". 
+
+  As a counterpart to the access to the source code and  rights to copy,
+  modify and redistribute granted by the license, users are provided only
+  with a limited warranty  and the software's author,  the holder of the
+  economic rights,  and the successive licensors  have only  limited
+  liability. 
+
+  In this respect, the user's attention is drawn to the risks associated
+  with loading,  using,  modifying and/or developing or reproducing the
+  software by the user in light of its specific status of free software,
+  that may mean  that it is complicated to manipulate,  and  that  also
+  therefore means  that it is reserved for developers  and  experienced
+  professionals having in-depth computer knowledge. Users are therefore
+  encouraged to load and test the software's suitability as regards their
+  requirements in conditions enabling the security of their systems and/or 
+  data to be ensured and,  more generally, to use and operate it in the 
+  same conditions as regards security. 
+
+  The fact that you are presently reading this means that you have had
+  knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _TREE_H_
+#define _TREE_H_
+
+#include "TreeExceptions.h"
+
+// From Utils:
+#include <Bpp/Clonable.h>
+
+// From the STL:
+#include <string>
+#include <vector>
+#include <map>
+
+/**
+ * @mainpage
+ *
+ * @section tree Tree data storage and manipulation
+ *
+ * @par
+ * The Bio++ Phylogenetics Library (PhylLib) provides classes and methods for phylogenetics and molecular evolution.
+ * The bpp::Tree interface provides general methods to store and manipulate phylogenetic trees.
+ * Several utilitary methods can also be found in the bpp::TreeTools static class.
+ * The only implementation for now of the bpp::Tree interface is the bpp::TreeTemplate class.
+ * It uses a recursive storage of bpp::Node objects (or any class inheriting from it).
+ * The bpp::Node object contains methods to access the father and son nodes in the hierarchy, and several fields like a name,
+ * an id or the length of the branch connected to its father. It also includes support for node and branch properties (like
+ * bootstrap values) that can be attached to and manipulated together with the tree.
+ * The bpp::NodeTemplate class can be used in order to extend the tree structure and add more complex
+ * data to the tree. The corresponding bpp::TreeTemplateTools provide specific methods, in most cases more efficient
+ * than their equivalent in the bpp::TreeTools.
+ *
+ * @par
+ * Trees can also be read and written from/to files, using the bpp::Newick class.
+ *
+ *
+ * @section reconstruction Phylogenetic reconstruction methods
+ *
+ * @par
+ * PhylLib provides tools to reconstruct phylogenies from sequence data, using maximum parsimony, distance-based methods 
+ * and maximum likelihood, all of them implemented in an object-oriented way, and hence involving several classes.
+ *
+ * @par Maximum parcimony
+ * See bpp::TreeParsimonyScore for parsimony score computation. Only a Nearest Neighbor Interchange (NNI) algorithm for
+ * topology estimation is provided for now, see bpp::NNISearchable, bpp::NNITopologySearch and bpp::OptimizationTools for
+ * more user-friendly methods.
+ *
+ * @par Distance methods
+ * The bpp::DistanceEstimation class allows you to compute pairwise distances from a large set of models (see next section),
+ * and store them as a bpp::DistanceMatrix. This matrix is the input of any distance-based method.
+ * The (U/W)PGMA (bpp::PGMA), neighbor-joining (bpp::NeighborJoining) and BioNJ (bpp::BioNJ) methods are implemented.
+ *
+ * @par Maximum likelihood methods
+ * Use a model to describe the evolutionary process, among many available (see next section).
+ * Support for homogeneous (reversible or not) and non-homogeneous models is provided. Several likelihood computation
+ * algorithms are provided, depending on the final usage. All classes are instances of the bpp::TreeLikelihood interface.
+ * The bpp::DiscreteRatesAcrossSitesTreeLikelihood interface adds support for rate heterogeneity across sites.
+ * - The bpp::RHomogeneousTreeLikelihood class is the most simple implementation. It uses Felsenstein's recursion.
+ *   The possibility of compressing sites save comptation time and memory.
+ * - The bpp::DRHomogeneousTreeLikelihood class is similar to the previous one, but uses a double-recursive algorithm.
+ *   It is more CPU expensive when computing likelihoods, and uses more memory. Computation of branch length analytical 
+ *   derivatives is nonetheless faster, since they do not involve any additionnal recursion.
+ *   You also have to use this class in order to perform substitution mapping (bpp::SubstitutionMappingTools) or reconstruct
+ *   ancestral sequences (bpp::AncestralStateReconstruction).
+ * - The bpp::NNIHomogeneousTreeLikelihood class inherits from bpp::DRHomogeneousTreeLikelihood, and implements the bpp::NNISearchable
+ *   interface. This class should hence be used in order to optimize the tree topology.
+ * - The bpp::RNonHomogeneousTreeLikelihood and bpp::DRNonHomogeneousTreeLikelihood are similar to their homogeneous homologues,
+ *   but are designed for non-reversible or non-homogeneous models of substitution.
+ * - Finally, the bpp::ClockTreeLikelihood interface uses a different parametrization by assuming a global molecular clock.
+ *   It is implemented in the bpp::RHomogeneousClockTreeLikelihood class, which inherits from bpp::RHomogeneousTreeLikelihood.
+ *
+ * @par 
+ * The bpp::TreeLikelihood class inherits from the bpp::Function interface, which means that any optimization method from
+ * the NumCalc library can be used to estimate numerical parameters. The bpp::OptimizationTools static class provides
+ * general methods with predefined options, including for topology estimation.
+ *
+ *
+ * @section models Evolutionary models
+ *
+ * @par
+ * The Bio++ phylogenetic library provides different kinds of models.
+ * Substitution models are provided via the bpp::SubstitutionModel interface.
+ * All commonly used models for nucleotides and proteins are provided (see for instance bpp::JCnuc, bpp::K80, bpp::GTR, bpp::JTT92, etc.).
+ * You can add your own model by implementing the bpp::SubstitutionModel interface.
+ * Rate across sites (RAS) models are integrated thanks to the bpp::DiscreteDistribution interface, providing support for the gamma
+ * (bpp::GammaDiscreteDistribution) and gamma+invariant (bpp::InvariantMixedDiscreteDistribution) rate distributions.
+ * Here again, this is very easy to add support for new rate distributions by implementing the corresponding interface.
+ * 
+ * @par
+ * Markov-modulated Markov models (of which the covarion model is a particular case) are included via the bpp::MarkovModulatedSubstitutionModel interface,
+ * and its implementation bpp::G2001 and bpp::TS98.
+ *
+ * @par
+ * Finally from version 1.5, it is possible to build virtually any kind of non-homogeneous model thanks to the bpp::SubstitutionModelSet class.
+ *
+ *
+ * @section more And more...
+ *
+ * @par
+ * PhylLib allows you to perform a lot of analysis, like evolutionary rate estimation, tree consensus, etc.
+ *
+ */
+
+namespace bpp
+{
+
+  /**
+   * @brief Interface for phylogenetic tree objects. 
+   */
+  class Tree:
+    public virtual Clonable
+  {
+
+  public: // Constructors and destructor:
+		
+    Tree() {}
+    virtual ~Tree() {}
+
+    Tree* clone() const = 0;
+
+    /**
+     * @brief clones a Subtree rooted at given node Id
+     *
+     **/
+    
+    virtual Tree* cloneSubtree(int newRootId) const = 0;
+  public:
+		
+    /**
+     * @brief Tree name.
+     *
+     * @{
+     */
+    virtual std::string getName() const = 0;
+		
+    virtual void setName(const std::string& name) = 0;
+    /** @} */
+		
+    virtual size_t getNumberOfLeaves() const = 0;
+		
+    virtual size_t getNumberOfNodes() const = 0;
+
+    virtual std::vector<double> getBranchLengths() const = 0;
+
+    virtual std::vector<std::string> getLeavesNames() const = 0;
+
+    /**
+     * @name Retrieving ids.
+     *
+     * @{
+     */
+    virtual int getRootId() const = 0;
+
+    virtual int getLeafId(const std::string& name) const throw (NodeNotFoundException)= 0;
+	
+    virtual std::vector<int> getLeavesId() const = 0;
+
+    virtual std::vector<int> getNodesId() const = 0;
+		
+    virtual std::vector<int> getInnerNodesId() const = 0;
+		
+    virtual std::vector<int> getBranchesId() const = 0;
+
+    virtual std::vector<int> getSonsId(int parentId) const throw (NodeNotFoundException) = 0;
+
+    virtual std::vector<int> getAncestorsId(int nodeId) const throw (NodeNotFoundException) = 0;
+
+    virtual int getFatherId(int parentId) const throw (NodeNotFoundException) = 0;
+
+    virtual bool hasFather(int nodeId) const throw (NodeNotFoundException) = 0;
+
+/** @} */
+
+    /**
+     * @name Dealing with node names.
+     *
+     * @{
+     */
+    virtual std::string getNodeName(int nodeId) const throw (NodeNotFoundException) = 0;
+		
+    virtual void setNodeName(int nodeId, const std::string& name) throw (NodeNotFoundException) = 0;
+		
+    virtual void deleteNodeName(int nodeId) throw (NodeNotFoundException) = 0;
+		
+    virtual bool hasNodeName(int nodeId) const throw (NodeNotFoundException) = 0;
+    /** @} */
+		
+    /**
+     * @name Several tests.
+     *
+     * @{
+     */
+    virtual bool hasNode(int nodeId) const = 0;
+
+    virtual bool isLeaf(int nodeId) const throw (NodeNotFoundException) = 0;
+
+    virtual bool isRoot(int nodeId) const throw (NodeNotFoundException) = 0;
+    /** @} */
+
+    /**
+     * @name Acting on topology.
+     *
+     * @{
+     */
+
+    /**
+     * @brief Swap two son nodes.
+     *
+     * @param tree The tree.
+     * @param nodeId The node.
+     * @param i1 First son node index.
+     * @param i2 Second son node index.
+     * @throw NodeNotFoundException If the node is not found.
+     * @throw IndexOutOfBoundsException If one node index is not valid, or if the node
+     */
+    void swapNodes(const Tree& tree, int nodeId, size_t i1 = 0, size_t i2 = 1) throw (NodeNotFoundException,IndexOutOfBoundsException);
+  
+    /** @} */
+
+    /**
+     * @name Dealing with branch lengths.
+     *
+     * @{
+     */
+    virtual double getDistanceToFather(int nodeId) const = 0;
+		
+    virtual void setDistanceToFather(int nodeId, double length) = 0;
+		
+    virtual void deleteDistanceToFather(int nodeId) = 0;
+		
+    virtual bool hasDistanceToFather(int nodeId) const = 0;
+    /** @} */
+
+    /**
+     * @name Node properties.
+     *
+     * @{
+     */
+    virtual bool hasNodeProperty(int nodeId, const std::string& name) const throw (NodeNotFoundException) = 0;
+		
+    virtual void setNodeProperty(int nodeId, const std::string& name, const Clonable& property) throw (NodeNotFoundException) = 0;
+				
+    virtual Clonable* getNodeProperty(int nodeId, const std::string& name) throw (NodeNotFoundException) = 0;
+				
+    virtual const Clonable* getNodeProperty(int nodeId, const std::string& name) const throw (NodeNotFoundException) = 0;
+				
+    virtual Clonable* removeNodeProperty(int nodeId, const std::string& name) throw (NodeNotFoundException) = 0;
+
+    virtual std::vector<std::string> getNodePropertyNames(int nodeId) const throw (NodeNotFoundException) = 0;
+    /** @} */
+		
+    /**
+     * @name Branch properties.
+     *
+     * @{
+     */
+    virtual bool hasBranchProperty(int nodeId, const std::string& name) const throw (NodeNotFoundException) = 0;
+		
+    virtual void setBranchProperty(int nodeId, const std::string& name, const Clonable & property) throw (NodeNotFoundException) = 0;
+				
+    virtual Clonable* getBranchProperty(int nodeId, const std::string& name) throw (NodeNotFoundException) = 0;
+				
+    virtual const Clonable* getBranchProperty(int nodeId, const std::string& name) const throw (NodeNotFoundException) = 0;
+				
+    virtual Clonable* removeBranchProperty(int nodeId, const std::string& name) throw (NodeNotFoundException) = 0;
+
+    virtual std::vector<std::string> getBranchPropertyNames(int nodeId) const throw (NodeNotFoundException) = 0;
+    /** @} */
+
+    /**
+     * @brief Change the root node.
+     *
+     * Works on unrooted tree.
+     * If the tree is rooted, the method unroots it first.
+     *
+     * @param nodeId The id of the node that will be the new root.
+     */
+    virtual void rootAt(int nodeId) throw (NodeNotFoundException) = 0;
+
+    /**
+     * @brief Root a tree by specifying an outgroup.
+     *
+     * If the tree is rooted, unroot it first, change the root node and then
+     * reroot the tree using the previous root id.
+     * If the tree is unrooted, change the root node and then create a new root node.
+     *
+     * @param nodeId The id of the node that will be the new root.
+     */
+    virtual void newOutGroup(int nodeId) throw (NodeNotFoundException) = 0;
+		
+    /**
+     * @brief Tell if the tree is rooted.
+     * 
+     * @return True if the tree is rooted.
+     */
+    virtual bool isRooted() const = 0;
+		
+    /**
+     * @brief Unroot a rooted tree.
+     *
+     * @return True if the tree has been unrooted.
+     * @throw UnrootedTreeException If the tree is already rooted.
+     */
+    virtual bool unroot() throw (UnrootedTreeException) = 0;
+
+    /**
+     * @brief Number nodes.
+     */
+    virtual void resetNodesId() = 0;
+		
+    // Works on (multi)furcations:
+		
+    /**
+     * @brief Tell if the tree is multifurcating.
+     * 
+     * @return True if the tree is multifurcating.
+     */
+    virtual bool isMultifurcating() const = 0;
+		
+    /**
+     * @brief Get all the branch lengths of a tree.
+     *
+     * @return A vector with all branch lengths.
+     * @throw NodeException If a branch length is lacking.
+     */
+    virtual std::vector<double> getBranchLengths() throw (NodeException) = 0;
+
+    /**
+     * @brief Get the total length (sum of all branch lengths) of a tree.
+     *
+     * @return The total length of the subtree.
+     * @throw NodeException If a branch length is lacking.
+     */
+    virtual double getTotalLength() throw (NodeException) = 0;
+
+    /**
+     * @brief Set all the branch lengths of a tree.
+     *
+     * @param brLen The branch length to apply.
+     */
+    virtual void setBranchLengths(double brLen) = 0;
+		
+    /**
+     * @brief Give a length to branches that don't have one in a tree.
+     *
+     * @param brLen The branch length to apply.
+     */
+    virtual void setVoidBranchLengths(double brLen) = 0;
+	
+    /**
+     * @brief Scale a given tree.
+     *
+     * Multiply all branch lengths by a given factor.
+     *
+     * @param factor The factor to multiply all branch lengths with.
+     * @throw NodeException If a branch length is lacking.
+     */
+    virtual void scaleTree(double factor) throw (NodeException) = 0;
+
+    /**
+     * @brief Get an id.
+     *
+     * @return an unused node id.
+     */
+    virtual int getNextId() = 0;
+
+  };
+
+} //end of namespace bpp.
+
+#endif	//_TREE_H_
+
diff --git a/src/Bpp/Phyl/TreeExceptions.cpp b/src/Bpp/Phyl/TreeExceptions.cpp
new file mode 100755
index 0000000..76344ce
--- /dev/null
+++ b/src/Bpp/Phyl/TreeExceptions.cpp
@@ -0,0 +1,78 @@
+//
+// File: TreeExceptions.cpp
+// Created by: Julien Dutheil
+// Created on: Mon Nov  3 17:04:46 2003
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   Julien.Dutheil at univ-montp2.fr
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "TreeExceptions.h"
+#include "Node.h"
+#include "Tree.h"
+
+#include <Bpp/Text/TextTools.h>
+
+using namespace bpp;
+
+/******************************************************************************/
+
+NodePException::NodePException(const std::string& text, const Node* node) :
+    NodeException(text, node->getId()), node_(node)
+{}
+
+/******************************************************************************/
+
+NodeNotFoundException::NodeNotFoundException(const std::string& text, const std::string& id) :
+  Exception("NodeNotFoundException: " + text + "(" + id + ")"),
+  id_(id) {}
+
+NodeNotFoundException::NodeNotFoundException(const std::string& text, int id) :
+  Exception("NodeNotFoundException: " + text + "(" + TextTools::toString(id) + ")"),
+  id_(TextTools::toString(id)) {}
+
+/******************************************************************************/
+
+TreeException::TreeException(const std::string& text, const Tree* tree) :
+  Exception("TreeException: " + text + (tree != 0 ? "(" + tree->getName() + ")" : "")),
+  tree_(tree) {}
+
+/******************************************************************************/
+
+UnrootedTreeException::UnrootedTreeException(const std::string& text, const Tree* tree) :
+  TreeException("UnrootedTreeException: " + text, tree) {}
+
+/******************************************************************************/
+
diff --git a/src/Bpp/Phyl/TreeExceptions.h b/src/Bpp/Phyl/TreeExceptions.h
new file mode 100755
index 0000000..54d5f38
--- /dev/null
+++ b/src/Bpp/Phyl/TreeExceptions.h
@@ -0,0 +1,281 @@
+//
+// File: TreeExceptions.h
+// Created by: Julien Dutheil
+// Created on: Mon Nov  3 17:04:46 2003
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _TREEEXCEPTIONS_H_
+#define _TREEEXCEPTIONS_H_
+
+#include <Bpp/Exceptions.h>
+#include <Bpp/Text/TextTools.h>
+
+// From the STL:
+#include <string>
+
+namespace bpp
+{
+class Node;
+class Tree;
+
+/**
+ * @brief General exception thrown when something is wrong with a particular node.
+ */
+class NodeException :
+  public Exception
+{
+protected:
+  int nodeId_;
+
+public:
+  /**
+   * @brief Build a new NodePException.
+   * @param text A message to be passed to the exception hierarchy.
+   * @param nodeId The id of the node that threw the exception.
+   */
+  NodeException(const std::string& text, int nodeId) :
+    Exception("NodeException: " + text + "(id:" + TextTools::toString(nodeId) + ")"),
+    nodeId_(nodeId) {}
+
+  virtual ~NodeException() throw () {}
+
+public:
+  /**
+   * @brief Get the id of node that threw the exception.
+   *
+   * @return The id of the faulty node.
+   */
+  virtual int getNodeId() const { return nodeId_; }
+};
+
+
+/**
+ * @brief General exception thrown when something is wrong with a particular node.
+ */
+class NodePException :
+  public NodeException
+{
+private:
+  const Node* node_;
+
+public:
+  /**
+   * @brief Build a new NodePException.
+   * @param text A message to be passed to the exception hierarchy.
+   * @param node A const pointer toward the node that threw the exception.
+   */
+  NodePException(const std::string& text, const Node* node = 0);
+
+  /**
+   * @brief Build a new NodePException.
+   * @param text A message to be passed to the exception hierarchy.
+   * @param nodeId The id of the node that threw the exception.
+   */
+  NodePException(const std::string& text, int nodeId) :
+    NodeException(text, nodeId), node_(0) {}
+
+  NodePException(const NodePException& nex) :
+    NodeException(nex),
+    node_(nex.node_)
+  {}
+
+  NodePException& operator=(const NodePException& nex)
+  {
+    NodeException::operator=(nex);
+    node_ = nex.node_;
+    return *this;
+  }
+
+  virtual ~NodePException() throw () {}
+
+public:
+  /**
+   * @brief Get the node that threw the exception.
+   *
+   * @return A pointer toward the faulty node.
+   */
+  virtual const Node* getNode() const { return node_; };
+  /**
+   * @brief Get the id of node that threw the exception.
+   *
+   * @return The id of the faulty node.
+   */
+  virtual int getNodeId() const { return nodeId_; }
+};
+
+/**
+ * @brief General exception thrown if a property could not be found.
+ */
+class PropertyNotFoundException :
+  public NodePException
+{
+private:
+  std::string propertyName_;
+
+public:
+  /**
+   * @brief Build a new PropertyNotFoundException.
+   *
+   * @param text A message to be passed to the exception hierarchy.
+   * @param propertyName The name of the property.
+   * @param node A const pointer toward the node that threw the exception.
+   */
+  PropertyNotFoundException(const std::string& text, const std::string& propertyName, const Node* node = 0) :
+    NodePException("Property not found: " + propertyName + ". " + text, node),
+    propertyName_(propertyName) {}
+
+  /**
+   * @brief Build a new PropertyNotFoundException.
+   *
+   * @param text A message to be passed to the exception hierarchy.
+   * @param propertyName The name of the property.
+   * @param nodeId The id of the node that threw the exception.
+   */
+  PropertyNotFoundException(const std::string& text, const std::string& propertyName, int nodeId) :
+    NodePException("Property not found: " + propertyName + ". " + text, nodeId),
+    propertyName_(propertyName) {}
+
+  virtual ~PropertyNotFoundException() throw () {}
+
+public:
+  /**
+   * @brief Get the name of the property that could not be found.
+   *
+   * @return The name of the missing property.
+   */
+  virtual const std::string& getPropertyName() const { return propertyName_; }
+};
+
+/**
+ * @brief Exception thrown when something is wrong with a particular node.
+ */
+class NodeNotFoundException :
+  public Exception
+{
+private:
+  std::string id_;
+
+public:
+  /**
+   * @brief Build a new NodeNotFoundException.
+   *
+   * @param text A message to be passed to the exception hierarchy.
+   * @param id   A string describing the node.
+   */
+  NodeNotFoundException(const std::string& text, const std::string& id);
+
+  /**
+   * @brief Build a new NodeNotFoundException.
+   *
+   * @param text A message to be passed to the exception hierarchy.
+   * @param id   A node identifier.
+   */
+  NodeNotFoundException(const std::string& text, int id);
+
+  virtual ~NodeNotFoundException() throw () {}
+
+public:
+  /**
+   * @brief Get the node id that threw the exception.
+   *
+   * @return The id of the node.
+   */
+  virtual std::string getId() const { return id_; }
+};
+
+/**
+ * @brief General exception thrown when something wrong happened in a tree.
+ */
+class TreeException :
+  public Exception
+{
+private:
+  const Tree* tree_;
+
+public:
+  /**
+   * @brief Build a new TreeException.
+   *
+   * @param text A message to be passed to the exception hierarchy.
+   * @param tree A const pointer toward the tree that threw the exception.
+   */
+  TreeException(const std::string& text, const Tree* tree = 0);
+
+  TreeException(const TreeException& tex) :
+    Exception(tex),
+    tree_(tex.tree_)
+  {}
+
+  TreeException& operator=(const TreeException& tex)
+  {
+    Exception::operator=(tex);
+    tree_ = tex.tree_;
+    return *this;
+  }
+
+  virtual ~TreeException() throw () {}
+
+public:
+  /**
+   * @brief Get the tree that threw the exception.
+   *
+   * @return The faulty tree
+   */
+  virtual const Tree* getTree() const { return tree_; }
+};
+
+/**
+ * @brief Exception thrown when a tree is expected to be rooted.
+ */
+class UnrootedTreeException :
+  public TreeException
+{
+public:
+  /**
+   * @brief Build a new UnrootedTreeException.
+   *
+   * @param text A message to be passed to the exception hierarchy.
+   * @param tree A const pointer toward the tree that threw the exception.
+   */
+  UnrootedTreeException(const std::string& text, const Tree* tree = 0);
+
+  virtual ~UnrootedTreeException() throw () {}
+};
+
+} // end of namespace bpp.
+
+#endif  // _TREEEXCEPTIONS_H_
+
diff --git a/src/Bpp/Phyl/TreeTemplate.h b/src/Bpp/Phyl/TreeTemplate.h
new file mode 100644
index 0000000..040ea7d
--- /dev/null
+++ b/src/Bpp/Phyl/TreeTemplate.h
@@ -0,0 +1,541 @@
+//
+// File: TreeTemplate.h
+// Created by: Julien Dutheil
+//             Celine Scornavacca
+// Created on: Thu Mar 13 12:03:18 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#ifndef _TREETEMPLATE_H_
+#define _TREETEMPLATE_H_
+
+#include "TreeExceptions.h"
+#include "TreeTemplateTools.h"
+#include "Tree.h"
+
+// From the STL:
+#include <string>
+#include <vector>
+#include <map>
+
+namespace bpp
+{
+/**
+ * @brief The phylogenetic tree class.
+ *
+ * This class is part of the object implementation of phylogenetic trees. Tree are made
+ * made of nodes, instances of the class Node. It is possible to use a tree with more
+ * complexe Node classes, but currently all nodes of a tree have to be of the same class.
+ *
+ * Trees are oriented (rooted), i.e. each node has one <i>father node</i> and possibly
+ * many <i>son nodes</i>. Leaves are nodes without descendant and root is defined has the without
+ * father. Inner nodes will generally contain two descendants (the tree is then called
+ * <i>bifurcating</i>), but mutlifurcating trees are also allowed with this kind of description.
+ * In the rooted case, each inner node also defines a <i>subtree</i>.
+ * This allows to work recursively on trees, which is very convenient in most cases.
+ * To deal with non-rooted trees, we place an artificial root at a particular node:
+ * hence the root node appears to be trifurcated. This is the way unrooted trees are
+ * described in the parenthetic description, the so called Newick format.
+ *
+ * To clone a tree from from another tree with a different template,
+ * consider using the TreeTools::cloneSutree<N>() method:
+ * @code
+ * Tree * t = new Tree<Node>(...)
+ * NodeTemplate<int> * newRoot = TreeTools::cloneSubtree< NodeTemplate<int> >(* (t -> getRootNode()))
+ * Tree< NodeTemplate<int> > * tt = new Tree< NodeTemplate<int> >(* newRoot);
+ * @endcode
+ *
+ * The getNextId() method sends a id value which is not used in the tree.
+ * In the current implementation, it uses the TreeTools::getMPNUId() method.
+ * This avoids to use duplicated ids, but is time consuming.
+ * In most cases, it is of better efficiency if the user deal with the ids himself, by using the Node::setId() method.
+ * The TreeTools::getMaxId() method may also prove useful in this respect.
+ * The resetNodesId() method can also be used to re-initialize all ids.
+ *
+ * @see Node
+ * @see NodeTemplate
+ * @see TreeTools
+ */
+template<class N>
+class TreeTemplate :
+  public Tree
+{
+  /**
+   * Fields:
+   */
+
+private:
+  N* root_;
+  std::string name_;
+
+public:
+  // Constructors and destructor:
+  TreeTemplate() : root_(0),
+    name_() {}
+
+  TreeTemplate(const TreeTemplate<N>& t) :
+    root_(0),
+    name_(t.name_)
+  {
+    // Perform a hard copy of the nodes:
+    root_ = TreeTemplateTools::cloneSubtree<N>(*t.getRootNode());
+  }
+
+  TreeTemplate(const Tree& t) :
+    root_(0),
+    name_(t.getName())
+  {
+    // Create new nodes from an existing tree:
+    root_ = TreeTemplateTools::cloneSubtree<N>(t, t.getRootId());
+  }
+
+  TreeTemplate(N* root) : root_(root),
+    name_()
+  {
+    root_->removeFather(); // In case this is a subtree from somewhere else...
+  }
+
+  TreeTemplate<N>& operator=(const TreeTemplate<N>& t)
+  {
+    // Perform a hard copy of the nodes:
+    if (root_) { TreeTemplateTools::deleteSubtree(root_); delete root_; }
+    root_ = TreeTemplateTools::cloneSubtree<N>(*t.getRootNode());
+    name_ = t.name_;
+    return *this;
+  }
+
+  TreeTemplate<N>* cloneSubtree(int newRootId) const
+  {
+    N* newRoot = TreeTemplateTools::cloneSubtree<N>(*this, newRootId);
+    return new TreeTemplate<N>(newRoot);
+  }
+
+  virtual ~TreeTemplate()
+  {
+    TreeTemplateTools::deleteSubtree(root_);
+    delete root_;
+  }
+
+  TreeTemplate<N>* clone() const { return new TreeTemplate<N>(*this); }
+
+  /**
+   * Methods:
+   */
+
+public:
+  std::string getName() const { return name_; }
+
+  void setName(const std::string& name) { name_ = name; }
+
+  int getRootId() const { return root_->getId(); }
+
+  size_t getNumberOfLeaves() const { return TreeTemplateTools::getNumberOfLeaves(*root_); }
+
+  size_t getNumberOfNodes() const { return TreeTemplateTools::getNumberOfNodes(*root_); }
+
+  int getLeafId(const std::string& name) const throw (NodeNotFoundException) { return TreeTemplateTools::getLeafId(*root_, name); }
+
+  std::vector<int> getLeavesId() const { return TreeTemplateTools::getLeavesId(*root_); }
+
+  std::vector<int> getNodesId() const { return TreeTemplateTools::getNodesId(*root_); }
+
+  std::vector<int> getInnerNodesId() const { return TreeTemplateTools::getInnerNodesId(*root_); }
+
+  std::vector<int> getBranchesId() const { return TreeTemplateTools::getBranchesId(*root_); }
+
+  std::vector<double> getBranchLengths() const { return TreeTemplateTools::getBranchLengths(*root_); }
+
+  std::vector<std::string> getLeavesNames() const { return TreeTemplateTools::getLeavesNames(*const_cast<const N*>( root_)); }
+
+  std::vector<int> getSonsId(int parentId) const throw (NodeNotFoundException)  { return getNode(parentId)->getSonsId(); }
+
+  std::vector<int> getAncestorsId(int nodeId) const throw (NodeNotFoundException) { return TreeTemplateTools::getAncestorsId(*getNode(nodeId)); }
+
+  int getFatherId(int parentId) const throw (NodeNotFoundException) { return getNode(parentId)->getFatherId(); }
+
+  bool hasFather(int nodeId) const throw (NodeNotFoundException) { return getNode(nodeId)->hasFather(); }
+
+  std::string getNodeName(int nodeId) const throw (NodeNotFoundException) { return getNode(nodeId)->getName(); }
+
+  bool hasNodeName(int nodeId) const throw (NodeNotFoundException) { return getNode(nodeId)->hasName(); }
+
+  void setNodeName(int nodeId, const std::string& name) throw (NodeNotFoundException) { getNode(nodeId)->setName(name); }
+
+  void deleteNodeName(int nodeId) throw (NodeNotFoundException) { return getNode(nodeId)->deleteName(); }
+
+  bool hasNode(int nodeId) const { return TreeTemplateTools::hasNodeWithId(*root_, nodeId); }
+
+  bool isLeaf(int nodeId) const throw (NodeNotFoundException) { return getNode(nodeId)->isLeaf(); }
+
+  bool isRoot(int nodeId) const throw (NodeNotFoundException) { return TreeTemplateTools::isRoot(*getNode(nodeId)); }
+
+  double getDistanceToFather(int nodeId) const { return getNode(nodeId)->getDistanceToFather(); }
+
+  void setDistanceToFather(int nodeId, double length) { getNode(nodeId)->setDistanceToFather(length); }
+
+  void deleteDistanceToFather(int nodeId) { getNode(nodeId)->deleteDistanceToFather(); }
+
+  bool hasDistanceToFather(int nodeId) const { return getNode(nodeId)->hasDistanceToFather(); }
+
+  bool hasNodeProperty(int nodeId, const std::string& name) const throw (NodeNotFoundException) { return getNode(nodeId)->hasNodeProperty(name); }
+
+  void setNodeProperty(int nodeId, const std::string& name, const Clonable& property) throw (NodeNotFoundException) { getNode(nodeId)->setNodeProperty(name, property); }
+
+  Clonable* getNodeProperty(int nodeId, const std::string& name) throw (NodeNotFoundException) { return getNode(nodeId)->getNodeProperty(name); }
+
+  const Clonable* getNodeProperty(int nodeId, const std::string& name) const throw (NodeNotFoundException) { return getNode(nodeId)->getNodeProperty(name); }
+
+  Clonable* removeNodeProperty(int nodeId, const std::string& name) throw (NodeNotFoundException) { return getNode(nodeId)->removeNodeProperty(name); }
+
+  std::vector<std::string> getNodePropertyNames(int nodeId) const throw (NodeNotFoundException) { return getNode(nodeId)->getNodePropertyNames(); }
+
+  bool hasBranchProperty(int nodeId, const std::string& name) const throw (NodeNotFoundException) { return getNode(nodeId)->hasBranchProperty(name); }
+
+  void setBranchProperty(int nodeId, const std::string& name, const Clonable& property) throw (NodeNotFoundException) { getNode(nodeId)->setBranchProperty(name, property); }
+
+  Clonable* getBranchProperty(int nodeId, const std::string& name) throw (NodeNotFoundException) { return getNode(nodeId)->getBranchProperty(name); }
+
+  const Clonable* getBranchProperty(int nodeId, const std::string& name) const throw (NodeNotFoundException) { return getNode(nodeId)->getBranchProperty(name); }
+
+  Clonable* removeBranchProperty(int nodeId, const std::string& name) throw (NodeNotFoundException) { return getNode(nodeId)->removeBranchProperty(name); }
+
+  std::vector<std::string> getBranchPropertyNames(int nodeId) const throw (NodeNotFoundException) { return getNode(nodeId)->getBranchPropertyNames(); }
+
+  void rootAt(int nodeId) throw (NodeNotFoundException) { rootAt(getNode(nodeId)); }
+
+  void newOutGroup(int nodeId) throw (NodeNotFoundException) {  newOutGroup(getNode(nodeId)); }
+
+  bool isRooted() const { return root_->getNumberOfSons() == 2; }
+
+  bool unroot() throw (UnrootedTreeException)
+  {
+    if (!isRooted()) throw UnrootedTreeException("Tree::unroot", this);
+    else
+    {
+      N* son1 = root_->getSon(0);
+      N* son2 = root_->getSon(1);
+      if (son1->isLeaf() && son2->isLeaf()) return false;  // We can't unroot a single branch!
+
+      // We manage to have a subtree in position 0:
+      if (son1->isLeaf())
+      {
+        root_->swap(0, 1);
+        son1 = root_->getSon(0);
+        son2 = root_->getSon(1);
+      }
+
+      // Take care of branch lengths:
+      if (son1->hasDistanceToFather())
+      {
+        if (son2->hasDistanceToFather())
+        {
+          // Both nodes have lengths, we sum them:
+          son2->setDistanceToFather(son1->getDistanceToFather() + son2->getDistanceToFather());
+        }
+        else
+        {
+          // Only node 1 has length, we set it to node 2:
+          son2->setDistanceToFather(son1->getDistanceToFather());
+        }
+        son1->deleteDistanceToFather();
+      } // Else node 2 may or may not have a branch length, we do not care!
+
+      // Remove the root:
+      root_->removeSons();
+      son1->addSon(son2);
+      delete root_;
+      setRootNode(son1);
+      return true;
+    }
+  }
+
+  void resetNodesId()
+  {
+    std::vector<N*> nodes = getNodes();
+    for (size_t i = 0; i < nodes.size(); i++)
+    {
+      nodes[i]->setId(static_cast<int>(i));
+    }
+  }
+
+  bool isMultifurcating() const
+  {
+    if (root_->getNumberOfSons() > 3) return true;
+    for (size_t i = 0; i < root_->getNumberOfSons(); i++)
+      if (TreeTemplateTools::isMultifurcating(*root_->getSon(i)))
+        return true;
+    return false;
+  }
+
+  /**
+   * @brief Tells if this tree has the same topology as the one given for comparison.
+   *
+   * This method compares recursively all subtrees. The comparison is performed only on the nodes names and the parental relationships.
+   * Nodes ids are ignored, and so are branch lengths and any branch/node properties. The default is to ignore the ordering of the descendants,
+   * that is (A,B),C) will be considered as having the same topology as (B,A),C). Multifurcations are permited.
+   * If ordering is ignored, a copy of the two trees to be compared is performed and are ordered before comparison, making the whole comparison
+   * slower and more memory greedy.
+   *
+   * @param tree The tree to be compared with.
+   * @param ordered Should the ordering of the branching be taken into account?
+   * @return True if the input tree has the same topology as this one.
+   */
+  template<class N2>
+  bool hasSameTopologyAs(const TreeTemplate<N2>& tree, bool ordered = false) const
+  {
+    const TreeTemplate<N>* t1 = 0;
+    const TreeTemplate<N2>* t2 = 0;
+    if (ordered)
+    {
+      t1 = this;
+      t2 = &tree;
+    }
+    else
+    {
+      TreeTemplate<N>* t1tmp = this->clone();
+      TreeTemplate<N2>* t2tmp = tree.clone();
+      TreeTemplateTools::orderTree(*t1tmp->getRootNode(), true, true);
+      TreeTemplateTools::orderTree(*t2tmp->getRootNode(), true, true);
+      t1 = t1tmp;
+      t2 = t2tmp;
+    }
+    bool test = TreeTemplateTools::haveSameOrderedTopology(*t1->getRootNode(), *t2->getRootNode());
+    if (!ordered)
+    {
+      delete t1;
+      delete t2;
+    }
+    return test;
+  }
+
+  std::vector<double> getBranchLengths() throw (NodeException)
+  {
+    Vdouble brLen(1);
+    for (size_t i = 0; i < root_->getNumberOfSons(); i++)
+    {
+      Vdouble sonBrLen = TreeTemplateTools::getBranchLengths(*root_->getSon(i));
+      for (size_t j = 0; j < sonBrLen.size(); j++) { brLen.push_back(sonBrLen[j]); }
+    }
+    return brLen;
+  }
+
+  double getTotalLength() throw (NodeException)
+  {
+    return TreeTemplateTools::getTotalLength(*root_, false);
+  }
+
+  void setBranchLengths(double brLen)
+  {
+    for (size_t i = 0; i < root_->getNumberOfSons(); i++)
+    {
+      TreeTemplateTools::setBranchLengths(*root_->getSon(i), brLen);
+    }
+  }
+
+  void setVoidBranchLengths(double brLen)
+  {
+    for (size_t i = 0; i < root_->getNumberOfSons(); i++)
+    {
+      TreeTemplateTools::setVoidBranchLengths(*root_->getSon(i), brLen);
+    }
+  }
+
+  void scaleTree(double factor) throw (NodeException)
+  {
+    for (size_t i = 0; i < root_->getNumberOfSons(); i++)
+    {
+      TreeTemplateTools::scaleTree(*root_->getSon(i), factor);
+    }
+  }
+
+  int getNextId()
+  {
+    return TreeTools::getMPNUId(*this, root_->getId());
+  }
+
+  void swapNodes(int parentId, size_t i1, size_t i2) throw (NodeNotFoundException, IndexOutOfBoundsException)
+  {
+    std::vector<N*> nodes = TreeTemplateTools::searchNodeWithId<N>(*root_, parentId);
+    if (nodes.size() == 0) throw NodeNotFoundException("TreeTemplate:swapNodes(): Node with id not found.", "" + parentId);
+    for (size_t i = 0; i < nodes.size(); i++) { nodes[i]->swap(i1, i2); }
+  }
+
+
+  /**
+   * @name Specific methods
+   *
+   * @{
+   */
+  virtual void setRootNode(N* root) { root_ = root; }
+
+  virtual N* getRootNode() { return root_; }
+
+  virtual const N* getRootNode() const { return root_; }
+
+  virtual std::vector<const N*> getLeaves() const { return TreeTemplateTools::getLeaves(*const_cast<const N*>(root_)); }
+
+  virtual std::vector<N*> getLeaves() { return TreeTemplateTools::getLeaves(*root_); }
+
+  virtual std::vector<const N*> getNodes() const { return TreeTemplateTools::getNodes(*const_cast<const N*>(root_)); }
+
+  virtual std::vector<N*> getNodes() { return TreeTemplateTools::getNodes(*root_); }
+
+  virtual std::vector<const N*> getInnerNodes() const { return TreeTemplateTools::getInnerNodes(*const_cast<const N*>(root_)); }
+
+  virtual std::vector<N*> getInnerNodes() { return TreeTemplateTools::getInnerNodes(*root_); }
+
+  virtual N* getNode(int id, bool checkId = false) throw (NodeNotFoundException, Exception)
+  {
+    if (checkId) {
+      std::vector<N*> nodes;
+      TreeTemplateTools::searchNodeWithId<N>(*root_, id, nodes);
+      if (nodes.size() > 1) throw Exception("TreeTemplate::getNode(): Non-unique id! (" + TextTools::toString(id) + ").");
+      if (nodes.size() == 0) throw NodeNotFoundException("TreeTemplate::getNode(): Node with id not found.", TextTools::toString(id));
+      return nodes[0];
+    } else {
+      N* node = dynamic_cast<N*>(TreeTemplateTools::searchFirstNodeWithId(*root_, id));
+      if (node)
+        return node;
+      else
+        throw NodeNotFoundException("TreeTemplate::getNode(): Node with id not found.", TextTools::toString(id));
+    }
+  }
+
+  virtual const N* getNode(int id, bool checkId = false) const throw (NodeNotFoundException, Exception)
+  {
+    if (checkId) {
+      std::vector<const N*> nodes;
+      TreeTemplateTools::searchNodeWithId<const N>(*root_, id, nodes);
+      if (nodes.size() > 1) throw Exception("TreeTemplate::getNode(): Non-unique id! (" + TextTools::toString(id) + ").");
+      if (nodes.size() == 0) throw NodeNotFoundException("TreeTemplate::getNode(): Node with id not found.", TextTools::toString(id));
+      return nodes[0];
+    } else {
+      const N* node = dynamic_cast<const N*>(TreeTemplateTools::searchFirstNodeWithId(*root_, id));
+      if (node)
+        return node;
+      else
+        throw NodeNotFoundException("TreeTemplate::getNode(): Node with id not found.", TextTools::toString(id));
+    }
+  }
+
+  virtual N* getNode(const std::string& name) throw (NodeNotFoundException, Exception)
+  {
+    std::vector<N*> nodes;
+    TreeTemplateTools::searchNodeWithName(*root_, name, nodes);
+    if (nodes.size() > 1) throw NodeNotFoundException("TreeTemplate::getNode(): Non-unique name.", "" + name);
+    if (nodes.size() == 0) throw NodeNotFoundException("TreeTemplate::getNode(): Node with name not found.", "" + name);
+    return nodes[0];
+  }
+
+  virtual const N* getNode(const std::string& name) const throw (NodeNotFoundException, Exception)
+  {
+    std::vector<const N*> nodes;
+    TreeTemplateTools::searchNodeWithName<const N>(*root_, name, nodes);
+    if (nodes.size() > 1) throw NodeNotFoundException("TreeTemplate::getNode(): Non-unique name.", "" + name);
+    if (nodes.size() == 0) throw NodeNotFoundException("TreeTemplate::getNode(): Node with name not found.", "" + name);
+    return nodes[0];
+  }
+
+  void rootAt(N* newRoot)
+  {
+    if (root_ == newRoot) return;
+    if (isRooted()) unroot();
+    std::vector<Node*> path = TreeTemplateTools::getPathBetweenAnyTwoNodes(*root_, *newRoot);
+
+    for (size_t i = 0; i < path.size() - 1; i++)
+    {
+      // pathMatrix[i] -> _father = pathMatrix[i + 1];
+      // pathMatrix[i] -> setDistanceToFather(pathMatrix[i + 1] -> getDistanceToFather());
+      // typename vector<Node *>::iterator vec_iter;
+      // vec_iter = remove(pathMatrix[i] -> _sons.begin(), pathMatrix[i] -> _sons.end(), pathMatrix[i + 1]);
+      // pathMatrix[i] -> _sons.erase(vec_iter, pathMatrix[i] -> _sons.end()); // pg 1170, primer.
+      // pathMatrix[i+1] -> _sons.push_back(pathMatrix[i + 1] -> getFather());
+      // pathMatrix[i+1] -> _father = 0;
+      path[i]->removeSon(path[i + 1]);
+      if (path[i + 1]->hasDistanceToFather()) path[i]->setDistanceToFather(path[i + 1]->getDistanceToFather());
+      else path[i]->deleteDistanceToFather();
+      path[i + 1]->addSon(path[i]);
+
+      std::vector<std::string> names = path[i + 1]->getBranchPropertyNames();
+      for (size_t j = 0; j < names.size(); j++)
+      {
+        path[i]->setBranchProperty(names[j], *path[i + 1]->getBranchProperty(names[j]));
+      }
+      path[i + 1]->deleteBranchProperties();
+    }
+    newRoot->deleteDistanceToFather();
+    newRoot->deleteBranchProperties();
+    root_ = newRoot;
+  }
+
+  void newOutGroup(N* outGroup)
+  {
+    if (root_ == outGroup) return;
+    int rootId;
+    if (isRooted())
+    {
+      for (size_t i = 0; i < root_->getNumberOfSons(); i++)
+      {
+        if (root_->getSon(i) == outGroup) return;  // This tree is already rooted appropriately.
+      }
+      rootId = getRootId();
+      unroot();
+    }
+    else
+    {
+      rootId = getNextId();
+    }
+    rootAt(outGroup->getFather());
+    N* oldRoot = root_;
+    oldRoot->removeSon(outGroup);
+    root_ = new N();
+    root_->setId(rootId);
+    root_->addSon(oldRoot);
+    root_->addSon(outGroup);
+    // Check lengths:
+    if (outGroup->hasDistanceToFather())
+    {
+      double l = outGroup->getDistanceToFather() / 2.;
+      outGroup->setDistanceToFather(l);
+      oldRoot->setDistanceToFather(l);
+    }
+  }
+
+  /** @} */
+};
+} // end of namespace bpp.
+
+#endif  // _TREETEMPLATE_H_
+
diff --git a/src/Bpp/Phyl/TreeTemplateTools.cpp b/src/Bpp/Phyl/TreeTemplateTools.cpp
new file mode 100644
index 0000000..83e23b4
--- /dev/null
+++ b/src/Bpp/Phyl/TreeTemplateTools.cpp
@@ -0,0 +1,1187 @@
+//
+// File: TreeTemplateTools.cpp
+// Created by: Julien Dutheil
+// Created on: Fri Oct  13 13:00 2006
+// From file TreeTools.cpp
+// Created on: Wed Aug  6 13:45:28 2003
+//
+
+/*
+   Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "TreeTemplateTools.h"
+#include "TreeTemplate.h"
+
+#include <Bpp/Numeric/Number.h>
+#include <Bpp/BppString.h>
+#include <Bpp/Text/StringTokenizer.h>
+#include <Bpp/Text/NestedStringTokenizer.h>
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Numeric/Random/RandomTools.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+#include <sstream>
+#include <limits>
+
+using namespace std;
+
+/******************************************************************************/
+
+bool TreeTemplateTools::isMultifurcating(const Node& node)
+{
+  if (node.getNumberOfSons() > 2)
+    return true;
+  else
+  {
+    bool b = false;
+    for (size_t i = 0; i < node.getNumberOfSons(); i++)
+    {
+      b = b || isMultifurcating(*node.getSon(i));
+    }
+    return b;
+  }
+}
+
+/******************************************************************************/
+
+unsigned int TreeTemplateTools::getNumberOfLeaves(const Node& node)
+{
+  unsigned int nbLeaves = 0;
+  if (node.isLeaf())
+  {
+    nbLeaves++;
+  }
+  for (int i = 0; i < static_cast<int>(node.getNumberOfSons()); i++)
+  {
+    nbLeaves += getNumberOfLeaves(*node[i]);
+  }
+  return nbLeaves;
+}
+
+/******************************************************************************/
+
+unsigned int TreeTemplateTools::getNumberOfNodes(const Node& node)
+{
+  unsigned int nbNodes = 1;
+  for (int i = 0; i < static_cast<int>(node.getNumberOfSons()); i++)
+  {
+    nbNodes += getNumberOfNodes(*node[i]);
+  }
+  return nbNodes;
+}
+
+/******************************************************************************/
+
+vector<string> TreeTemplateTools::getLeavesNames(const Node& node)
+{
+  vector<string> names;
+  if (node.isLeaf())
+  {
+    names.push_back(node.getName());
+  }
+  for (size_t i = 0; i < node.getNumberOfSons(); i++)
+  {
+    vector<string> subNames = getLeavesNames(*node.getSon(i));
+    for (size_t j = 0; j < subNames.size(); j++)
+    {
+      names.push_back(subNames[j]);
+    }
+  }
+  return names;
+}
+
+/******************************************************************************/
+
+unsigned int TreeTemplateTools::getDepth(const Node& node)
+{
+  unsigned int d = 0;
+  for (int i = 0; i < static_cast<int>(node.getNumberOfSons()); i++)
+  {
+    unsigned int c = getDepth(*node[i]) + 1;
+    if (c > d)
+      d = c;
+  }
+  return d;
+}
+
+/******************************************************************************/
+
+unsigned int TreeTemplateTools::getDepths(const Node& node, map<const Node*, unsigned int>& depths)
+{
+  unsigned int d = 0;
+  for (int i = 0; i < static_cast<int>(node.getNumberOfSons()); i++)
+  {
+    unsigned int c = getDepths(*node[i], depths) + 1;
+    if (c > d)
+      d = c;
+  }
+  depths[&node] = d;
+  return d;
+}
+
+/******************************************************************************/
+
+double TreeTemplateTools::getHeight(const Node& node)
+{
+  double d = 0;
+  for (int i = 0; i < static_cast<int>(node.getNumberOfSons()); i++)
+  {
+    const Node* son = node[i];
+    double dist = son->getDistanceToFather();
+    double c = getHeight(*son) + dist;
+    if (c > d)
+      d = c;
+  }
+  return d;
+}
+
+/******************************************************************************/
+
+double TreeTemplateTools::getHeights(const Node& node, map<const Node*, double>& heights)
+{
+  double d = 0;
+  for (int i = 0; i < static_cast<int>(node.getNumberOfSons()); i++)
+  {
+    const Node* son = node[i];
+    double dist = son->getDistanceToFather();
+    double c = getHeights(*son, heights) + dist;
+    if (c > d)
+      d = c;
+  }
+  heights[&node] = d;
+  return d;
+}
+
+/******************************************************************************/
+
+TreeTemplateTools::Element TreeTemplateTools::getElement(const string& elt) throw (IOException)
+{
+  Element element;
+  element.length    = ""; // default
+  element.bootstrap = ""; // default
+  element.isLeaf    = false; // default
+
+  size_t colonIndex;
+  bool hasColon = false;
+  for (colonIndex = elt.size(); colonIndex > 0 && elt[colonIndex] != ')'; colonIndex--)
+  {
+    if (elt[colonIndex] == ':')
+    {
+      hasColon = true;
+      break;
+    }
+  }
+  try
+  {
+    string elt2;
+    if (hasColon)
+    {
+      // this is an element with length:
+      elt2 = elt.substr(0, colonIndex);
+      element.length = TextTools::removeSurroundingWhiteSpaces(elt.substr(colonIndex + 1));
+    }
+    else
+    {
+      // this is an element without length;
+      elt2 = elt;
+    }
+
+    string::size_type lastP = elt2.rfind(')');
+    string::size_type firstP = elt2.find('(');
+    if (firstP == string::npos)
+    {
+      // This is a leaf:
+      element.content = elt2;
+      element.isLeaf = true;
+    }
+    else
+    {
+      // This is a node:
+      if (lastP < firstP)
+        throw IOException("TreeTemplateTools::getElement(). Invalid format: bad closing parenthesis in " + elt2);
+      element.content = TextTools::removeSurroundingWhiteSpaces(elt2.substr(firstP + 1, lastP - firstP - 1));
+      string bootstrap = TextTools::removeSurroundingWhiteSpaces(elt2.substr(lastP + 1));
+      // cout << "ELEMENT: BOOTSTRAP: " << bootstrap << endl;
+      if (!TextTools::isEmpty(bootstrap))
+      {
+        element.bootstrap = bootstrap;
+      }
+    }
+  }
+  catch (exception e)
+  {
+    throw IOException("Bad tree description: " + elt);
+  }
+  return element;
+}
+
+/******************************************************************************/
+
+
+Node* TreeTemplateTools::parenthesisToNode(const string& description, bool bootstrap, const string& propertyName, bool withId)
+{
+  //cout << "NODE: " << description << endl;
+  Element elt = getElement(description);
+
+  // New node:
+  Node* node = new Node();
+  if (!TextTools::isEmpty(elt.length))
+  {
+    node->setDistanceToFather(TextTools::toDouble(elt.length));
+    // cout << "NODE: LENGTH: " << * elt.length << endl;
+  }
+  if (!TextTools::isEmpty(elt.bootstrap))
+  {
+    if (withId)
+    {
+      node->setId(TextTools::toInt(elt.bootstrap));
+    }
+    else
+    {
+      if (bootstrap)
+      {
+        node->setBranchProperty(TreeTools::BOOTSTRAP, Number<double>(TextTools::toDouble(elt.bootstrap)));
+        // cout << "NODE: BOOTSTRAP: " << * elt.bootstrap << endl;
+      }
+      else
+      {
+        node->setBranchProperty(propertyName, BppString(elt.bootstrap));
+      }
+    }
+  }
+
+  NestedStringTokenizer nt(elt.content, "(", ")", ",");
+  vector<string> elements;
+  while (nt.hasMoreToken())
+  {
+    elements.push_back(nt.nextToken());
+  }
+
+  if (elt.isLeaf)
+  {
+    //This is a leaf:
+    string name = TextTools::removeSurroundingWhiteSpaces(elements[0]);
+    if (withId)
+    {
+      StringTokenizer st(name, "_", true, true);
+      ostringstream realName;
+      for (int i = 0; i < static_cast<int>(st.numberOfRemainingTokens()) - 1; i++)
+      {
+        if (i != 0)
+        {
+          realName << "_";
+        }
+        realName << st.getToken(i);
+      }
+      node->setName(realName.str());
+      node->setId(TextTools::toInt(st.getToken(st.numberOfRemainingTokens() - 1)));
+    }
+    else
+    {
+      node->setName(name);
+    }
+  }
+  else
+  {
+    // This is a node:
+    for (size_t i = 0; i < elements.size(); i++)
+    {
+      // cout << "NODE: SUBNODE: " << i << ", " << elements[i] << endl;
+      Node* son = parenthesisToNode(elements[i], bootstrap, propertyName, withId);
+      node->addSon(son);
+    }
+  }
+  return node;
+}
+
+/******************************************************************************/
+
+TreeTemplate<Node>* TreeTemplateTools::parenthesisToTree(const string& description, bool bootstrap, const string& propertyName, bool withId) throw (Exception)
+{
+  string::size_type semi = description.rfind(';');
+  if (semi == string::npos)
+    throw Exception("TreeTemplateTools::parenthesisToTree(). Bad format: no semi-colon found.");
+  string content = description.substr(0, semi);
+  Node* node = parenthesisToNode(content, bootstrap, propertyName, withId);
+  TreeTemplate<Node>* tree = new TreeTemplate<Node>();
+  tree->setRootNode(node);
+  if (!withId)
+  {
+    tree->resetNodesId();
+  }
+  return tree;
+}
+
+/******************************************************************************/
+
+string TreeTemplateTools::nodeToParenthesis(const Node& node, bool writeId)
+{
+  ostringstream s;
+  if (node.isLeaf())
+  {
+    s << node.getName();
+  }
+  else
+  {
+    s << "(";
+    s << nodeToParenthesis(*node[0], writeId);
+    for (int i = 1; i < static_cast<int>(node.getNumberOfSons()); i++)
+    {
+      s << "," << nodeToParenthesis(*node[i], writeId);
+    }
+    s << ")";
+  }
+  if (writeId)
+  {
+    if (node.isLeaf())
+      s << "_";
+    s << node.getId();
+  }
+  else
+  {
+    if (node.hasBranchProperty(TreeTools::BOOTSTRAP))
+      s << (dynamic_cast<const Number<double>*>(node.getBranchProperty(TreeTools::BOOTSTRAP))->getValue());
+  }
+  if (node.hasDistanceToFather())
+    s << ":" << node.getDistanceToFather();
+  return s.str();
+}
+
+/******************************************************************************/
+
+string TreeTemplateTools::nodeToParenthesis(const Node& node, bool bootstrap, const string& propertyName)
+{
+  ostringstream s;
+  if (node.isLeaf())
+  {
+    s << node.getName();
+  }
+  else
+  {
+    s << "(";
+    s << nodeToParenthesis(*node[0], bootstrap, propertyName);
+    for (int i = 1; i < static_cast<int>(node.getNumberOfSons()); i++)
+    {
+      s << "," << nodeToParenthesis(*node[i], bootstrap, propertyName);
+    }
+    s << ")";
+
+    if (bootstrap)
+    {
+      if (node.hasBranchProperty(TreeTools::BOOTSTRAP))
+        s << (dynamic_cast<const Number<double>*>(node.getBranchProperty(TreeTools::BOOTSTRAP))->getValue());
+    }
+    else
+    {
+      if (node.hasBranchProperty(propertyName))
+      {
+        const BppString* ppt = dynamic_cast<const BppString*>(node.getBranchProperty(propertyName));
+        if (ppt) 
+          s << *ppt;
+        else
+          throw Exception("TreeTemplateTools::nodeToParenthesis. Property should be a BppString.");
+      }
+    }
+  }
+  if (node.hasDistanceToFather())
+    s << ":" << node.getDistanceToFather();
+  return s.str();
+}
+
+/******************************************************************************/
+
+string TreeTemplateTools::treeToParenthesis(const TreeTemplate<Node>& tree, bool writeId)
+{
+  ostringstream s;
+  s << "(";
+  const Node* node = tree.getRootNode();
+  if (node->isLeaf() && node->hasName()) //In case we have a tree like ((A:1.0)); where the root node is an unamed leaf!
+  {
+    s << node->getName();
+    for (size_t i = 0; i < node->getNumberOfSons(); ++i)
+    {
+      s << "," << nodeToParenthesis(*node->getSon(i), writeId);
+    }
+  }
+  else
+  {
+    s << nodeToParenthesis(*node->getSon(0), writeId);
+    for (size_t i = 1; i < node->getNumberOfSons(); ++i)
+    {
+      s << "," << nodeToParenthesis(*node->getSon(i), writeId);
+    }
+  }
+  s << ")";
+  if (node->hasDistanceToFather())
+    s << ":" << node->getDistanceToFather();
+  s << ";" << endl;
+  return s.str();
+}
+
+/******************************************************************************/
+
+string TreeTemplateTools::treeToParenthesis(const TreeTemplate<Node>& tree, bool bootstrap, const string& propertyName)
+{
+  ostringstream s;
+  s << "(";
+  const Node* node = tree.getRootNode();
+  if (node->isLeaf())
+  {
+    s << node->getName();
+    for (size_t i = 0; i < node->getNumberOfSons(); i++)
+    {
+      s << "," << nodeToParenthesis(*node->getSon(i), bootstrap, propertyName);
+    }
+  }
+  else
+  {
+    s << nodeToParenthesis(*node->getSon(0), bootstrap, propertyName);
+    for (size_t i = 1; i < node->getNumberOfSons(); i++)
+    {
+      s << "," << nodeToParenthesis(*node->getSon(i), bootstrap, propertyName);
+    }
+  }
+  s << ")";
+  if (bootstrap)
+  {
+    if (node->hasBranchProperty(TreeTools::BOOTSTRAP))
+      s << (dynamic_cast<const Number<double>*>(node->getBranchProperty(TreeTools::BOOTSTRAP))->getValue());
+  }
+  else
+  {
+    if (node->hasBranchProperty(propertyName)) {
+      const BppString* ppt =dynamic_cast<const BppString*>(node->getBranchProperty(propertyName));
+      if (ppt)
+        s << *ppt;
+      else
+        throw Exception("TreeTemplateTools::nodeToParenthesis. Property should be a BppString.");
+    }
+  }
+  s << ";" << endl;
+  return s.str();
+}
+
+/******************************************************************************/
+
+Vdouble TreeTemplateTools::getBranchLengths(const Node& node) throw (NodePException)
+{
+  Vdouble brLen(1);
+  brLen[0] = node.getDistanceToFather();
+  for (size_t i = 0; i < node.getNumberOfSons(); i++)
+  {
+    Vdouble sonBrLen = getBranchLengths(*node.getSon(i));
+    for (size_t j = 0; j < sonBrLen.size(); j++)
+    {
+      brLen.push_back(sonBrLen[j]);
+    }
+  }
+  return brLen;
+}
+
+/******************************************************************************/
+
+double TreeTemplateTools::getTotalLength(const Node& node, bool includeAncestor) throw (NodePException)
+{
+  if (includeAncestor && !node.hasDistanceToFather())
+    throw NodePException("TreeTools::getTotalLength(). No branch length.", &node);
+  double length = includeAncestor ? node.getDistanceToFather() : 0;
+  for (size_t i = 0; i < node.getNumberOfSons(); i++)
+  {
+    length += getTotalLength(*node.getSon(i), true);
+  }
+  return length;
+}
+
+/******************************************************************************/
+
+void TreeTemplateTools::setBranchLengths(Node& node, double brLen)
+{
+  node.setDistanceToFather(brLen);
+  for (size_t i = 0; i < node.getNumberOfSons(); i++)
+  {
+    setBranchLengths(*node.getSon(i), brLen);
+  }
+}
+
+/******************************************************************************/
+
+void TreeTemplateTools::deleteBranchLengths(Node& node)
+{
+  node.deleteDistanceToFather();
+  for (size_t i = 0; i < node.getNumberOfSons(); i++)
+  {
+    deleteBranchLengths(*node.getSon(i));
+  }
+}
+
+/******************************************************************************/
+
+void TreeTemplateTools::setVoidBranchLengths(Node& node, double brLen)
+{
+  if (!node.hasDistanceToFather())
+    node.setDistanceToFather(brLen);
+  for (size_t i = 0; i < node.getNumberOfSons(); i++)
+  {
+    setVoidBranchLengths(*node.getSon(i), brLen);
+  }
+}
+
+/******************************************************************************/
+
+void TreeTemplateTools::scaleTree(Node& node, double factor) throw (NodePException)
+{
+  if (node.hasFather())
+  {
+    node.setDistanceToFather(node.getDistanceToFather() * factor);
+  }
+  for (size_t i = 0; i < node.getNumberOfSons(); i++)
+  {
+    scaleTree(*node.getSon(i), factor);
+  }
+}
+
+/******************************************************************************/
+
+TreeTemplate<Node>* TreeTemplateTools::getRandomTree(vector<string>& leavesNames, bool rooted)
+{
+  if (leavesNames.size() == 0)
+    return 0;  // No taxa.
+  // This vector will contain all nodes.
+  // Start with all leaves, and then group nodes randomly 2 by 2.
+  // Att the end, contains only the root node of the tree.
+  vector<Node*> nodes(leavesNames.size());
+  // Create all leaves nodes:
+  for (size_t i = 0; i < leavesNames.size(); ++i)
+  {
+    nodes[i] = new Node(leavesNames[i]);
+  }
+  // Now group all nodes:
+  while (nodes.size() > (rooted ? 2 : 3))
+  {
+    // Select random nodes:
+    int pos1 = RandomTools::giveIntRandomNumberBetweenZeroAndEntry(static_cast<int>(nodes.size()));
+    Node* node1 = nodes[pos1];
+    nodes.erase(nodes.begin() + pos1);
+    int pos2 = RandomTools::giveIntRandomNumberBetweenZeroAndEntry(static_cast<int>(nodes.size()));
+    Node* node2 = nodes[pos2];
+    nodes.erase(nodes.begin() + pos2);
+    // Add new node:
+    Node* parent = new Node();
+    parent->addSon(node1);
+    parent->addSon(node2);
+    nodes.push_back(parent);
+  }
+  // Return tree with last node as root node:
+  Node* root = new Node();
+  for (size_t i = 0; i < nodes.size(); ++i)
+  {
+    root->addSon(nodes[i]);
+  }
+  TreeTemplate<Node>* tree = new TreeTemplate<Node>(root);
+  tree->resetNodesId();
+  return tree;
+}
+
+/******************************************************************************/
+
+vector<Node*> TreeTemplateTools::getPathBetweenAnyTwoNodes(Node& node1, Node& node2, bool includeAncestor)
+{
+  vector<Node*> path;
+  vector<Node*> pathMatrix1;
+  vector<Node*> pathMatrix2;
+
+  Node* nodeUp = &node1;
+  while (nodeUp->hasFather())   // while(nodeUp != root)
+  {
+    pathMatrix1.push_back(nodeUp);
+    nodeUp = nodeUp->getFather();
+  }
+  pathMatrix1.push_back(nodeUp); // The root.
+
+  nodeUp = &node2;
+  while (nodeUp->hasFather())
+  {
+    pathMatrix2.push_back(nodeUp);
+    nodeUp = nodeUp->getFather();
+  }
+  pathMatrix2.push_back(nodeUp); // The root.
+  // Must check that the two nodes have the same root!!!
+
+  size_t tmp1 = pathMatrix1.size() - 1;
+  size_t tmp2 = pathMatrix2.size() - 1;
+
+  while (pathMatrix1[tmp1] == pathMatrix2[tmp2]
+         and tmp1 > 0
+         and tmp2 > 0)
+  {
+    tmp1--; tmp2--;
+  }
+
+  for (size_t y = 0; y < tmp1; ++y)
+  {
+    path.push_back(pathMatrix1[y]);
+  }
+  if (includeAncestor)
+    path.push_back(pathMatrix1[tmp1]);  // pushing once, the Node that was common to both.
+  for (size_t j = tmp2; j > 0; --j)
+  {
+    path.push_back(pathMatrix2[j - 1]);
+  }
+  return path;
+}
+
+/******************************************************************************/
+
+vector<const Node*> TreeTemplateTools::getPathBetweenAnyTwoNodes(const Node& node1, const Node& node2, bool includeAncestor)
+{
+  vector<const Node*> path;
+  vector<const Node*> pathMatrix1;
+  vector<const Node*> pathMatrix2;
+
+  const Node* nodeUp = &node1;
+  while (nodeUp->hasFather())   // while(nodeUp != root)
+  {
+    pathMatrix1.push_back(nodeUp);
+    nodeUp = nodeUp->getFather();
+  }
+  pathMatrix1.push_back(nodeUp); // The root.
+
+  nodeUp = &node2;
+  while (nodeUp->hasFather())
+  {
+    pathMatrix2.push_back(nodeUp);
+    nodeUp = nodeUp->getFather();
+  }
+  pathMatrix2.push_back(nodeUp); // The root.
+  // Must check that the two nodes have the same root!!!
+
+  size_t tmp1 = pathMatrix1.size() - 1;
+  size_t tmp2 = pathMatrix2.size() - 1;
+
+  while (pathMatrix1[tmp1] == pathMatrix2[tmp2]
+         and tmp1 > 0
+         and tmp2 > 0)
+  {
+    tmp1--; tmp2--;
+  }
+
+  for (size_t y = 0; y < tmp1; ++y)
+  {
+    path.push_back(pathMatrix1[y]);
+  }
+  if (includeAncestor)
+    path.push_back(pathMatrix1[tmp1]);  // pushing once, the Node that was common to both.
+  for (size_t j = tmp2; j > 0; --j)
+  {
+    path.push_back(pathMatrix2[j - 1]);
+  }
+  return path;
+}
+
+/******************************************************************************/
+
+double TreeTemplateTools::getDistanceBetweenAnyTwoNodes(const Node& node1, const Node& node2)
+{
+  vector<const Node*> path = getPathBetweenAnyTwoNodes(node1, node2, false);
+  double d = 0;
+  for (size_t i = 0; i < path.size(); i++)
+  {
+    d += path[i]->getDistanceToFather();
+  }
+  return d;
+}
+
+/******************************************************************************/
+
+void TreeTemplateTools::processDistsInSubtree_(const Node* node, DistanceMatrix& matrix, vector< std::pair<string, double> >& distsToNodeFather)
+{
+  distsToNodeFather.clear();
+
+  // node-is-leaf case
+  if (node->getNumberOfSons() == 0)
+  {
+    distsToNodeFather.push_back(make_pair(node->getName(), node->getDistanceToFather()));
+    return;
+  }
+
+  // For all leaves in node's subtree, get leaf-to-node distances.
+  // Leaves are classified upon node's sons.
+  map<const Node*, vector< pair<string, double> > > leavesDists;
+  for (size_t i = 0; i < node->getNumberOfSons(); ++i)
+  {
+    const Node* son = node->getSon(i);
+    processDistsInSubtree_(son, matrix, leavesDists[son]); // recursivity
+  }
+  // Write leaf-leaf distances to the distance matrix.
+  // Only pairs in which the two leaves belong to different
+  // sons are considered.
+  for (size_t son1_loc = 0; son1_loc < node->getNumberOfSons(); ++son1_loc)
+  {
+    for (size_t son2_loc = 0; son2_loc < son1_loc; ++son2_loc)
+    {
+      const Node* son1 = node->getSon(son1_loc);
+      const Node* son2 = node->getSon(son2_loc);
+
+      for (vector< pair<string, double> >::iterator son1_leaf = leavesDists[son1].begin();
+           son1_leaf != leavesDists[son1].end();
+           ++son1_leaf)
+      {
+        for (vector< pair<string, double> >::iterator son2_leaf = leavesDists[son2].begin();
+             son2_leaf != leavesDists[son2].end();
+             ++son2_leaf)
+        {
+          matrix(son1_leaf->first, son2_leaf->first) =
+            matrix(son2_leaf->first, son1_leaf->first) =
+              ( son1_leaf->second + son2_leaf->second );
+        }
+      }
+    }
+  }
+
+  // node-is-root case
+  if (!node->hasFather())
+  {
+    // node-is-root-and-leaf case
+    if (node->isLeaf() )
+    {
+      string root_name = node->getName();
+      for (vector< pair<string, double> >::iterator other_leaf = leavesDists[node->getSon(0)].begin();
+           other_leaf != leavesDists[node->getSon(0)].end();
+           ++other_leaf)
+      {
+        matrix(root_name, other_leaf->first) = matrix( other_leaf->first, root_name) = other_leaf->second;
+      }
+    }
+
+    return;
+  }
+
+  // Get distances from node's father to considered leaves
+  distsToNodeFather.clear();
+  double nodeToFather = node->getDistanceToFather();
+  for (map<const Node*, vector<pair<string, double> > >::iterator son = leavesDists.begin(); son != leavesDists.end(); ++son)
+  {
+    for (vector< pair<string, double> >::iterator leaf = (son->second).begin(); leaf != (son->second).end(); ++leaf)
+    {
+      distsToNodeFather.push_back(make_pair(leaf->first, (leaf->second + nodeToFather)));
+    }
+  }
+}
+
+DistanceMatrix* TreeTemplateTools::getDistanceMatrix(const TreeTemplate<Node>& tree)
+{
+  DistanceMatrix* matrix = new DistanceMatrix(tree.getLeavesNames());
+  vector< pair<string, double> > distsToRoot;
+  processDistsInSubtree_(tree.getRootNode(), *matrix, distsToRoot);
+  return matrix;
+}
+
+/******************************************************************************/
+
+std::vector<const Node*> TreeTemplateTools::getRemainingNeighbors(const Node* node1, const Node* node2, const Node* node3)
+{
+  vector<const Node*> neighbors = node1->getNeighbors();
+  vector<const Node*> neighbors2;
+  for (size_t k = 0; k < neighbors.size(); k++)
+  {
+    const Node* n = neighbors[k];
+    if (n != node2 && n != node3)
+      neighbors2.push_back(n);
+  }
+  return neighbors2;
+}
+
+/******************************************************************************/
+
+void TreeTemplateTools::incrementAllIds(Node* node, int increment)
+{
+  node->setId(node->getId() + increment);
+  for (size_t i = 0; i < node->getNumberOfSons(); i++)
+  {
+    incrementAllIds(node->getSon(i), increment);
+  }
+}
+
+/******************************************************************************/
+
+void TreeTemplateTools::getNodePropertyNames(const Node& node, vector<string>& propertyNames)
+{
+  VectorTools::extend(propertyNames, node.getNodePropertyNames());
+  for (size_t i = 0; i < node.getNumberOfSons(); i++)
+  {
+    getNodePropertyNames(*node.getSon(i), propertyNames);
+  }
+}
+
+void TreeTemplateTools::getNodeProperties(const Node& node, const string& propertyName, map<int, const Clonable*>& properties)
+{
+  if (node.hasNodeProperty(propertyName))
+    properties[node.getId()] = node.getNodeProperty(propertyName);
+  for (size_t i = 0; i < node.getNumberOfSons(); i++)
+  {
+    getNodeProperties(*node.getSon(i), propertyName, properties);
+  }
+}
+
+void TreeTemplateTools::getNodeProperties(Node& node, const string& propertyName, map<int, Clonable*>& properties)
+{
+  if (node.hasNodeProperty(propertyName))
+    properties[node.getId()] = node.getNodeProperty(propertyName);
+  for (size_t i = 0; i < node.getNumberOfSons(); i++)
+  {
+    getNodeProperties(*node.getSon(i), propertyName, properties);
+  }
+}
+
+/******************************************************************************/
+
+void TreeTemplateTools::getBranchPropertyNames(const Node& node, vector<string>& propertyNames)
+{
+  VectorTools::extend(propertyNames, node.getBranchPropertyNames());
+  for (size_t i = 0; i < node.getNumberOfSons(); i++)
+  {
+    getBranchPropertyNames(*node.getSon(i), propertyNames);
+  }
+}
+
+void TreeTemplateTools::getBranchProperties(const Node& node, const string& propertyName, map<int, const Clonable*>& properties)
+{
+  if (node.hasBranchProperty(propertyName))
+    properties[node.getId()] = node.getBranchProperty(propertyName);
+  for (size_t i = 0; i < node.getNumberOfSons(); i++)
+  {
+    getBranchProperties(*node.getSon(i), propertyName, properties);
+  }
+}
+
+void TreeTemplateTools::getBranchProperties(Node& node, const string& propertyName, map<int, Clonable*>& properties)
+{
+  if (node.hasBranchProperty(propertyName))
+    properties[node.getId()] = node.getBranchProperty(propertyName);
+  for (size_t i = 0; i < node.getNumberOfSons(); i++)
+  {
+    getBranchProperties(*node.getSon(i), propertyName, properties);
+  }
+}
+
+/******************************************************************************/
+
+bool TreeTemplateTools::haveSameOrderedTopology(const Node& n1, const Node& n2)
+{
+  if (n1.isLeaf() && n2.isLeaf() && n1.getName() != n2.getName())
+    return false;
+  size_t nl1 = n1.getNumberOfSons();
+  size_t nl2 = n2.getNumberOfSons();
+  if (nl1 != nl2)
+    return false;
+
+  bool test = true;
+  for (size_t i = 0; test && i < n1.getNumberOfSons(); ++i)
+  {
+    test &= haveSameOrderedTopology(*n1.getSon(i), *n2.getSon(i));
+  }
+  return test;
+}
+
+/******************************************************************************/
+
+TreeTemplateTools::OrderTreeData_ TreeTemplateTools::orderTree_(Node& node, bool downward, bool orderLeaves)
+{
+  OrderTreeData_ otd;
+
+  if (node.isLeaf() && node.hasFather())
+  {
+    otd.size = 1;
+    otd.firstLeaf = node.getName();
+  }
+  else
+  {
+    vector<size_t> nbSons;
+    vector<string> firstLeaves;
+    for (size_t i = 0; i < node.getNumberOfSons(); i++)
+    {
+      OrderTreeData_ otdsub = orderTree_(*node.getSon(i), downward, orderLeaves);
+      if (i == 0)
+        otd.firstLeaf = otdsub.firstLeaf;
+      else if (orderLeaves && otdsub.firstLeaf < otd.firstLeaf)
+        otd.firstLeaf = otdsub.firstLeaf;
+      nbSons.push_back(otdsub.size);
+      firstLeaves.push_back(otdsub.firstLeaf);
+    }
+    otd.size = VectorTools::sum(nbSons);
+
+    // Now swap nodes:
+    if (downward)
+    {
+      for (size_t i = 0; i < nbSons.size() - 1; ++i)
+      {
+        size_t pos;
+        vector<size_t> index = VectorTools::whichMaxAll(nbSons);
+        if (index.size() == 1 || !orderLeaves)
+        {
+          pos = index[0];
+        }
+        else
+        {
+          // There are ties to solve:
+          vector<string> v;
+          for (size_t j = 0; j < index.size(); ++j)
+          {
+            v.push_back(firstLeaves[index[j]]);
+          }
+          size_t mx = VectorTools::whichMax(v);
+          pos = index[mx];
+        }
+        if (pos != i)
+        {
+          node.swap(i, pos);
+          nbSons[pos] = nbSons[i];
+        }
+        nbSons[i] = 0;
+      }
+    }
+    else
+    {
+      for (size_t i = 0; i < nbSons.size() - 1; ++i)
+      {
+        size_t pos;
+        vector<size_t> index = VectorTools::whichMinAll(nbSons);
+        if (index.size() == 1 || !orderLeaves)
+        {
+          pos = index[0];
+        }
+        else
+        {
+          // There are ties to solve:
+          vector<string> v;
+          for (size_t j = 0; j < index.size(); ++j)
+          {
+            v.push_back(firstLeaves[index[j]]);
+          }
+          size_t mx = VectorTools::whichMin(v);
+          pos = index[mx];
+        }
+        if (pos != i)
+        {
+          node.swap(i, pos);
+          nbSons[pos] = nbSons[i];
+        }
+        nbSons[i] = otd.size + 1;
+      }
+    }
+  }
+  return otd;
+}
+
+/******************************************************************************/
+
+void TreeTemplateTools::midRoot (TreeTemplate<Node>& tree, const string& criterion)
+{
+  if(not (criterion == "variance" || "sum of squares"))
+    throw Exception("TreeTemplateTools::reRoot Illegal criterion value '" + criterion + "'");
+
+  if(tree.isRooted())
+    tree.unroot();
+  Node* ref_root = tree.getRootNode();
+   /*
+   * The bestRoot object records :
+   * -- the current best branch : .first
+   * -- the current best value of the criterion : .second["value"]
+   * -- the best position of the root on the branch : .second["position"]
+   *      0 is toward the original root, 1 is away from it
+   */
+  pair<Node*, map<string, double> > best_root_branch;
+  best_root_branch.first = ref_root; // nota: the root does not correspond to a branch as it has no father
+  best_root_branch.second ["position"] = -1;
+  best_root_branch.second ["score"] = numeric_limits<double>::max();
+
+  // find the best root
+  TreeTemplateTools::getBestRootInSubtree(tree, criterion, ref_root, best_root_branch);
+  tree.rootAt(ref_root); // back to the original root
+
+  // reroot
+  const double pos = best_root_branch.second["position"];
+  if(pos<1e-6 or pos>1-1e-6)
+    // The best root position is on a node (this is often the case with the sum of squares criterion)
+    tree.rootAt(pos<1e-6 ? best_root_branch.first->getFather() : best_root_branch.first);
+  else
+    // The best root position is somewhere on a branch (a new Node is created)
+    {
+    Node* new_root = new Node();
+    new_root->setId( TreeTools::getMPNUId(tree, tree.getRootId()) );
+
+    double root_branch_length = best_root_branch.first->getDistanceToFather();
+    Node* best_root_father = best_root_branch.first->getFather();
+
+    best_root_father->removeSon(best_root_branch.first);
+    best_root_father->addSon(new_root);
+    new_root->addSon(best_root_branch.first);
+
+    new_root->setDistanceToFather(max(pos * root_branch_length, 1e-6));
+    best_root_branch.first->setDistanceToFather(max((1-pos) * root_branch_length, 1e-6));
+
+    // The two branches leaving the root must have the same branch properties
+    const vector<string> branch_properties = best_root_branch.first->getBranchPropertyNames();
+    for(vector<string>::const_iterator p = branch_properties.begin(); p!=branch_properties.end(); ++p)
+      new_root->setBranchProperty(*p, *best_root_branch.first->getBranchProperty(*p));
+
+    tree.rootAt(new_root);
+    }
+}
+
+/******************************************************************************/
+
+double TreeTemplateTools::getRadius (TreeTemplate<Node>& tree)
+{
+  TreeTemplateTools::midRoot(tree, "sum of squares");
+  Moments_ moments = getSubtreeMoments(tree.getRootNode());
+  double radius = moments.sum / moments.numberOfLeaves;
+  return radius;
+}
+
+/******************************************************************************/
+
+void TreeTemplateTools::getBestRootInSubtree (TreeTemplate<Node>& tree, const string& criterion, Node* node, pair<Node*, map<string, double> >& bestRoot)
+{
+  const vector<Node*> sons = node->getSons(); // copy
+  tree.rootAt(node);
+
+  // Try to place the root on each branch downward node
+  for(vector<Node*>::const_iterator son=sons.begin(); son!=sons.end(); ++son)
+    {
+    // Compute the moment of the subtree on son's side
+    Moments_ son_moment = getSubtreeMoments(*son);
+
+    // Compute the moment of the subtree on node's side
+    tree.rootAt(*son);
+    Moments_ node_moment = getSubtreeMoments(node);
+    tree.rootAt(node);
+
+    /*
+     * Get the position of the root on this branch that
+     * minimizes the root-to-leaves distances variance.
+     *
+     * This variance can be written in the form A x^2 + B x + C
+     */
+    double min_criterion_value;
+    double best_position; // 0 is toward the root, 1 is away from it
+
+    const TreeTemplateTools::Moments_& m1 = node_moment;
+    const TreeTemplateTools::Moments_& m2 = son_moment;
+    const double d = (**son).getDistanceToFather();
+    const double n1 = m1.numberOfLeaves;
+    const double n2 = m2.numberOfLeaves;
+
+    double A=0, B=0, C=0;
+    if(criterion == "sum of squares")
+      {
+      A = (n1 + n2) * d * d;
+      B = 2 * d * (m1.sum - m2.sum) - 2 * n2 * d * d;
+      C = m1.squaresSum + m2.squaresSum
+          + 2 * m2.sum * d
+          + n2 * d * d;
+      }
+    else if(criterion == "variance")
+      {
+      A = 4 * n1 * n2 * d*d;
+      B = 4 * d * ( n2 * m1.sum - n1 * m2.sum - d * n1 * n2);
+      C = (n1 + n2) * (m1.squaresSum + m2.squaresSum) + n1 * d * n2 * d
+          + 2 * n1 * d * m2.sum - 2 * n2 * d * m1.sum
+          - (m1.sum + m2.sum) * (m1.sum + m2.sum);
+      }
+
+    if(A < 1e-20)
+      {
+      min_criterion_value = numeric_limits<double>::max();
+      best_position = 0.5;
+      }
+    else
+      {
+      min_criterion_value = C - B*B / (4*A);
+      best_position = - B / (2*A);
+      if(best_position < 0)
+        {
+        best_position = 0;
+        min_criterion_value = C;
+        }
+      else if(best_position > 1)
+        {
+        best_position = 1;
+        min_criterion_value = A+B+C;
+        }
+      }
+
+    // Is this branch is the best seen, update 'bestRoot'
+    if(min_criterion_value < bestRoot.second["score"])
+      {
+      bestRoot.first = *son;
+      bestRoot.second["position"] = best_position;
+      bestRoot.second["score"] = min_criterion_value;
+      }
+
+    // Recurse
+    TreeTemplateTools::getBestRootInSubtree(tree, criterion, *son, bestRoot);
+    }
+}
+
+/******************************************************************************/
+
+TreeTemplateTools::Moments_ TreeTemplateTools::getSubtreeMoments (const Node* node)
+{
+  TreeTemplateTools::Moments_ moments = {0,0,0};
+
+  if(node->isLeaf())
+    {
+    moments.numberOfLeaves = 1;
+    }
+  else
+    {
+    const size_t nsons = node->getNumberOfSons();
+    for(size_t i=0; i<nsons; ++i)
+      {
+      const Node* son = node->getSon(i);
+      const TreeTemplateTools::Moments_ son_moments = TreeTemplateTools::getSubtreeMoments(son);
+      const double d = son->getDistanceToFather();
+      moments.numberOfLeaves += son_moments.numberOfLeaves;
+      moments.sum += son_moments.sum + d * son_moments.numberOfLeaves;
+      moments.squaresSum += son_moments.squaresSum + 2 * d * son_moments.sum + son_moments.numberOfLeaves * d*d;
+      }
+    }
+
+  return moments;
+}
+
+/******************************************************************************/
diff --git a/src/Bpp/Phyl/TreeTemplateTools.h b/src/Bpp/Phyl/TreeTemplateTools.h
new file mode 100644
index 0000000..8e23145
--- /dev/null
+++ b/src/Bpp/Phyl/TreeTemplateTools.h
@@ -0,0 +1,1246 @@
+//
+// File: TreeTemplateTools.h
+// Created by:  Julien Dutheil
+// Created on: Fri Oct  13 13:00 2006
+// From file TreeTools.h
+// Created on: Wed Aug  6 13:45:28 2003
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _TREETEMPLATETOOLS_H_
+#define _TREETEMPLATETOOLS_H_
+
+#include "TreeTools.h"
+#include <Bpp/Numeric/Random/RandomTools.h>
+
+//From the STL:
+#include <string>
+#include <vector>
+
+namespace bpp
+{
+
+template<class N> class TreeTemplate;
+
+
+/**
+ * @brief Utilitary methods working with TreeTemplate and Node objects.
+ *
+ * @see TreeTools for more generic methods.
+ */
+class TreeTemplateTools
+{
+  public:
+    TreeTemplateTools() {}
+    virtual ~TreeTemplateTools() {}
+
+  public:
+    
+    /**
+     * @name Retrieve topology information
+     *
+     * @{
+     */
+
+    /**
+     * @brief Retrieve all leaves from a subtree.
+     *
+     * @param node The node that defines the subtree.
+     * @return A vector of pointers toward each leaf in the subtree.
+     */
+    template<class N>
+    static std::vector<N*> getLeaves(N& node)
+    {
+      std::vector<N*> leaves;
+      getLeaves<N>(node, leaves);
+      return leaves;
+    }
+
+    /**
+     * @brief Retrieve all leaves from a subtree.
+     *
+     * @param node The node that defines the subtree.
+     * @param leaves A vector of pointers toward each leaf in the subtree.
+     */
+    template<class N>
+    static void getLeaves(N & node, std::vector<N *> & leaves)
+    {
+      if(node.isLeaf())
+      {
+        leaves.push_back(& node);
+      }
+      for(size_t i = 0; i < node.getNumberOfSons(); i++)
+      {
+        getLeaves<N>(* node.getSon(i), leaves);
+      }
+    }
+
+    /**
+     * @brief Retrieve all leaves ids from a subtree.
+     *
+     * @param node The node that defines the subtree.
+     * @return A vector of ids.
+     */
+    static std::vector<int> getLeavesId(const Node& node)
+    {
+      std::vector<int> ids;
+      getLeavesId(node, ids);
+      return ids;
+    }
+
+    /**
+     * @brief Retrieve all leaves ids from a subtree.
+     *
+     * @param node The node that defines the subtree.
+     * @param ids A vector of ids.
+     */
+    static void getLeavesId(const Node& node, std::vector<int>& ids)
+    {
+      if(node.isLeaf()) {
+        ids.push_back(node.getId());
+      }
+      for(size_t i = 0; i < node.getNumberOfSons(); i++) {
+        getLeavesId(* node.getSon(i), ids);
+      }
+    }
+    
+  /**
+   * @brief Retrieve all nodes ids that are ancestors of a node.
+   *
+   * @param node The node
+   * @return A vector of ids.
+   */
+  static std::vector<int> getAncestorsId(const Node& node)
+  {
+    std::vector<int> ids;
+    const Node* n = &node;
+    while (n->hasFather()) {
+      n = n->getFather();
+      ids.push_back(n->getId());
+    }
+    return ids;
+  }
+
+    /**
+     * @brief Get the id of a leaf given its name in a subtree.
+     *
+     * @param node The node defining the subtree to search.
+     * @param name The name of the node.
+     * @return The id of the node.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static int getLeafId(const Node& node, const std::string& name) throw (NodeNotFoundException)
+    {
+      int* id = 0;
+      searchLeaf(node, name, id);
+      if (id == 0) throw NodeNotFoundException("TreeTemplateTools::getLeafId().", name);
+      else
+      {
+        int i = *id;
+        delete id;
+        return i;
+      }
+    }
+
+    /**
+     * @brief Get the id of a leaf given its name in a subtree.
+     *
+     * @param node The node defining the subtree to search.
+     * @param name The name of the node.
+     * @param id The id of the node.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static void searchLeaf(const Node& node, const std::string& name, int*& id) throw (NodeNotFoundException)
+    {
+      if (node.isLeaf())
+      {
+        if (node.getName() == name)
+        {
+          id = new int(node.getId());
+          return;
+        }
+      }
+      for (size_t i = 0; i < node.getNumberOfSons(); i++)
+      {
+        searchLeaf(* node.getSon(i), name, id);
+      }
+    }
+
+    /**
+     * @brief Remove a leaf node and its parent node, while correcting for branch lengths.
+     *
+     * @param tree The tree to edit.
+     * @param leafName The name of the leaf node.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    template<class N>
+    static void dropLeaf(TreeTemplate<N>& tree, const std::string& leafName) throw (NodeNotFoundException, Exception)
+    {
+      N* leaf = tree.getNode(leafName);
+      if (!leaf->hasFather())
+        throw Exception("TreeTemplateTools::dropLeaf(). Leaf is the only node in the tree, can't remove it.");
+      N* parent = leaf->getFather();
+      if (parent->getNumberOfSons() > 2)
+      {
+        //The easy case:
+        parent->removeSon(leaf);
+        delete leaf;
+      }
+      else if (parent->getNumberOfSons() == 2)
+      {
+        //We have to delete the parent node as well:
+        N* brother = parent->getSon(0);
+        if (brother == leaf) brother = parent->getSon(1);
+        if (!parent->hasFather())
+        {
+          //The brother becomes the root:
+          if (leaf->hasDistanceToFather() && brother->hasDistanceToFather())
+          {
+            brother->setDistanceToFather(brother->getDistanceToFather() + leaf->getDistanceToFather());
+          }
+          brother->removeFather();
+          tree.setRootNode(brother);
+          delete parent;
+          delete leaf;
+        }
+        else
+        {
+          N* gParent = parent->getFather();
+          if (brother->hasDistanceToFather() && parent->hasDistanceToFather())
+          {
+            brother->setDistanceToFather(brother->getDistanceToFather() + parent->getDistanceToFather());
+          }
+          size_t pos = gParent->getSonPosition(parent);
+          gParent->setSon(pos, brother);
+          delete parent;
+          delete leaf;
+        }
+      }
+      else
+      {
+        //Dunno what to do in that case :(
+        throw Exception("TreeTemplateTools::dropLeaf. Parent node as only one child, I don't know what to do in that case :(");
+      }
+    }
+
+    /**
+     * @brief Remove a subtree defined by its root node and its parent node, while correcting for branch lengths.
+     *
+     * @param tree The tree to edit.
+     * @param subtree The subtree to remove, defined by its root node.
+     * @throw Exception If something unexpected happens :s 
+     */
+    template<class N>
+    static void dropSubtree(TreeTemplate<N>& tree, Node* subtree) throw (Exception)
+    {
+      if (!subtree->hasFather())
+        throw Exception("TreeTemplateTools::dropSubtree(). Trying to remove the full tree!");
+      N* parent = subtree->getFather();
+      if (parent->getNumberOfSons() > 2)
+      {
+        //The easy case:
+        parent->removeSon(subtree);
+        deleteSubtree(subtree);
+      }
+      else if (parent->getNumberOfSons() == 2)
+      {
+        //We have to delete the parent node as well:
+        N* brother = parent->getSon(0);
+        if (brother == subtree) brother = parent->getSon(1);
+        if (!parent->hasFather())
+        {
+          //The brother becomes the root:
+          if (subtree->hasDistanceToFather() && brother->hasDistanceToFather())
+          {
+            brother->setDistanceToFather(brother->getDistanceToFather() + subtree->getDistanceToFather());
+          }
+          tree.setRootNode(brother);
+          delete parent;
+          deleteSubtree(subtree);
+        }
+        else
+        {
+          N* gParent = parent->getFather();
+          if (brother->hasDistanceToFather() && parent->hasDistanceToFather())
+          {
+            brother->setDistanceToFather(brother->getDistanceToFather() + parent->getDistanceToFather());
+          }
+          size_t pos = gParent->getSonPosition(parent);
+          gParent->setSon(pos, brother);
+          delete parent;
+          deleteSubtree(subtree);
+        }
+      }
+      else
+      {
+        //Dunno what to do in that case :(
+        throw Exception("TreeTemplateTools::dropSubtree. Parent node as only one child, I don't know what to do in that case :(");
+      }
+    }
+
+    /**
+     * @brief Sample a subtree by removing leaves randomly.
+     *
+     * @param tree The tree to edit.
+     * @param leaves The leafs names that should be sampled. They must be found in the tree otherwise an exception will be thrown.
+     * @param size The number of leaves in the final sample. If greater or equal to the number of leaf names, the function returns without doing anything.
+     */
+    template<class N>
+    static void sampleSubtree(TreeTemplate<N>& tree, const std::vector<std::string>& leaves, size_t size)
+    {
+      std::vector<std::string> names = leaves;
+      for (size_t n = names.size(); n > size; --n) {
+        size_t i = RandomTools::giveIntRandomNumberBetweenZeroAndEntry(n);
+        dropLeaf(tree, names[i]);
+        names.erase(names.begin() + i);
+      }
+    }
+
+    /**
+     * @brief Retrieve all son nodes from a subtree.
+     *
+     * @param node The node that defines the subtree.
+     * @return A vector of pointers toward each son node in the subtree.
+     */
+    template<class N>
+    static std::vector<N*> getNodes(N& node)
+    {
+      std::vector<N *> nodes;
+      getNodes<N>(node, nodes);
+      return nodes;
+    }
+
+    /**
+     * @brief Retrieve all son nodes from a subtree.
+     *
+     * @param node The node that defines the subtree.
+     * @param nodes A vector of pointers toward each son node in the subtree.
+     */
+    template<class N>
+    static void getNodes(N & node, std::vector<N*> & nodes)
+    {
+      for(size_t i = 0; i < node.getNumberOfSons(); i++)
+      {
+        getNodes<N>(*node.getSon(i), nodes);
+      }
+      nodes.push_back(& node);
+    }
+
+    /**
+     * @brief Retrieve all nodes ids from a subtree.
+     *
+     * @param node The node that defines the subtree.
+     * @return A vector of ids.
+     */
+    static std::vector<int> getNodesId(const Node& node)
+    {
+      std::vector<int> ids;
+      getNodesId(node, ids);
+      return ids;
+    }
+
+    /**
+     * @brief Retrieve all branches ids from a subtree.
+     *
+     * @param node The node that defines the subtree.
+     * @return A vector of ids.
+     */
+    static std::vector<int> getBranchesId(const Node& node)
+    {
+      std::vector<int> ids;
+      getBranchesId(node, ids);
+      return ids;
+    }
+
+    /**
+     * @brief Retrieve all nodes ids from a subtree.
+     *
+     * @param node The node that defines the subtree.
+     * @param ids A vector of ids.
+     */
+    static void getNodesId(const Node& node, std::vector<int>& ids)
+    {
+      for (size_t i = 0; i < node.getNumberOfSons(); i++)
+      {
+        getNodesId(*node.getSon(i), ids);
+      }
+      ids.push_back(node.getId());
+    }
+
+    /**
+     * @brief Retrieve all branches ids from a subtree.
+     *
+     * @param node The node that defines the subtree.
+     * @param ids A vector of ids.
+     */
+    static void getBranchesId(const Node& node, std::vector<int>& ids)
+    {
+      for (size_t i = 0; i < node.getNumberOfSons(); i++)
+      {
+        getNodesId(*node.getSon(i), ids);
+      }
+    }
+
+    /**
+     * @brief Retrieve all inner nodes from a subtree.
+     *
+     * @param node The node that defines the subtree.
+     * @return A vector of pointers toward each inner node in the subtree.
+     */
+    template<class N>
+    static std::vector<N*> getInnerNodes(N& node)
+    {
+      std::vector<N *> nodes;
+      getInnerNodes<N>(node, nodes);
+      return nodes;
+    }
+
+    /**
+     * @brief Retrieve all inner nodes from a subtree.
+     *
+     * A inner node is a node with degree > 1, that is, all nodes but the leaves, be they terminal or not.
+     *
+     * @param node The node that defines the subtree.
+     * @param nodes A vector to be filled with pointers toward each inner node in the subtree.
+     */
+    template<class N>
+    static void getInnerNodes(N& node, std::vector<N*>& nodes)
+    {
+      for(size_t i = 0; i < node.getNumberOfSons(); i++)
+      {
+        getInnerNodes<N>(* node.getSon(i), nodes);
+      }
+      if (!node.isLeaf()) 
+        nodes.push_back(&node); //Do not add leaves!
+    }
+
+    /**
+     * @brief Retrieve all inner nodes ids from a subtree.
+     *
+     * A inner node is a node with degree > 1, that is, all nodes but the leaves, be they terminal or not.
+     *
+     * @param node The node that defines the subtree.
+     * @return A vector of ids.
+     */
+    static std::vector<int> getInnerNodesId(const Node& node)
+    {
+      std::vector<int> ids;
+      getInnerNodesId(node, ids);
+      return ids;
+    }
+
+    /**
+     * @brief Retrieve all inner nodes ids from a subtree.
+     *
+     * @param node The node that defines the subtree.
+     * @param ids  A vector to be filled with the resulting ids.
+     */
+    static void getInnerNodesId(const Node& node, std::vector<int> & ids)
+    {
+      for (size_t i = 0; i < node.getNumberOfSons(); i++)
+      {
+        getInnerNodesId(* node.getSon(i), ids);
+      }
+      if (!node.isLeaf())
+        ids.push_back(node.getId()); //Do not add leaves!
+    }
+
+    /**
+     * @param node The node defining the subtree to be searched.
+     * @param id   The id to search for.
+     * @return     Nodes with the specified id.
+     */
+    template<class N>
+    static std::vector<N*> searchNodeWithId(N& node, int id)
+    {
+      std::vector<N*> nodes;
+      searchNodeWithId<N>(node, id, nodes);
+      return nodes;    
+    }
+
+    /**
+     * @param node  The node defining the subtree to be searched.
+     * @param id    The id to search for.
+     * @param nodes A vector to be filled with the matching nodes.
+     */
+    template<class N>
+    static void searchNodeWithId(N& node, int id, std::vector<N*>& nodes)
+    {
+      for (size_t i = 0; i < node.getNumberOfSons(); ++i)
+      {
+        searchNodeWithId<N>(*node.getSon(i), id, nodes);
+      }
+      if (node.getId() == id) nodes.push_back(&node);
+    }
+
+    /**
+     * @param node  The node defining the subtree to be searched.
+     * @param id    The id to search for.
+     * @return The first node encountered with the given id, or 0 if no node with the given id is found.
+     */
+    static Node* searchFirstNodeWithId(Node& node, int id)
+    {
+      if (node.getId() == id) 
+        return &node;
+      else {
+        for (size_t i = 0; i < node.getNumberOfSons(); ++i)
+        {
+          Node* result = searchFirstNodeWithId(*node.getSon(i), id);
+          if (result)
+            return result;
+        }
+      }
+      return 0;
+    }
+
+    /**
+     * @param node  The node defining the subtree to be searched.
+     * @param id    The id to search for.
+     * @return The first node encountered with the given id, or 0 if no node with the given id is found.
+     */
+    static const Node* searchFirstNodeWithId(const Node& node, int id)
+    {
+      if (node.getId() == id) 
+        return &node;
+      else {
+        for (size_t i = 0; i < node.getNumberOfSons(); ++i)
+        {
+          const Node* result = searchFirstNodeWithId(*node.getSon(i), id);
+          if (result)
+            return result;
+        }
+      }
+      return 0;
+    }
+
+    /**
+     * @param node The node defining the subtree to be searched.
+     * @param id   The id to search for.
+     * @return     True if the subtree contains a node with the specified id.
+     */
+    template<class N>
+    static bool hasNodeWithId(const N& node, int id)
+    {
+      if (node.getId() == id) return true;
+      else
+      {
+        for(size_t i = 0; i < node.getNumberOfSons(); i++)
+        {
+          if(hasNodeWithId(*node.getSon(i), id)) return true;
+        }
+        return false;
+      }
+    }
+
+    /**
+     * @param node The node defining the subtree to be searched.
+     * @param name The name to search for.
+     * @return     Nodes with the specified name.
+     */
+    template<class N>
+    static std::vector<N*> searchNodeWithName(N& node, const std::string& name)
+    {
+      std::vector<N*> nodes;
+      searchNodeWithId<N>(node, name, nodes);
+      return nodes;    
+    }
+
+    /**
+     * @param node  The node defining the subtree to be searched.
+     * @param name  The name to search for.
+     * @param nodes A vector to be filled with the matching nodes.
+     */
+    template<class N>
+    static void searchNodeWithName(N& node, const std::string& name, std::vector<N*> & nodes)
+    {
+      for(size_t i = 0; i < node.getNumberOfSons(); i++)
+      {
+        searchNodeWithName<N>(*node.getSon(i), name, nodes);
+      }
+      if(node.hasName() && node.getName() == name) nodes.push_back(&node);
+    }
+
+    /**
+     * @param node The node defining the subtree to be searched.
+     * @param name The name to search for.
+     * @return     True if the subtree contains a node with the specified name.
+     */
+    template<class N>
+    static bool hasNodeWithName(const N& node, const std::string& name)
+    {
+      if(node.hasName() & node.getName() == name) return true;
+      else
+      {
+        for(size_t i = 0; i < node.getNumberOfSons(); i++)
+        {
+          if(hasNodeWithName(*node.getSon(i), name)) return true;
+        }
+        return false;
+      }
+    }
+
+    /**
+     * @brief Tell if a particular node is the root of a tree
+     * i.e. if it has a father node.
+     *
+     * @param node The node to check.
+     * @return True if node does not have a father.
+     */
+    static bool isRoot(const Node& node) { return !node.hasFather(); }
+
+    /**
+     * @brief Get the number of leaves of a subtree defined by a particular node.
+     *
+     * @param node The node defining the subtree to check.
+     * @return The number of leaves.
+     */
+    static unsigned int getNumberOfLeaves(const Node& node);
+
+    /**
+     * @brief Get the number of nodes of a subtree defined by a particular node.
+     *
+     * @param node The node defining the subtree to check.
+     * @return The number of nodes.
+     */
+    static unsigned int getNumberOfNodes(const Node& node);
+
+    /**
+     * @brief Get the leaves names of a subtree defined by a particular node.
+     *
+     * @param node The node defining the subtree to check.
+     * @return The list of all leaves names.
+     */
+    static std::vector<std::string> getLeavesNames(const Node& node);
+
+    /**
+     * @brief Get the depth of the subtree defined by node 'node', i.e. the maximum
+     * number of sons 'generations'.
+     *
+     * ex:
+     * @verbatim
+     *    +----------A
+     *    |
+     * ---+ N1     +-------B
+     *    |        |
+     *    +--------+ N2
+     *             |
+     *             +------C
+     * @endverbatim
+     * Depth of node 'N1' id 2, depth of node 'N2' is 1, depth of leaves is 0.
+     *
+     * @param node The node defining the subtree to check.
+     * @return The depth of the subtree.
+     */
+    static unsigned int getDepth(const Node& node);
+
+    /**
+     * @brief Get the depths for all nodes of the subtree defined by node 'node', i.e. the maximum
+     * number of sons 'generations'.
+     *
+     * ex:
+     * @verbatim
+     *    +----------A
+     *    |
+     * ---+ N1     +-------B
+     *    |        |
+     *    +--------+ N2
+     *             |
+     *             +------C
+     * @endverbatim
+     * Depth of node 'N1' id 2, depth of node 'N2' is 1, depth of leaves is 0.
+     *
+     * @param node The node defining the subtree to check.
+     * @param depths The map that will contain all the depths of the nodes, with node pointers as keys.
+     * @return The depth of the subtree.
+     */
+    static unsigned int getDepths(const Node& node, std::map<const Node*, unsigned int>& depths);
+
+    /**
+     * @brief Get the height of the subtree defined by node 'node', i.e. the maximum
+     * distance between leaves and the root of the subtree.
+     *
+     * The distance do not include the branch length of the subtree root node.
+     * The height of a leaf is hence 0.
+     *
+     * @param node The node defining the subtree to check.
+     * @return The height of the subtree.
+     * @throw NodePException If a branch length is lacking.
+     */ 
+    static double getHeight(const Node& node);
+
+    /**
+     * @brief Get the heights of all nodes within a subtree defined by node 'node', i.e. the maximum
+     * distance between leaves and the root of the subtree.
+     *
+     * The height of a leaf is 0.
+     *
+     * @param node The node defining the subtree to check.
+     * @param heights The map that will contain all the heights of the nodes, with node pointers as keys.
+     * @return The height of the subtree.
+     * @throw NodePException If a branch length is lacking.
+     */ 
+    static double getHeights(const Node& node, std::map<const Node*, double>& heights);
+
+    /**
+     * @brief Tell is a subtree is multifurcating.
+     *
+     * @param node The root node of the subtree.
+     * @return True is the subtree contains at least one multifurcating
+     * node (including the root node).
+     */
+    static bool isMultifurcating(const Node& node);
+
+    /**
+     * @brief Tells if two subtrees have the same topology.
+     *
+     * The comparison is based on parental relationships and leaf names only, node ids and all branch/node properties are ignored.
+     * The ordering of son nodes is taken into account so that ((A,B),C) will be considered different from ((B,A),C). Considerer
+     * ordering the trees first if you want to perform a strict topological comparison.
+     *
+     * @param n1 Root node of the first subtree.
+     * @param n2 Root node of the second subtree.
+     * @return true if the two subtrees have the same topology.
+     */
+    static bool haveSameOrderedTopology(const Node& n1, const Node& n2);
+
+    static std::vector<Node*> getPathBetweenAnyTwoNodes(Node& node1, Node& node2, bool includeAncestor = true);
+    
+    static std::vector<const Node*> getPathBetweenAnyTwoNodes(const Node & node1, const Node & node2, bool includeAncestor = true);
+    
+    /**
+     * @brief Recursively clone a subtree structure.
+     *
+     * This is a template function allowing to specify the class of the copy.
+     * The template class has to have a constructor accepting const Node& as single argument.
+     *
+     * @param node The basal node of the subtree.
+     * @return The basal node of the new copy.
+     */
+    template<class N>
+    static N* cloneSubtree(const Node& node) 
+    {
+      //First we copy this node using default copy constuctor:
+      N* clone = new N(node);
+      //We remove the link toward the father:
+      //clone->removeFather();
+
+      //Now we perform a hard copy:
+      for (int i = 0; i < static_cast<int>(node.getNumberOfSons()); i++)
+      {
+        clone->addSon(cloneSubtree<N>(*node[i]));
+      }
+      return clone;
+    }
+
+    /**
+     * @brief Recursively delete a subtree structure.
+     *
+     * @param node The basal node of the subtree.
+     */
+    template<class N>
+    static void deleteSubtree(N* node)
+    {
+      for (size_t i = 0; i < node->getNumberOfSons(); ++i)
+      {
+        N* son = node->getSon(i);
+        deleteSubtree(son);
+        delete son;
+      }
+    }
+
+    
+    template<class N>
+    static N* cloneSubtree(const Tree& tree, int nodeId) 
+    {
+      //First we copy this node using default copy constuctor:
+      N* clone = tree.hasNodeName(nodeId) ? new N(nodeId, tree.getNodeName(nodeId)) : new N(nodeId);
+      //Then we set the length:
+      if (tree.hasDistanceToFather(nodeId))
+        clone->setDistanceToFather(tree.getDistanceToFather(nodeId));
+      //Now we copy all sons:
+      std::vector<int> sonsId = tree.getSonsId(nodeId);
+      for (size_t i = 0; i < sonsId.size(); i++)
+      {
+        clone->addSon(cloneSubtree<N>(tree, sonsId[i]));
+      }
+      //Must copy all properties too:
+      std::vector<std::string> names;
+      names = tree.getNodePropertyNames(nodeId);
+      for (size_t i = 0; i < names.size(); i++)
+      {
+        clone->setNodeProperty(names[i], *tree.getNodeProperty(nodeId, names[i]));
+      }
+      names = tree.getBranchPropertyNames(nodeId);
+      for (size_t i = 0; i < names.size(); i++)
+      {
+        clone->setBranchProperty(names[i], *tree.getBranchProperty(nodeId, names[i]));
+      }
+      
+      return clone;
+    }
+    /** @} */
+ 
+    /**
+     * @name Act on branch lengths.
+     *
+     * @{
+     */
+    
+    /**
+     * @brief Get all the branch lengths of a subtree.
+     *
+     * @param node The root node of the subtree.
+     * @return A vector with all branch lengths.
+     * @throw NodePException If a branch length is lacking.
+     */
+    static Vdouble getBranchLengths(const Node& node) throw (NodePException);
+
+    /**
+     * @brief Get the total length (sum of all branch lengths) of a subtree.
+     *
+     * @param node The root node of the subtree.
+     * @param includeAncestor Tell if the branch length of the most ancient node should be included in the counting.
+     * (this should be set to false if this node is the root of the tree for instance).
+      * @return The total length of the subtree.
+     * @throw NodePException If a branch length is lacking.
+     */
+    static double getTotalLength(const Node& node, bool includeAncestor = true) throw (NodePException);
+    
+    /**
+     * @brief Set all the branch lengths of a subtree.
+     *
+     * @param node  The root node of the subtree.
+     * @param brLen The branch length to apply.
+     */
+    static void setBranchLengths(Node& node, double brLen);
+     
+    /**
+     * @brief Remove all the branch lengths of a subtree.
+     *
+     * @param node  The root node of the subtree.
+     */
+    static void deleteBranchLengths(Node& node);
+
+    /**
+     * @brief Give a length to branches that don't have one in a subtree.
+     *
+     * @param node  The root node of the subtree.
+     * @param brLen The branch length to apply.
+     */
+    static void setVoidBranchLengths(Node& node, double brLen);
+        
+    /**
+     * @brief Scale a given tree.
+     *
+     * Multiply all branch lengths by a given factor.
+     *
+     * @param node   The root node of the subtree to scale.
+     * @param factor The factor to multiply all branch lengths with.
+     * @throw NodePException If a branch length is lacking.
+     */
+    static void scaleTree(Node& node, double factor) throw (NodePException);
+   
+    /**
+     * @brief Get the total distance between to nodes.
+     *
+     * Sum all branch lengths between two nodes.
+     *
+     * @param node1 The first node.
+     * @param node2 The second node.
+     * @return The sum of all branch lengths between the two nodes.
+     */
+    static double getDistanceBetweenAnyTwoNodes(const Node& node1, const Node& node2);
+
+    /**
+     * @brief Compute a distance matrix from a tree.
+     *
+     * Compute all distances between each leaves and store them in a matrix.
+     * A new DistanceMatrix object is created, and a pointer toward it is returned.
+     * The destruction of this matrix is left up to the user.
+     *
+     * From version 1.9 of Bio++, this function has been rewritten in a more efficient way
+     * and does not use getDistanceBetweenAnyTwoNodes anymore, but makes use of a more clever
+     * pass on the tree. The new function now works well on trees with thousands of leaves.
+     *
+     * @see getDistanceBetweenAnyTwoNodes
+     *
+     * @author Nicolas Rochette
+     *
+     * @param tree The tree to use.
+     * @return The distance matrix computed from tree.
+     */
+    static DistanceMatrix* getDistanceMatrix(const TreeTemplate<Node>& tree);
+
+  private:
+    /**
+     * @brief Inner function used by getDistanceMatrix.
+     *
+     * (1) Retrieves leaf-leaf distances in node's subtree and
+     *  writes them in the distance matrix.
+     * (2) Returns distances from node's father to those leaves.
+     *
+     * @param node The current node in the recursion.
+     * @param matrix The output matrix which will be filled.
+     * @param distsToNodeFather Intermediate computations contianing the distances of the node to the leaves.
+     */
+    static void processDistsInSubtree_(const Node* node, DistanceMatrix& matrix, std::vector< std::pair<std::string, double> >& distsToNodeFather);
+
+  public:
+    /** @} */
+
+    /**
+     * @name Conversion tools.
+     *
+     * Convert from Newick standard tree description.
+     * The description is for a node, and hence is to be surrounded with
+     * parenthesis. ex: (A:0.001, (B:0.001, C:0.02)90:0.005)50:0.0005
+     *
+     * @{
+     */
+
+    struct Element
+    {
+      public:
+        std::string content;
+        std::string length;
+        std::string bootstrap;
+        bool isLeaf;
+
+      public:
+        Element() : content(), length(), bootstrap(), isLeaf(false) {}
+    };
+
+    static Element getElement(const std::string& elt) throw (IOException);
+
+    /**
+     * @brief Parse a string in the parenthesis format and convert it to
+     * a subtree.
+     *
+     * @param description the string to parse;
+     * @param bootstrap Tell is real bootstrap values are expected. If so, a property with name TreeTools::BOOTSTRAP will be created and stored at the corresponding node.
+     * The property value will be of type Number<double>. Otherwise, an object of type String will be created and stored with the property name propertyName.
+     * @param propertyName The name of the property to store. Only used if bootstrap = false.
+     * @param withId Tells if node ids have been stored in the tree. If set at "true", no bootstrap or property values can be read. Node ids are positioned as bootstrap values for internal nodes, and are concatenated to leaf names after a "_" sign.
+     * @return A pointer toward a dynamically created subtree.
+     */
+    static Node* parenthesisToNode(const std::string& description, bool bootstrap=true, const std::string& propertyName=TreeTools::BOOTSTRAP, bool withId=false);
+  
+    /**
+     * @brief Parse a string in the parenthesis format and convert it to
+     * a tree.
+     *
+     * @param description the string to parse;
+     * @param bootstrap Tells if real bootstrap values are expected. If so, a property with name TreeTools::BOOTSTRAP will be created and stored at the corresponding node.
+     * The property value will be of type Number<double>. Otherwise, an object of type String will be created and stored with the property name propertyName.
+     * @param propertyName The name of the property to store. Only used if bootstrap = false.
+     * @param withId Tells if node ids have been stored in the tree. If set at "true", no bootstrap or property values can be read. Node ids are positioned as bootstrap values for internal nodes, and are concatenated to leaf names after a "_" sign.
+     * @return A pointer toward a dynamically created tree.
+     * @throw Exception in case of bad format.
+     */
+    static TreeTemplate<Node>* parenthesisToTree(const std::string& description, bool bootstrap = true, const std::string& propertyName = TreeTools::BOOTSTRAP, bool withId = false) throw (Exception);
+    
+    /**
+     * @brief Get the parenthesis description of a subtree.
+     *
+     * @param node The node defining the subtree.
+     * @param writeId Tells if node ids must be printed.
+     *                This will overwrite bootstrap values if there are ones.
+     *                Leaves id will be added to the leave names, separated by a '_' character.
+     * @return A string in the parenthesis format.
+     */
+    static std::string nodeToParenthesis(const Node & node, bool writeId = false);
+
+    /**
+     * @brief Get the parenthesis description of a subtree.
+     *
+     * @param node The node defining the subtree.
+     * @param bootstrap Tell is bootstrap values must be writen.
+     * If so, the content of the property with name TreeTools::BOOTSTRAP will be written as bootstrap value.
+     * The property should be a Number<double> object.
+     * Otherwise, the content of the property with name 'propertyName' will be written.
+     * In this later case, the property should be a String object.
+     * @param propertyName The name of the property to use. Only used if bootstrap = false.
+     * @return A string in the parenthesis format.
+     */
+    static std::string nodeToParenthesis(const Node & node, bool bootstrap, const std::string & propertyName);
+
+    /**
+     * @brief Get the parenthesis description of a tree.
+     *
+     * @param tree The tree to convert.
+     * @param writeId Tells if node ids must be printed.
+     *                This will overwrite bootstrap values if there are ones.
+     *                Leaves id will be added to the leave names, separated by a '_' character.
+     * @return A string in the parenthesis format.
+     */
+    static std::string treeToParenthesis(const TreeTemplate<Node>& tree, bool writeId = false);
+    
+    /**
+     * @brief Get the parenthesis description of a tree.
+     *
+     * @param tree The tree to convert.
+     * @param bootstrap Tell is bootstrap values must be writen.
+     * If so, the content of the property with name TreeTools::BOOTSTRAP will be written as bootstrap value.
+     * The property should be a Number<double> object.
+     * Otherwise, the content of the property with name 'propertyName' will be written.
+     * In this later case, the property should be a String object.
+     * @param propertyName The name of the property to use. Only used if bootstrap = false.
+     * @return A string in the parenthesis format.
+     */
+    static std::string treeToParenthesis(const TreeTemplate<Node> & tree, bool bootstrap, const std::string& propertyName);
+  
+    /** @} */
+
+    /**
+     * @name Random trees
+     *
+     * @{
+     */
+
+    /**
+     * @brief Draw a random tree from a list of taxa, using a Yule process.
+     *
+     * @param leavesNames A list of taxa.
+     * @param rooted Tell is the output tree should be rooted.
+     * @return A random tree with all corresponding taxa.
+     */
+    static TreeTemplate<Node>* getRandomTree(std::vector<std::string>& leavesNames, bool rooted=true);
+
+    /** @} */
+    
+    /**
+     * @brief Get a subset of node neighbors.
+     *
+     * Get all neighbors of node node1 that are neither node1 nor node2.
+     * This method is useful for topology manipulations, like NNI.
+     *
+     * @param node1 The node whose neighbors must be retrieved.
+     * @param node2 One neighbor to exclude.
+     * @param node3 Another neighbor to exclude.
+     * @return A vector of neighbors.
+     */
+    static std::vector<const Node*> getRemainingNeighbors(const Node* node1, const Node* node2, const Node* node3);
+
+    /**
+     * @brief This method will add a given value (possibly negative) to all identifiers in a (sub)tree.
+     *
+     * @param node The root node of the (sub)tree to use.
+     * @param increment The value to add.
+     */
+    static void incrementAllIds(Node* node, int increment);
+
+    /**
+     * @name Retrieve properties from a (sub)tree.
+     *
+     * @{
+     */
+
+    /**
+     * @brief Retrieve the names of all available node properties in the tree.
+     *
+     * @param node [in] The root node of the (sub)tree to use.
+     * @param propertyNames [out] a vector where names will be added.
+     */
+    static void getNodePropertyNames(const Node& node, std::vector<std::string>& propertyNames);
+
+    /**
+     * @brief Retrieve all node property objects with a given name over a (sub) tree (const version).
+     *
+     * @param node [in] The root node of the (sub)tree to use.
+     * @param propertyName [in] The name of the property to retrieve.
+     * @param properties [out] A map with pointers toward the properties as values, and node ids as key.
+     * If a node does not contain the given property, then no entry in the map is created.
+     * If an entry already exists in the map, it will be replaced, but the underlying property will not be destroyed.
+     * Property objects are not cloned when added to the map, but passed as pointers.
+     */
+    static void getNodeProperties(const Node& node, const std::string& propertyName, std::map<int, const Clonable*>& properties);
+    
+    /**
+     * @brief Retrieve all node property objects with a given name over a (sub) tree.
+     *
+     * @param node [in] The root node of the (sub)tree to use.
+     * @param propertyName [in] The name of the property to retrieve.
+     * @param properties [out] A map with pointers toward the properties as values, and node ids as key.
+     * If a node does not contain the given property, then no entry in the map is created.
+     * If an entry already exists in the map, it will be replaced, but the underlying property will not be destroyed.
+     * Property objects are not cloned when added to the map, but passed as pointers.
+     */
+    static void getNodeProperties(Node& node, const std::string& propertyName, std::map<int, Clonable*>& properties);
+
+    /**
+     * @brief Retrieve the names of all available branch properties in the tree.
+     *
+     * @param node [in] The root node of the (sub)tree to use.
+     * @param propertyNames [out] a vector where names will be added.
+     */
+    static void getBranchPropertyNames(const Node& node, std::vector<std::string>& propertyNames);
+
+    /**
+     * @brief Retrieve all branch property objects with a given name over a (sub) tree (const version).
+     *
+     * @param node [in] The root node of the (sub)tree to use.
+     * @param propertyName [in] The name of the property to retrieve.
+     * @param properties [out] A map with pointers toward the properties as values, and node ids as key.
+     * If a node does not contain the given property, then no entry in the map is created.
+     * If an entry already exists in the map, it will be replaced, but the underlying property will not be destroyed.
+     * Property objects are not cloned when added to the map, but passed as pointers.
+     */
+    static void getBranchProperties(const Node& node, const std::string& propertyName, std::map<int, const Clonable*>& properties);
+    
+    /**
+     * @brief Retrieve all branch property objects with a given name over a (sub) tree.
+     *
+     * @param node [in] The root node of the (sub)tree to use.
+     * @param propertyName [in] The name of the property to retrieve.
+     * @param properties [out] A map with pointers toward the properties as values, and node ids as key.
+     * If a node does not contain the given property, then no entry in the map is created.
+     * If an entry already exists in the map, it will be replaced, but the underlying property will not be destroyed.
+     * Property objects are not cloned when added to the map, but passed as pointers.
+     */
+    static void getBranchProperties(Node& node, const std::string& propertyName, std::map<int, Clonable*>& properties);
+
+    /**
+     * @brief Swap nodes in the subtree so that they are ordered according to the underlying number of leaves.
+     *
+     * @param node The root node of the (sub)tree to use.
+     * @param downward If yes, biggest subtrees (in terms of number of leaves) will come first. Otherwise, the smallest subtrees will come first.
+     * @param orderLeaves Tell if leaves have to be ordered alphabetically. This ensures that two identical topology will always have the same ordered tree, whatever the initial ordering of nodes.
+     */
+    static void orderTree(Node& node, bool downward = true, bool orderLeaves = false) {
+      orderTree_(node, downward, orderLeaves);
+    }
+    /** @} */
+
+    /**
+     * @brief Midroot the tree by minimizing a given criterion ("variance" or "sum of squares")
+     *
+     * @details
+     * For each branch, the best root position, according to the given criterion, is computed analytically.
+     *
+     * For the 'variance' criterion :
+     * \f[
+     *  (n_1+n_2)^2 V(x)
+     *   = (n_1+n_2) \left[ \sum_{F_1} (d_i + x \delta )^2 + \sum_{F_2} (d_i + (1-x) \delta )^2 \right]
+     *     - \left[ \sum_{F_1} (d_i + x \delta) + \sum_{F_2} (d_i + (1-x) \delta) \right]^2
+     *   = A x^2 + B x + C
+     * \f]
+     * With
+     * \f[ \begin{array}{rcl}
+     * A &=& 4 n_1 n_2 \delta^2 \\
+     * B &=& 4 \delta ( n_2 S_1 - n_1 S_2 - n_1 n_2 \delta ) \\
+     * C &=& (n_1+n_2) (C_1+C_2) + n_1 n_2 \delta^2 + 2 n_1 S_2 \delta - 2 n_2 S_1 \delta - (S_1+S_2)^2 \\
+     * \end{array} \f]
+     *
+     * Where \f$F_1\f$ and \f$F_2\f$ are the sets of leaves on either side of
+     * the root branch,
+     * \f$d_i\f$ is the distance of leaf \f$i\f$ to the nearest end of the root branch,
+     * \f$\delta\f$ is the length of the root branch, and \f$S_k\f$ and \f$C_k\f$ are respectively
+     * \f$\sum_{F_k} d_i\f$ and \f$\sum_{F_k} d_i^2\f$
+     *
+     * ~
+     *
+     * @param tree
+     * @param criterion The criterion upon which to reroot. Legal values : "variance"
+     *   to minimize root-leaf distance variance (molecular clock assumption) or
+     *   "sum of squares" to minimize the sum of root-leaf distance squares.
+     *
+     * @author Nicolas Rochette
+     */
+    static void midRoot (bpp::TreeTemplate<bpp::Node>& tree, const std::string& criterion);
+
+    /**
+     * @brief Get the caracteristic radius of a tree (average distance to the root minimizing the sum of squared distances).
+     *
+     * @param tree The tree (which is rerooted in the process).
+     */
+    static double getRadius (bpp::TreeTemplate<bpp::Node>& tree);
+
+  private:
+    struct OrderTreeData_ {
+      size_t size;
+      std::string firstLeaf;
+      OrderTreeData_(): size(0), firstLeaf("") {}
+    };
+
+    static OrderTreeData_ orderTree_(Node& node, bool downward, bool orderLeaves);
+
+    /**
+     * @brief
+     * A <i>structure</i> recording, for a subtree, the sum of root-leaf distances, the sum of their squares,
+     * and the number of elements in these sums (ie. the number of leaves).
+     *
+     * @details
+     * The branch at the base of the subtree should never be included,
+     * as the subtree of the root does not have one.
+     *
+     */
+    struct Moments_
+    {
+      double sum;
+      double squaresSum;
+      int numberOfLeaves;
+    };
+
+    /**
+     * @brief
+     * Computes the moment of a subtree
+     *
+     * @param node The root of the subtree
+     * @return A Moments_ structure
+     */
+    static Moments_ getSubtreeMoments (const Node* node);
+
+    /**
+     * @brief Find, in the branches of a subtree, the root that minimizes a criterion over the tree.
+     *
+     * @details
+     * The branches are explored recursively. For each branch leaving the input node, the method
+     * computes the best root position, possibly updates the bestRoot parameter, then recurses.
+     *
+     * @param tree The tree to which the subtree belongs. (The root is moved.)
+     * @param criterion The criterion to minimize. Legal values are "variance" and "sum of squares".
+     * @param node The root of the subtree.
+     * @param bestRoot The object storing the best root found, if it is better than the initial one, or otherwise left unchanged.
+     *
+     * @author Nicolas Rochette, Manolo Gouy
+     */
+    static void getBestRootInSubtree (bpp::TreeTemplate<bpp::Node>& tree, const std::string& criterion,  bpp::Node* node, std::pair<bpp::Node*, std::map<std::string, double> >& bestRoot);
+
+};
+
+} //end of namespace bpp.
+
+#endif //_TREETEMPLATETOOLS_H_
+
diff --git a/src/Bpp/Phyl/TreeTools.cpp b/src/Bpp/Phyl/TreeTools.cpp
new file mode 100644
index 0000000..cf9fd28
--- /dev/null
+++ b/src/Bpp/Phyl/TreeTools.cpp
@@ -0,0 +1,1263 @@
+//
+// File: TreeTools.cpp
+// Created by: Julien Dutheil
+// Created on: Wed Aug  6 13:45:28 2003
+//
+
+/*
+   Copyright or © or Copr. CNRS, (November 16, 2004)
+
+   This software is a computer program whose purpose is to provide classes
+   for phylogenetic data analysis.
+
+   This software is governed by the CeCILL  license under French law and
+   abiding by the rules of distribution of free software.  You can  use,
+   modify and/ or redistribute the software under the terms of the CeCILL
+   license as circulated by CEA, CNRS and INRIA at the following URL
+   "http://www.cecill.info".
+
+   As a counterpart to the access to the source code and  rights to copy,
+   modify and redistribute granted by the license, users are provided only
+   with a limited warranty  and the software's author,  the holder of the
+   economic rights,  and the successive licensors  have only  limited
+   liability.
+
+   In this respect, the user's attention is drawn to the risks associated
+   with loading,  using,  modifying and/or developing or reproducing the
+   software by the user in light of its specific status of free software,
+   that may mean  that it is complicated to manipulate,  and  that  also
+   therefore means  that it is reserved for developers  and  experienced
+   professionals having in-depth computer knowledge. Users are therefore
+   encouraged to load and test the software's suitability as regards their
+   requirements in conditions enabling the security of their systems and/or
+   data to be ensured and,  more generally, to use and operate it in the
+   same conditions as regards security.
+
+   The fact that you are presently reading this means that you have had
+   knowledge of the CeCILL license and that you accept its terms.
+ */
+
+#include "TreeTools.h"
+#include "Tree.h"
+#include "BipartitionTools.h"
+#include "Model/Nucleotide/JCnuc.h"
+#include "Distance/DistanceEstimation.h"
+#include "Distance/BioNJ.h"
+#include "Parsimony/DRTreeParsimonyScore.h"
+#include "OptimizationTools.h"
+
+#include <Bpp/Text/TextTools.h>
+#include <Bpp/Text/StringTokenizer.h>
+#include <Bpp/Numeric/Number.h>
+#include <Bpp/BppString.h>
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Numeric/VectorTools.h>
+#include <Bpp/Numeric/Prob/ConstantDistribution.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Alphabet/DNA.h>
+#include <Bpp/Seq/Container/VectorSiteContainer.h>
+
+using namespace bpp;
+
+// From the STL:
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+
+/******************************************************************************/
+
+const string TreeTools::BOOTSTRAP = "bootstrap";
+
+/******************************************************************************/
+
+vector<int> TreeTools::getLeavesId(const Tree& tree, int nodeId) throw (NodeNotFoundException)
+{
+  vector<int> leaves;
+  getLeavesId(tree, nodeId, leaves);
+  return leaves;
+}
+
+void TreeTools::getLeavesId(const Tree& tree, int nodeId, std::vector<int>& leaves) throw (NodeNotFoundException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::getLeavesId", nodeId);
+  if (tree.isLeaf(nodeId))
+  {
+    leaves.push_back(nodeId);
+  }
+  vector<int> sons = tree.getSonsId(nodeId);
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    getLeavesId(tree, sons[i], leaves);
+  }
+}
+
+size_t TreeTools::getNumberOfLeaves(const Tree& tree, int nodeId) throw (NodeNotFoundException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::getNumberOfLeaves", nodeId);
+
+  size_t n = 0;
+  if (tree.isLeaf(nodeId))
+  {
+    ++n;
+  }
+  vector<int> sons = tree.getSonsId(nodeId);
+  for (size_t i = 0; i < sons.size(); ++i)
+  {
+    n += getNumberOfLeaves(tree, sons[i]);
+  }
+  return n;
+}
+
+/******************************************************************************/
+
+int TreeTools::getLeafId(const Tree& tree, int nodeId, const std::string& name)
+throw (NodeNotFoundException)
+{
+  int* id = NULL;
+  searchLeaf(tree, nodeId, name, id);
+  if (id == NULL)
+    throw NodeNotFoundException("TreeTools::getLeafId().", name);
+  else
+  {
+    int i = *id;
+    delete id;
+    return i;
+  }
+}
+
+void TreeTools::searchLeaf(const Tree& tree, int nodeId, const string& name, int*& id)
+throw (NodeNotFoundException)
+{
+  if (tree.isLeaf(nodeId))
+  {
+    if (tree.getNodeName(nodeId) == name)
+    {
+      id = new int(nodeId);
+      return;
+    }
+  }
+  vector<int> sons;
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    searchLeaf(tree, nodeId, name, id);
+  }
+}
+
+/******************************************************************************/
+
+vector<int> TreeTools::getNodesId(const Tree& tree, int nodeId) throw (NodeNotFoundException)
+{
+  vector<int> nodes;
+  getNodesId(tree, nodeId, nodes);
+  return nodes;
+}
+
+void TreeTools::getNodesId(const Tree& tree, int nodeId, vector<int>& nodes) throw (NodeNotFoundException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::getNodesId", nodeId);
+  vector<int> sons = tree.getSonsId(nodeId);
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    getNodesId(tree, sons[i], nodes);
+  }
+  nodes.push_back(nodeId);
+}
+
+/******************************************************************************/
+
+size_t TreeTools::getDepth(const Tree& tree, int nodeId) throw (NodeNotFoundException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::getDepth", nodeId);
+  size_t d = 0;
+  vector<int> sons = tree.getSonsId(nodeId);
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    size_t c = getDepth(tree, sons[i]) + 1;
+    if (c > d)
+      d = c;
+  }
+  return d;
+}
+
+/******************************************************************************/
+
+size_t TreeTools::getDepths(const Tree& tree, int nodeId, map<int, size_t>& depths) throw (NodeNotFoundException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::getDepth", nodeId);
+  size_t d = 0;
+  vector<int> sons = tree.getSonsId(nodeId);
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    size_t c = getDepths(tree, sons[i], depths) + 1;
+    if (c > d)
+      d = c;
+  }
+  depths[nodeId] = d;
+  return d;
+}
+
+/******************************************************************************/
+
+double TreeTools::getHeight(const Tree& tree, int nodeId) throw (NodeNotFoundException, NodeException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::getHeight", nodeId);
+  double d = 0;
+  vector<int> sons = tree.getSonsId(nodeId);
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    double dist = 0;
+    if (tree.hasDistanceToFather(sons[i]))
+      dist = tree.getDistanceToFather(sons[i]);
+    else
+      throw NodeException("Node without branch length.", sons[i]);
+    double c = getHeight(tree, sons[i]) + dist;
+    if (c > d)
+      d = c;
+  }
+  return d;
+}
+
+/******************************************************************************/
+
+double TreeTools::getHeights(const Tree& tree, int nodeId, map<int, double>& heights) throw (NodeNotFoundException, NodeException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::getHeight", nodeId);
+  double d = 0;
+  vector<int> sons = tree.getSonsId(nodeId);
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    double dist = 0;
+    if (tree.hasDistanceToFather(sons[i]))
+      dist = tree.getDistanceToFather(sons[i]);
+    else
+      throw NodeException("Node without branch length.", sons[i]);
+    double c = getHeights(tree, sons[i], heights) + dist;
+    if (c > d)
+      d = c;
+  }
+  heights[nodeId] = d;
+  return d;
+}
+
+/******************************************************************************/
+
+string TreeTools::nodeToParenthesis(const Tree& tree, int nodeId, bool writeId) throw (NodeNotFoundException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::nodeToParenthesis", nodeId);
+  ostringstream s;
+  if (tree.isLeaf(nodeId))
+  {
+    s << tree.getNodeName(nodeId);
+  }
+  else
+  {
+    s << "(";
+    vector<int> sonsId = tree.getSonsId(nodeId);
+    s << nodeToParenthesis(tree, sonsId[0], writeId);
+    for (size_t i = 1; i < sonsId.size(); i++)
+    {
+      s << "," << nodeToParenthesis(tree, sonsId[i], writeId);
+    }
+    s << ")";
+  }
+  if (writeId)
+  {
+    if (tree.isLeaf(nodeId))
+      s << "_";
+    s << nodeId;
+  }
+  else
+  {
+    if (tree.hasBranchProperty(nodeId, BOOTSTRAP))
+      s << (dynamic_cast<const Number<double>*>(tree.getBranchProperty(nodeId, BOOTSTRAP))->getValue());
+  }
+  if (tree.hasDistanceToFather(nodeId))
+    s << ":" << tree.getDistanceToFather(nodeId);
+  return s.str();
+}
+
+/******************************************************************************/
+
+string TreeTools::nodeToParenthesis(const Tree& tree, int nodeId, bool bootstrap, const string& propertyName) throw (NodeNotFoundException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::nodeToParenthesis", nodeId);
+  ostringstream s;
+  if (tree.isLeaf(nodeId))
+  {
+    s << tree.getNodeName(nodeId);
+  }
+  else
+  {
+    s << "(";
+    vector<int> sonsId = tree.getSonsId(nodeId);
+    s << nodeToParenthesis(tree, sonsId[0], bootstrap, propertyName);
+    for (size_t i = 1; i < sonsId.size(); i++)
+    {
+      s << "," << nodeToParenthesis(tree, sonsId[i], bootstrap, propertyName);
+    }
+    s << ")";
+
+    if (bootstrap)
+    {
+      if (tree.hasBranchProperty(nodeId, BOOTSTRAP))
+        s << (dynamic_cast<const Number<double>*>(tree.getBranchProperty(nodeId, BOOTSTRAP))->getValue());
+    }
+    else
+    {
+      if (tree.hasBranchProperty(nodeId, propertyName))
+        s << *(dynamic_cast<const BppString*>(tree.getBranchProperty(nodeId, propertyName)));
+    }
+  }
+  if (tree.hasDistanceToFather(nodeId))
+    s << ":" << tree.getDistanceToFather(nodeId);
+  return s.str();
+}
+
+/******************************************************************************/
+
+string TreeTools::treeToParenthesis(const Tree& tree, bool writeId)
+{
+  ostringstream s;
+  s << "(";
+  int rootId = tree.getRootId();
+  vector<int> sonsId = tree.getSonsId(rootId);
+  if (tree.isLeaf(rootId))
+  {
+    s << tree.getNodeName(rootId);
+    for (size_t i = 0; i < sonsId.size(); i++)
+    {
+      s << "," << nodeToParenthesis(tree, sonsId[i], writeId);
+    }
+  }
+  else
+  {
+    if (sonsId.size() > 0)
+    {
+      s << nodeToParenthesis(tree, sonsId[0], writeId);
+      for (size_t i = 1; i < sonsId.size(); i++)
+      {
+        s << "," << nodeToParenthesis(tree, sonsId[i], writeId);
+      }
+    }
+    // Otherwise, this is an empty tree!
+  }
+  s << ");" << endl;
+  return s.str();
+}
+
+/******************************************************************************/
+
+string TreeTools::treeToParenthesis(const Tree& tree, bool bootstrap, const string& propertyName)
+{
+  ostringstream s;
+  s << "(";
+  int rootId = tree.getRootId();
+  vector<int> sonsId = tree.getSonsId(rootId);
+  if (tree.isLeaf(rootId))
+  {
+    s << tree.getNodeName(rootId);
+    for (size_t i = 0; i < sonsId.size(); i++)
+    {
+      s << "," << nodeToParenthesis(tree, sonsId[i], bootstrap, propertyName);
+    }
+  }
+  else
+  {
+    s << nodeToParenthesis(tree, sonsId[0], bootstrap, propertyName);
+    for (size_t i = 1; i < sonsId.size(); i++)
+    {
+      s << "," << nodeToParenthesis(tree, sonsId[i], bootstrap, propertyName);
+    }
+  }
+  s << ")";
+  if (bootstrap)
+  {
+    if (tree.hasBranchProperty(rootId, BOOTSTRAP))
+      s << (dynamic_cast<const Number<double>*>(tree.getBranchProperty(rootId, BOOTSTRAP))->getValue());
+  }
+  else
+  {
+    if (tree.hasBranchProperty(rootId, propertyName))
+      s << *(dynamic_cast<const BppString*>(tree.getBranchProperty(rootId, propertyName)));
+  }
+  s << ";" << endl;
+  return s.str();
+}
+
+/******************************************************************************/
+
+vector<int> TreeTools::getPathBetweenAnyTwoNodes(const Tree& tree, int nodeId1, int nodeId2, bool includeAncestor)
+throw (NodeNotFoundException)
+{
+  if (!tree.hasNode(nodeId1))
+    throw NodeNotFoundException("TreeTools::getPathBetweenAnyTwoNodes", nodeId1);
+  if (!tree.hasNode(nodeId2))
+    throw NodeNotFoundException("TreeTools::getPathBetweenAnyTwoNodes", nodeId2);
+  vector<int> path;
+  vector<int> pathMatrix1;
+  vector<int> pathMatrix2;
+
+  int nodeUp = nodeId1;
+  while (tree.hasFather(nodeUp))
+  {
+    pathMatrix1.push_back(nodeUp);
+    nodeUp = tree.getFatherId(nodeUp);
+  }
+  pathMatrix1.push_back(nodeUp); // The root.
+
+  nodeUp = nodeId2;
+  while (tree.hasFather(nodeUp))
+  {
+    pathMatrix2.push_back(nodeUp);
+    nodeUp = tree.getFatherId(nodeUp);
+  }
+  pathMatrix2.push_back(nodeUp); // The root.
+  // Must check that the two nodes have the same root!!!
+
+  size_t tmp1 = pathMatrix1.size();
+  size_t tmp2 = pathMatrix2.size();
+
+  while ((tmp1 > 0) && (tmp2 > 0))
+  {
+    if (pathMatrix1[tmp1 - 1] != pathMatrix2[tmp2 - 1])
+      break;
+    tmp1--; tmp2--;
+  }
+  // (tmp1 - 1) and (tmp2 - 1) now point toward the first non-common nodes
+
+  for (size_t y = 0; y < tmp1; ++y)
+  {
+    path.push_back(pathMatrix1[y]);
+  }
+  if (includeAncestor)
+    path.push_back(pathMatrix1[tmp1]);  // pushing once, the Node that was common to both.
+  for (size_t j = tmp2; j > 0; --j)
+  {
+    path.push_back(pathMatrix2[j - 1]);
+  }
+  return path;
+}
+
+/******************************************************************************/
+
+double TreeTools::getDistanceBetweenAnyTwoNodes(const Tree& tree, int nodeId1, int nodeId2)
+{
+  if (!tree.hasNode(nodeId1))
+    throw NodeNotFoundException("TreeTools::getDistanceBetweenAnyTwoNodes", nodeId1);
+  if (!tree.hasNode(nodeId2))
+    throw NodeNotFoundException("TreeTools::getDistanceBetweenAnyTwoNodes", nodeId2);
+  vector<int> path = getPathBetweenAnyTwoNodes(tree, nodeId1, nodeId2, false);
+  double d = 0;
+  for (size_t i = 0; i < path.size(); i++)
+  {
+    d += tree.getDistanceToFather(path[i]);
+  }
+  return d;
+}
+
+/******************************************************************************/
+
+Vdouble TreeTools::getBranchLengths(const Tree& tree, int nodeId) throw (NodeNotFoundException, NodeException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::getBranchLengths", nodeId);
+  Vdouble brLen(1);
+  if (tree.hasDistanceToFather(nodeId))
+    brLen[0] = tree.getDistanceToFather(nodeId);
+  else
+    throw NodeException("TreeTools::getbranchLengths(). No branch length.", nodeId);
+  vector<int> sons = tree.getSonsId(nodeId);
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    Vdouble sonBrLen = getBranchLengths(tree, sons[i]);
+    for (size_t j = 0; j < sonBrLen.size(); j++)
+    {
+      brLen.push_back(sonBrLen[j]);
+    }
+  }
+  return brLen;
+}
+
+/******************************************************************************/
+
+double TreeTools::getTotalLength(const Tree& tree, int nodeId, bool includeAncestor) throw (NodeNotFoundException, NodeException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::getTotalLength", nodeId);
+  if (includeAncestor && !tree.hasDistanceToFather(nodeId))
+    throw NodeException("TreeTools::getTotalLength(). No branch length.", nodeId);
+  double length = includeAncestor ? tree.getDistanceToFather(nodeId) : 0;
+  vector<int> sons = tree.getSonsId(nodeId);
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    length += getTotalLength(tree, sons[i], true);
+  }
+  return length;
+}
+
+/******************************************************************************/
+
+void TreeTools::setBranchLengths(Tree& tree, int nodeId, double brLen) throw (NodeNotFoundException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::setBranchLengths", nodeId);
+  vector<int> nodes = getNodesId(tree, nodeId);
+  for (size_t i = 0; i < nodes.size(); i++)
+  {
+    tree.setDistanceToFather(nodes[i], brLen);
+  }
+}
+
+/******************************************************************************/
+
+void TreeTools::setVoidBranchLengths(Tree& tree, int nodeId, double brLen) throw (NodeNotFoundException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::setVoidBranchLengths", nodeId);
+  vector<int> nodes = getNodesId(tree, nodeId);
+  for (size_t i = 0; i < nodes.size(); i++)
+  {
+    if (!tree.hasDistanceToFather(nodes[i]))
+      tree.setDistanceToFather(nodes[i], brLen);
+  }
+}
+
+/******************************************************************************/
+
+void TreeTools::scaleTree(Tree& tree, int nodeId, double factor) throw (NodeNotFoundException, NodeException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::scaleTree", nodeId);
+  vector<int> nodes = getNodesId(tree, nodeId);
+  for (size_t i = 0; i < nodes.size(); i++)
+  {
+    if (tree.hasFather(nodes[i]))
+    {
+      if (!tree.hasDistanceToFather(nodes[i]))
+        throw NodeException("TreeTools::scaleTree(). Branch with no length", nodes[i]);
+      double brLen = tree.getDistanceToFather(nodes[i]) * factor;
+      tree.setDistanceToFather(nodes[i], brLen);
+    }
+  }
+}
+
+/******************************************************************************/
+
+size_t TreeTools::initBranchLengthsGrafen(Tree& tree, int nodeId) throw (NodeNotFoundException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::initBranchLengthsGrafen", nodeId);
+  vector<int> sons = tree.getSonsId(nodeId);
+  vector<size_t> h(sons.size());
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    h[i] = initBranchLengthsGrafen(tree, sons[i]);
+  }
+  size_t thish = sons.size() == 0 ? 0 : VectorTools::sum<size_t>(h) + sons.size() - 1;
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    tree.setDistanceToFather(sons[i], (double)(thish - h[i]));
+  }
+  return thish;
+}
+
+void TreeTools::initBranchLengthsGrafen(Tree& tree)
+{
+  initBranchLengthsGrafen(tree, tree.getRootId());
+}
+
+/******************************************************************************/
+
+void TreeTools::computeBranchLengthsGrafen(
+  Tree& tree,
+  int nodeId,
+  double power,
+  double total,
+  double& height,
+  double& heightRaised)
+throw (NodeNotFoundException, NodeException)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::computeBranchLengthsGrafen", nodeId);
+  vector<int> sons = tree.getSonsId(nodeId);
+  vector<double> hr(sons.size());
+  height = 0;
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    int son = sons[i];
+    if (tree.hasDistanceToFather(son))
+    {
+      double h;
+      computeBranchLengthsGrafen(tree, sons[i], power, total, h, hr[i]);
+      double d = h + tree.getDistanceToFather(son);
+      if (d > height)
+        height = d;
+    }
+    else
+      throw NodeException ("TreeTools::computeBranchLengthsGrafen. Branch length lacking.", son);
+  }
+  heightRaised = pow(height / total, power) * total;
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    tree.setDistanceToFather(sons[i], heightRaised - hr[i]);
+  }
+}
+
+void TreeTools::computeBranchLengthsGrafen(Tree& tree, double power, bool init)
+throw (NodeException)
+{
+  int rootId = tree.getRootId();
+  if (init)
+  {
+    initBranchLengthsGrafen(tree);
+  }
+  // Scale by total heigth:
+  double totalHeight = getHeight(tree, rootId);
+  double h, hr;
+  computeBranchLengthsGrafen(tree, rootId, power, totalHeight, h, hr);
+}
+
+/******************************************************************************/
+
+double TreeTools::convertToClockTree(Tree& tree, int nodeId, bool noneg)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::convertToClockTree", nodeId);
+  vector<int> sons = tree.getSonsId(nodeId);
+  vector<double> h(sons.size());
+  // We compute the mean height:
+  double l = 0;
+  double maxh = -1.;
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    int son = sons[i];
+    if (tree.hasDistanceToFather(son))
+    {
+      h[i] = convertToClockTree(tree, son);
+      if (h[i] > maxh)
+        maxh = h[i];
+      l += h[i] + tree.getDistanceToFather(son);
+    }
+    else
+      throw NodeException ("TreeTools::convertToClockTree. Branch length lacking.", son);
+  }
+  if (sons.size() > 0)
+    l /= (double)sons.size();
+  if (l < maxh)
+    l = maxh;
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    tree.setDistanceToFather(sons[i], l - h[i]);
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+double TreeTools::convertToClockTree2(Tree& tree, int nodeId)
+{
+  if (!tree.hasNode(nodeId))
+    throw NodeNotFoundException("TreeTools::convertToClockTree2", nodeId);
+  vector<int> sons = tree.getSonsId(nodeId);
+  vector<double> h(sons.size());
+  // We compute the mean height:
+  double l = 0;
+  double maxh = -1.;
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    int son = sons[i];
+    if (tree.hasDistanceToFather(son))
+    {
+      h[i] = convertToClockTree2(tree, son);
+      if (h[i] > maxh)
+        maxh = h[i];
+      l += h[i] + tree.getDistanceToFather(son);
+    }
+    else
+      throw NodeException ("TreeTools::convertToClockTree2. Branch length lacking.", son);
+  }
+  if (sons.size() > 0)
+    l /= (double)sons.size();
+  for (size_t i = 0; i < sons.size(); i++)
+  {
+    scaleTree(tree, sons[i], h[i] > 0 ? l / h[i] : 0);
+  }
+  return l;
+}
+
+/******************************************************************************/
+
+DistanceMatrix* TreeTools::getDistanceMatrix(const Tree& tree)
+{
+  vector<string> names = tree.getLeavesNames();
+  DistanceMatrix* mat = new DistanceMatrix(names);
+  for (size_t i = 0; i < names.size(); i++)
+  {
+    (*mat)(i, i) = 0;
+    for (size_t j = 0; j < i; j++)
+    {
+      (*mat)(i, j) = (*mat)(j, i) = getDistanceBetweenAnyTwoNodes(tree, tree.getLeafId(names[i]), tree.getLeafId(names[j]));
+    }
+  }
+  return mat;
+}
+
+/******************************************************************************/
+
+void TreeTools::midpointRooting(Tree& tree)
+{
+  if (tree.isRooted())
+    tree.unroot();
+  DistanceMatrix* dist = getDistanceMatrix(tree);
+  vector<size_t> pos = MatrixTools::whichMax(*dist);
+  double dmid = (*dist)(pos[0], pos[1]) / 2;
+  int id1 = tree.getLeafId(dist->getName(pos[0]));
+  int id2 = tree.getLeafId(dist->getName(pos[1]));
+  int rootId = tree.getRootId();
+  double d1 = getDistanceBetweenAnyTwoNodes(tree, id1, rootId);
+  double d2 = getDistanceBetweenAnyTwoNodes(tree, id2, rootId);
+  int current = d2 > d1 ? id2 : id1;
+  delete dist;
+  double l = tree.getDistanceToFather(current);
+  double c = l;
+  while (c < dmid)
+  {
+    current = tree.getFatherId(current);
+    l = tree.getDistanceToFather(current);
+    c += l;
+  }
+  tree.newOutGroup(current);
+  int brother = tree.getSonsId(tree.getRootId())[1];
+  if (brother == current)
+    brother = tree.getSonsId(tree.getRootId())[0];
+  tree.setDistanceToFather(current, l - (c - dmid));
+  tree.setDistanceToFather(brother, c - dmid);
+}
+
+/******************************************************************************/
+
+int TreeTools::getMaxId(const Tree& tree, int id)
+{
+  int maxId = id;
+  vector<int> sonsId = tree.getSonsId(id);
+  for (size_t i = 0; i < sonsId.size(); i++)
+  {
+    int subMax = getMaxId(tree, sonsId[i]);
+    if (subMax > maxId)
+      maxId = subMax;
+  }
+  return maxId;
+}
+
+/******************************************************************************/
+
+int TreeTools::getMPNUId(const Tree& tree, int id)
+{
+  vector<int> ids = getNodesId(tree, id);
+  sort(ids.begin(), ids.end());
+  // Check if some id is "missing" in the subtree:
+  for (size_t i = 0; i < ids.size(); i++)
+  {
+    if (ids[i] != (int)i)
+      return (int)i;
+  }
+  // Well, all ids are from 0 to n, so send n+1:
+  return (int)ids.size();
+}
+
+/******************************************************************************/
+
+bool TreeTools::checkIds(const Tree& tree, bool throwException) throw (Exception)
+{
+  vector<int> ids = tree.getNodesId();
+  sort(ids.begin(), ids.end());
+  for (size_t i = 1; i < ids.size(); i++)
+  {
+    if (ids[i] == ids[i - 1])
+    {
+      if (throwException)
+        throw Exception("TreeTools::checkIds. This id is used at least twice: " + TextTools::toString(ids[i]));
+      return false;
+    }
+  }
+  return true;
+}
+
+/******************************************************************************/
+
+VectorSiteContainer* TreeTools::MRPEncode(const vector<Tree*>& vecTr)
+{
+  vector<BipartitionList*> vecBipL;
+  for (size_t i = 0; i < vecTr.size(); i++)
+  {
+    vecBipL.push_back(new BipartitionList(*vecTr[i]));
+  }
+
+  VectorSiteContainer* cont = BipartitionTools::MRPEncode(vecBipL);
+
+  for (size_t i = 0; i < vecTr.size(); i++)
+  {
+    delete vecBipL[i];
+  }
+
+  return cont;
+}
+
+/******************************************************************************/
+
+bool TreeTools::haveSameTopology(const Tree& tr1, const Tree& tr2)
+{
+  size_t jj, nbbip;
+  BipartitionList* bipL1, * bipL2;
+  vector<size_t> size1, size2;
+
+  /* compare sets of leaves */
+  if (!VectorTools::haveSameElements(tr1.getLeavesNames(), tr2.getLeavesNames()))
+    return false;
+
+  /* construct bipartitions */
+  bipL1 = new BipartitionList(tr1, true);
+  bipL1->removeTrivialBipartitions();
+  bipL1->removeRedundantBipartitions();
+  bipL1->sortByPartitionSize();
+  bipL2 = new BipartitionList(tr2, true);
+  bipL2->removeTrivialBipartitions();
+  bipL2->removeRedundantBipartitions();
+  bipL2->sortByPartitionSize();
+
+  /* compare numbers of bipartitions */
+  if (bipL1->getNumberOfBipartitions() != bipL2->getNumberOfBipartitions())
+    return false;
+  nbbip = bipL1->getNumberOfBipartitions();
+
+  /* compare partition sizes */
+  for (size_t i = 0; i < nbbip; i++)
+  {
+    size1.push_back(bipL1->getPartitionSize(i));
+    size2.push_back(bipL1->getPartitionSize(i));
+    if (size1[i] != size2[i])
+      return false;
+  }
+
+  /* compare bipartitions */
+  for (size_t i = 0; i < nbbip; i++)
+  {
+    for (jj = 0; jj < nbbip; jj++)
+    {
+      if (size1[i] == size2[jj] && BipartitionTools::areIdentical(*bipL1, i, *bipL2, jj))
+        break;
+    }
+    if (jj == nbbip)
+      return false;
+  }
+
+  return true;
+}
+
+/******************************************************************************/
+
+int TreeTools::robinsonFouldsDistance(const Tree& tr1, const Tree& tr2, bool checkNames, int* missing_in_tr2, int* missing_in_tr1) throw (Exception)
+{
+  BipartitionList* bipL1, * bipL2;
+  size_t i, j;
+  vector<size_t> size1, size2;
+  vector<bool> bipOK2;
+
+
+  if (checkNames && !VectorTools::haveSameElements(tr1.getLeavesNames(), tr2.getLeavesNames()))
+    throw Exception("Distinct leaf sets between trees ");
+
+  /* prepare things */
+  int missing1 = 0;
+  int missing2 = 0;
+
+  bipL1 = new BipartitionList(tr1, true);
+  bipL1->removeTrivialBipartitions();
+  bipL1->sortByPartitionSize();
+  bipL2 = new BipartitionList(tr2, true);
+  bipL2->removeTrivialBipartitions();
+  bipL2->sortByPartitionSize();
+
+
+  for (i = 0; i < bipL1->getNumberOfBipartitions(); i++)
+  {
+    size1.push_back(bipL1->getPartitionSize(i));
+  }
+  for (i = 0; i < bipL2->getNumberOfBipartitions(); i++)
+  {
+    size2.push_back(bipL2->getPartitionSize(i));
+  }
+
+  for (i = 0; i < bipL2->getNumberOfBipartitions(); i++)
+  {
+    bipOK2.push_back(false);
+  }
+
+  /* main loops */
+
+  for (i = 0; i < bipL1->getNumberOfBipartitions(); i++)
+  {
+    for (j = 0; j < bipL2->getNumberOfBipartitions(); j++)
+    {
+      if (bipOK2[j])
+        continue;
+      if (size1[i] == size2[j] && BipartitionTools::areIdentical(*bipL1, i, *bipL2, j))
+      {
+        bipOK2[j] = true;
+        break;
+      }
+    }
+    if (j == bipL2->getNumberOfBipartitions())
+      missing2++;
+  }
+
+  missing1 = static_cast<int>(bipL2->getNumberOfBipartitions()) - static_cast<int>(bipL1->getNumberOfBipartitions()) + missing2;
+
+  if (missing_in_tr1)
+    *missing_in_tr1 = missing1;
+  if (missing_in_tr2)
+    *missing_in_tr2 = missing2;
+  return missing1 + missing2;
+}
+
+/******************************************************************************/
+
+BipartitionList* TreeTools::bipartitionOccurrences(const vector<Tree*>& vecTr, vector<size_t>& bipScore)
+{
+  vector<BipartitionList*> vecBipL;
+  BipartitionList* mergedBipL;
+  vector<size_t> bipSize;
+  size_t nbBip;
+
+  /*  build and merge bipartitions */
+  for (size_t i = 0; i < vecTr.size(); i++)
+  {
+    vecBipL.push_back(new BipartitionList(*vecTr[i]));
+  }
+  mergedBipL = BipartitionTools::mergeBipartitionLists(vecBipL);
+  for (size_t i = 0; i < vecTr.size(); i++)
+  {
+    delete vecBipL[i];
+  }
+
+  mergedBipL->removeTrivialBipartitions();
+  nbBip = mergedBipL->getNumberOfBipartitions();
+  bipScore.clear();
+  for (size_t i = 0; i < nbBip; i++)
+  {
+    bipSize.push_back(mergedBipL->getPartitionSize(i));
+    bipScore.push_back(1);
+  }
+
+  /* compare bipartitions */
+  for (size_t i = nbBip; i > 0; i--)
+  {
+    if (bipScore[i - 1] == 0)
+      continue;
+    for (size_t j = i - 1; j > 0; j--)
+    {
+      if (bipScore[j - 1] && bipSize[i - 1] == bipSize[j - 1] && mergedBipL->areIdentical(i - 1, j - 1))
+      {
+        bipScore[i - 1]++;
+        bipScore[j - 1] = 0;
+      }
+    }
+  }
+
+  /* keep only distinct bipartitions */
+  for (size_t i = nbBip; i > 0; i--)
+  {
+    if (bipScore[i - 1] == 0)
+    {
+      bipScore.erase(bipScore.begin() + i - 1);
+      mergedBipL->deleteBipartition(i - 1);
+    }
+  }
+
+  /* add terminal branches */
+  mergedBipL->addTrivialBipartitions(false);
+  for (size_t i = 0; i < mergedBipL->getNumberOfElements(); i++)
+  {
+    bipScore.push_back(vecTr.size());
+  }
+
+  return mergedBipL;
+}
+
+/******************************************************************************/
+
+TreeTemplate<Node>* TreeTools::thresholdConsensus(const vector<Tree*>& vecTr, double threshold, bool checkNames) throw (Exception)
+{
+  vector<size_t> bipScore;
+  vector<string> tr0leaves;
+  BipartitionList* bipL;
+  double score;
+
+  if (vecTr.size() == 0)
+    throw Exception("TreeTools::thresholdConsensus. Empty vector passed");
+
+  /* check names */
+  if (checkNames)
+  {
+    tr0leaves = vecTr[0]->getLeavesNames();
+    for (size_t i = 1; i < vecTr.size(); i++)
+    {
+      if (!VectorTools::haveSameElements(vecTr[i]->getLeavesNames(), tr0leaves))
+        throw Exception("TreeTools::thresholdConsensus. Distinct leaf sets between trees");
+    }
+  }
+
+  bipL = bipartitionOccurrences(vecTr, bipScore);
+
+  for (size_t i = bipL->getNumberOfBipartitions(); i > 0; i--)
+  {
+    if (bipL->getPartitionSize(i - 1) == 1)
+      continue;
+    score = static_cast<int>(bipScore[i - 1]) / static_cast<double>(vecTr.size());
+    if (score <= threshold && score != 1.)
+    {
+      bipL->deleteBipartition(i - 1);
+      continue;
+    }
+    if (score > 0.5)
+      continue;
+    for (size_t j = bipL->getNumberOfBipartitions(); j > i; j--)
+    {
+      if (!bipL->areCompatible(i - 1, j - 1))
+      {
+        bipL->deleteBipartition(i - 1);
+        break;
+      }
+    }
+  }
+
+  TreeTemplate<Node>* tr = bipL->toTree();
+  delete bipL;
+  return tr;
+}
+
+/******************************************************************************/
+
+TreeTemplate<Node>* TreeTools::fullyResolvedConsensus(const vector<Tree*>& vecTr, bool checkNames)
+{
+  return thresholdConsensus(vecTr, 0., checkNames);
+}
+
+/******************************************************************************/
+
+TreeTemplate<Node>* TreeTools::majorityConsensus(const vector<Tree*>& vecTr, bool checkNames)
+{
+  return thresholdConsensus(vecTr, 0.5, checkNames);
+}
+
+/******************************************************************************/
+
+TreeTemplate<Node>* TreeTools::strictConsensus(const vector<Tree*>& vecTr, bool checkNames)
+{
+  return thresholdConsensus(vecTr, 1., checkNames);
+}
+
+/******************************************************************************/
+
+Tree* TreeTools::MRP(const vector<Tree*>& vecTr)
+{
+  // matrix representation
+  VectorSiteContainer* sites = TreeTools::MRPEncode(vecTr);
+
+  // starting bioNJ tree
+  const DNA* alphabet = dynamic_cast<const DNA*>(sites->getAlphabet());
+  JCnuc* jc = new JCnuc(alphabet);
+  ConstantDistribution* constRate = new ConstantDistribution(1.);
+  DistanceEstimation distFunc(jc, constRate, sites, 0, true);
+  BioNJ bionjTreeBuilder(false, false);
+  bionjTreeBuilder.setDistanceMatrix(*(distFunc.getMatrix()));
+  bionjTreeBuilder.computeTree();
+  if (ApplicationTools::message)
+    ApplicationTools::message->endLine();
+  TreeTemplate<Node>* startTree = new TreeTemplate<Node>(*bionjTreeBuilder.getTree());
+
+  // MP optimization
+  DRTreeParsimonyScore* MPScore = new DRTreeParsimonyScore(*startTree, *sites, false);
+  MPScore = OptimizationTools::optimizeTreeNNI(MPScore, 0);
+  delete startTree;
+  Tree* retTree = new TreeTemplate<Node>(MPScore->getTree());
+  delete MPScore;
+
+  return retTree;
+}
+
+/******************************************************************************/
+
+void TreeTools::computeBootstrapValues(Tree& tree, const vector<Tree*>& vecTr, bool verbose)
+{
+  vector<int> index;
+  BipartitionList bpTree(tree, true, &index);
+  vector<size_t> occurences;
+  BipartitionList* bpList = bipartitionOccurrences(vecTr, occurences);
+
+  vector< Number<double> > bootstrapValues(bpTree.getNumberOfBipartitions());
+
+  for (size_t i = 0; i < bpTree.getNumberOfBipartitions(); i++)
+  {
+    if (verbose)
+      ApplicationTools::displayGauge(i, bpTree.getNumberOfBipartitions() - 1, '=');
+    for (size_t j = 0; j < bpList->getNumberOfBipartitions(); j++)
+    {
+      if (BipartitionTools::areIdentical(bpTree, i, *bpList, j))
+      {
+        bootstrapValues[i] = (double) occurences[j] * 100. / (double) vecTr.size();
+        break;
+      }
+    }
+  }
+
+  for (size_t i = 0; i < index.size(); i++)
+  {
+    if (!tree.isLeaf(index[i]))
+      tree.setBranchProperty(index[i], BOOTSTRAP, bootstrapValues[i]);
+  }
+
+  delete bpList;
+}
+
+/******************************************************************************/
+
+vector<int> TreeTools::getAncestors(const Tree& tree, int nodeId) throw (NodeNotFoundException)
+{
+  vector<int> ids;
+  int currentId = nodeId;
+  while (tree.hasFather(currentId))
+  {
+    currentId = tree.getFatherId(currentId);
+    ids.push_back(currentId);
+  }
+  return ids;
+}
+
+/******************************************************************************/
+
+int TreeTools::getLastCommonAncestor(const Tree& tree, const vector<int>& nodeIds) throw (NodeNotFoundException, Exception)
+{
+  if (nodeIds.size() == 0)
+    throw Exception("TreeTools::getLastCommonAncestor(). You must provide at least one node id.");
+  vector< vector<int> > ancestors(nodeIds.size());
+  for (size_t i = 0; i < nodeIds.size(); i++)
+  {
+    ancestors[i] = getAncestors(tree, nodeIds[i]);
+    ancestors[i].insert(ancestors[i].begin(), nodeIds[i]);
+  }
+  int lca = tree.getRootId();
+  size_t count = 1;
+  for ( ; ; )
+  {
+    if (ancestors[0].size() <= count)
+      return lca;
+    int current = ancestors[0][ancestors[0].size() - count - 1];
+    for (size_t i = 1; i < nodeIds.size(); i++)
+    {
+      if (ancestors[i].size() <= count)
+        return lca;
+      if (ancestors[i][ancestors[i].size() - count - 1] != current)
+        return lca;
+    }
+    lca = current;
+    count++;
+  }
+  // This line is never reached!
+  return lca;
+}
+
+/******************************************************************************/
+
+void TreeTools::constrainedMidPointRooting(Tree& tree)
+{
+  // is the tree rooted?
+  if (!tree.isRooted())
+    throw Exception("The tree has to be rooted on the branch of interest to determine the midpoint position of the root");
+  // is the tree multifurcating?
+  if (tree.isMultifurcating())
+    throw Exception("The tree is multifurcated, which is not allowed.");
+
+  double length = 0.;
+  vector<int> sonsIds = tree.getSonsId(tree.getRootId());
+  // Length of the branch containing the root:
+  length = tree.getDistanceToFather(sonsIds.at(0)) + tree.getDistanceToFather(sonsIds.at(1));
+  // The fraction of the original branch allowing to split its length and to place the root:
+  double x = bestRootPosition_(tree, sonsIds.at(0), sonsIds.at(1), length);
+  // The new branch lengths are then computed:
+  tree.setDistanceToFather(sonsIds.at(0), length * x);
+  tree.setDistanceToFather(sonsIds.at(1), length * (1 - x));
+}
+
+/******************************************************************************/
+
+double TreeTools::bestRootPosition_(Tree& tree, int nodeId1, int nodeId2, double length)
+{
+  double x;
+  Moments_ m1, m2;
+  double A, B; // C;
+  // The variance is expressed as a degree 2 polynomial : variance(x) = A * x * x + B * x + C
+  // The fraction x is then obtained by differentiating this equation.
+  m1 = statFromNode_(tree, nodeId1);
+  m2 = statFromNode_(tree, nodeId2);
+  A = 4 * m1.N * (m2.N * length) * length;
+  B = 4 * length * (m2.N * m1.sum - m1.N * m2.sum - length * m1.N * m2.N);
+//   C = (m1.N + m2.N) * (m1.squaredSum + m2.squaredSum) + m1.N * length * m2.N * length +
+//     2 * m1.N * length * m2.sum - 2 * m2.N * length * m1.sum -
+//     (m1.sum + m2.sum) * (m1.sum + m2.sum);
+
+  if (A < 1e-20)
+    x = 0.5;
+  else
+    x = -B / (2 * A);
+  if (x < 0)
+    x = 0;
+  else if (x > 1)
+    x = 1;
+
+  return x;
+}
+
+/******************************************************************************/
+
+TreeTools::Moments_ TreeTools::statFromNode_(Tree& tree, int rootId)
+{
+  // This function recursively calculates both the sum of the branch lengths and the sum of the squared branch lengths down the node whose ID is rootId.
+  // If below a particular node there are N leaves, the branch between this node and its father is taken into account N times in the calculation.
+  Moments_ m;
+  static Moments_ mtmp;
+
+  if (tree.isLeaf(rootId))
+  {
+    m.N = 1;
+    m.sum = 0.;
+    m.squaredSum = 0.;
+  }
+  else
+  {
+    vector<int> sonsId = tree.getSonsId(rootId);
+    for (size_t i = 0; i < sonsId.size(); i++)
+    {
+      mtmp = statFromNode_(tree, sonsId.at(i));
+      double bLength = tree.getDistanceToFather(sonsId.at(i));
+      m.N += mtmp.N;
+      m.sum += mtmp.sum + bLength * mtmp.N;
+      m.squaredSum += mtmp.squaredSum + 2 * bLength * mtmp.sum + mtmp.N * bLength * bLength;
+    }
+  }
+
+  return m;
+}
+
diff --git a/src/Bpp/Phyl/TreeTools.h b/src/Bpp/Phyl/TreeTools.h
new file mode 100755
index 0000000..ae1ae0c
--- /dev/null
+++ b/src/Bpp/Phyl/TreeTools.h
@@ -0,0 +1,715 @@
+//
+// File: TreeTools.h
+// Created by:  Julien Dutheil
+// Created on: Wed Aug  6 13:45:28 2003
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for phylogenetic data analysis.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#ifndef _TREETOOLS_H_
+#define _TREETOOLS_H_
+
+#include "TreeExceptions.h"
+#include "Node.h"
+#include "Tree.h"
+#include "BipartitionList.h"
+
+#include <Bpp/Exceptions.h>
+#include <Bpp/Numeric/VectorTools.h>
+
+// From SeqLib:
+#include <Bpp/Seq/Container/VectorSiteContainer.h>
+#include <Bpp/Seq/DistanceMatrix.h>
+
+namespace bpp
+{
+
+/**
+ * @brief Generic utilitary methods dealing with trees.
+ *
+ * These methods work with all Tree object.
+ * However, depending on the tree implementation, they may not be the most efficient.
+ *
+ * @see TreeTemplateTools
+ */
+class TreeTools
+{
+  public:
+    TreeTools() {}
+    virtual ~TreeTools() {}
+  
+  public:
+
+    /**
+     * @name Retrieve topology information
+     *
+     * @{
+     */
+    
+    /**
+     * @brief Retrieve all leaves from a subtree.
+     *
+     * @param tree The tree
+     * @param nodeId The id of node defining the subtree.
+     * @return A vector with the ids of all leaves in the subtree.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static std::vector<int> getLeavesId(const Tree& tree, int nodeId) throw (NodeNotFoundException);
+
+    /**
+     * @brief Retrieve all leaves from a subtree.
+     *
+     * @param tree The tree
+     * @param nodeId The id of node defining the subtree.
+     * @param leaves A vector with the ids of all leaves in the subtree.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static void getLeavesId(const Tree& tree, int nodeId, std::vector<int>& leaves) throw (NodeNotFoundException);
+ 
+    /**
+     * @brief Count the number of leaves from a subtree.
+     *
+     * @param tree The tree
+     * @param nodeId The id of node defining the subtree.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static size_t getNumberOfLeaves(const Tree& tree, int nodeId) throw (NodeNotFoundException);
+ 
+    /**
+     * @brief Get the id of a leaf given its name in a subtree.
+     *
+     * @param tree The tree
+     * @param nodeId The id of node defining the subtree.
+     * @param name The name of the node.
+     * @return The id of the node.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static int getLeafId(const Tree& tree, int nodeId, const std::string& name) throw (NodeNotFoundException);
+
+    /**
+     * @brief Get the id of a leaf given its name in a subtree.
+     *
+     * @param tree The tree
+     * @param nodeId The id of node defining the subtree.
+     * @param name The name of the node.
+     * @param id The id of the node.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static void searchLeaf(const Tree& tree, int nodeId, const std::string& name, int*& id) throw (NodeNotFoundException);
+
+    /**
+     * @brief Get a vector of ancestor nodes between to nodes.
+     *
+     * @param tree The tree to use.
+     * @param nodeId1 Id of first node.
+     * @param nodeId2 Id of second node.
+     * @param includeAncestor Tell if the common ancestor must be included in the vector.
+     * @return A vector of ancestor nodes ids.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static std::vector<int> getPathBetweenAnyTwoNodes(const Tree& tree, int nodeId1, int nodeId2, bool includeAncestor = true) throw (NodeNotFoundException);
+ 
+    /**
+     * @brief Get a list of all ids of parents nodes, from the current node (not included) to the root of the tree.
+     *
+     * @param tree The tree to use.
+     * @param nodeId The id of node defining the subtree.
+     * @return The list of ancestors ids.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static std::vector<int> getAncestors(const Tree& tree, int nodeId) throw (NodeNotFoundException);
+
+    /**
+     * @brief Get the id of the last common ancestors of all specified nodes.
+     *
+     * Nodes id need not correspond to leaves.
+     *
+     * @author Simon Carrignon
+     * @param tree The tree to use.
+     * @param nodeIds The ids of the input nodes.
+     * @throw NodeNotFoundException If at least of of input node is not found.
+     */
+    static int getLastCommonAncestor(const Tree& tree, const std::vector<int>& nodeIds) throw (NodeNotFoundException, Exception);
+
+    /**
+     * @brief Get the depth of the subtree defined by node 'node', i.e. the maximum
+     * number of sons 'generations'.
+     *
+     * ex:
+     * @code
+     *    +----------A
+     *    |
+     * ---+ N1     +-------B
+     *    |        |
+     *    +--------+ N2
+     *             |
+     *             +------C
+     * @endcode
+     * Depth of node 'N1' id 2, depth of node 'N2' is 1, depth of leaves is 0.
+     *
+     * @param tree The tree.
+     * @param nodeId The id of node defining the subtree.
+     * @return The depth of the subtree.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static size_t getDepth(const Tree& tree, int nodeId) throw (NodeNotFoundException);
+
+    /**
+     * @brief Get the depths for all nodes of the subtree defined by node 'node', i.e. the maximum
+     * number of sons 'generations'.
+     *
+     * ex:
+     * @verbatim
+     *    +----------A
+     *    |
+     * ---+ N1     +-------B
+     *    |        |
+     *    +--------+ N2
+     *             |
+     *             +------C
+     * @endverbatim
+     * Depth of node 'N1' id 2, depth of node 'N2' is 1, depth of leaves is 0.
+     *
+     * @param tree The tree.
+     * @param nodeId The id of node defining the subtree.
+     * @param depths The map that will contain all the depths of the nodes, with node ids as keys.
+     * @return The depth of the subtree.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static size_t getDepths(const Tree& tree, int nodeId, std::map<int, size_t>& depths) throw (NodeNotFoundException);
+
+    /**
+     * @brief Get the height of the subtree defined by node 'node', i.e. the maximum
+     * distance between leaves and the root of the subtree.
+     *
+     * The distance do not include the branch length of the subtree root node.
+     * The height of a leaf is hence 0.
+     *
+     * @param tree The tree.
+     * @param nodeId The id of node defining the subtree.
+     * @return The height of the subtree.
+     * @throw NodeNotFoundException If the node is not found.
+     * @throw NodeException If a branch length is lacking.
+     */ 
+    static double getHeight(const Tree& tree, int nodeId) throw (NodeNotFoundException,NodeException);
+
+    /**
+     * @brief Get the heights of all nodes within a subtree defined by node 'node', i.e. the maximum
+     * distance between leaves and the root of the subtree.
+     *
+     * The height of a leaf is 0.
+     *
+     * @param tree The tree.
+     * @param nodeId The id of node defining the subtree.
+     * @param heights The map that will contain all the heights of the nodes, with node ids as keys.
+     * @return The height of the subtree.
+     * @throw NodeNotFoundException If the node is not found.
+     * @throw NodeException If a branch length is lacking.
+     */ 
+    static double getHeights(const Tree& tree, int nodeId, std::map<int, double>& heights) throw (NodeNotFoundException,NodeException);
+
+    /** @} */
+
+    /**
+     * @name Act on branch lengths.
+     *
+     * @{
+     */
+    
+     /**
+     * @brief Get all the branch lengths of a subtree.
+     *
+     * @param tree The tree.
+     * @param nodeId The node defining the subtree.
+     * @return A vector with all branch lengths.
+     * @throw NodeNotFoundException If the node is not found.
+     * @throw NodeException If a branch length is lacking.
+     */
+    static Vdouble getBranchLengths(const Tree& tree, int nodeId) throw (NodeNotFoundException,NodeException);
+    
+    /**
+     * @brief Get the total length (sum of all branch lengths) of a subtree.
+     *
+     * @param tree The tree.
+     * @param nodeId The node defining the subtree.
+     * @param includeAncestor Tell if the branch length of the most ancient node should be included in the counting.
+     * (this should be set to false if this node is the root of the tree for instance).
+     * @return The total length of the subtree.
+     * @throw NodeNotFoundException If the node is not found.
+     * @throw NodeException If a branch length is lacking.
+     */
+    static double getTotalLength(const Tree& tree, int nodeId, bool includeAncestor = true) throw (NodeNotFoundException,NodeException);
+
+    /**
+     * @brief Set all the branch lengths of a subtree.
+     *
+     * @param tree The tree.
+     * @param nodeId The node defining the subtree.
+     * @param brLen The branch length to apply.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static void setBranchLengths(Tree& tree, int nodeId, double brLen) throw (NodeNotFoundException);
+          
+    /**
+     * @brief Give a length to branches that don't have one in a subtree.
+     *
+     * @param tree The tree.
+     * @param nodeId The node defining the subtree.
+     * @param brLen The branch length to apply.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static void setVoidBranchLengths(Tree& tree, int nodeId, double brLen) throw (NodeNotFoundException);
+        
+    /**
+     * @brief Scale a given tree.
+     *
+     * Multiply all branch lengths by a given factor.
+     *
+     * @param tree The tree.
+     * @param nodeId The node defining the subtree.
+     * @param factor The factor to multiply all branch lengths with.
+     * @throw NodeNotFoundException If the node is not found.
+     * @throw NodeException If a branch length is lacking.
+     */
+    static void scaleTree(Tree& tree, int nodeId, double factor) throw (NodeNotFoundException,NodeException);
+
+    /**
+     * @brief Grafen's method to initialize branch lengths.
+     *
+     * Each height of the node (total distance from the leaves) is set equal to the number of
+     * leaf nodes for the corresponding subtrees - 1 for inner nodes, 0 for leaves.
+     * 
+     * If the tree already has branch lengths, they will be ignored.
+     * 
+     * Reference:
+     * Grafen A. The phylogenetic regression. Philos Trans R Soc Lond B Biol Sci. 1989; 326(1233):119-57
+     * 
+     * @param tree The tree.
+     */ 
+    static void initBranchLengthsGrafen(Tree& tree);
+    
+    /**
+     * @brief Compute branch lengths using Grafen's method.
+     *
+     * The 'height' of each node is devided by the total height of the tree, and the ratio is raised at power 'rho'.
+     * A value of rho=0 hence returns a star tree.
+     *
+     * Reference:
+     * Grafen A. The phylogenetic regression. Philos Trans R Soc Lond B Biol Sci. 1989; 326(1233):119-57
+     * 
+     * @param tree The tree to use.
+     * @param power The rho parameter.
+     * @param init Tell if the height must be initialized by calling the initBranchLengthsGrafen() method.
+     *             Otherwise use branch lengths.
+     * @throw NodeException If init=false and one branch length is lacking.
+     */
+    static void computeBranchLengthsGrafen(Tree& tree, double power = 1, bool init = true) throw (NodeException);
+   
+  private:
+    static size_t initBranchLengthsGrafen(Tree& tree, int nodeId) throw (NodeNotFoundException);
+    static void computeBranchLengthsGrafen(Tree& tree, int nodeId, double power, double total, double& height, double& heightRaised) throw (NodeNotFoundException,NodeException);
+
+  public:
+    /**
+     * @brief Modify a tree's branch lengths to make a clock tree, by rebalancing branch lengths.
+     *
+     * The height of each node is set to the mean height of all son nodes.
+     * This may however lead to negative branch lengths, since the mean heigth
+     * may be inferior to one of the son heights, due to short branch lengths.
+     * If the 'noneg' is set to yes, the mean height is checked against all son
+     * heights. If it is inferior to one of the son heights, the maximum son
+     * height is used instead. This results in a multifurcation.
+     * 
+     * This method is recursive and will be applied on all sons nodes.
+     * 
+     * @param tree The tree to use.
+     * @param nodeId The node defining the subtree.
+     * @param noneg Tell if the correction for non negative branch lengths must be used.
+     * @return The modified height of the node.
+     * @throw NodeNotFoundException If the node is not found.
+     * @throw NodeException If one branch length is lacking.
+     */
+    static double convertToClockTree(Tree& tree, int nodeId, bool noneg = false);
+    
+    /**
+     * @brief Modify a tree's branch lengths to make a clock tree, by rescaling subtrees.
+     *
+     * The height of each node is set to the mean height of all son nodes.
+     * All branch lengths of the corresponding subtrees are updated proportionally.
+     * This algorithm is smaller than the convertToClockTree method, but may be more accurate.
+     * 
+     * This method is recursive and will be applied on all sons nodes.
+     * 
+     * @param tree The tree to use.
+     * @param nodeId The node defining the subtree.
+     * @return The modified height of the node.
+     * @throw NodeNotFoundException If the node is not found.
+     * @throw NodeException If one branch length is lacking.
+     */
+    static double convertToClockTree2(Tree& tree, int nodeId);
+ 
+    /**
+     * @brief Get the total distance between two nodes.
+     *
+     * Sum all branch lengths between two nodes.
+     *
+     * @param tree The tree to consider.
+     * @param nodeId1 First node id.
+     * @param nodeId2 Second node id.
+     * @return The sum of all branch lengths between the two nodes.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static double getDistanceBetweenAnyTwoNodes(const Tree& tree, int nodeId1, int nodeId2);
+    
+    /**
+     * @brief Compute a distance matrix from a tree.
+     *
+     * Compute all distances between each leaves and store them in a matrix.
+     * A new DistanceMatrix object is created, and a pointer toward it is returned.
+     * The destruction of this matrix is left up to the user.
+     *
+     * @see getDistanceBetweenAnyTwoNodes
+     *
+     * @param tree The tree to use.
+     * @return The distance matrix computed from tree.
+     */
+    static DistanceMatrix* getDistanceMatrix(const Tree& tree);
+
+    /**
+     * @brief (Re)root the tree using the midpoint method.
+     *
+     * This methods compute the pairwise distance matrix from the tree and get the maximum distance.
+     * The root is then set on the branch located at half this distance.
+     *
+     * @param tree The tree to (re)root.
+     */
+    static void midpointRooting(Tree& tree);
+    /** @} */
+
+
+    /**
+     * @name Conversion tools.
+     *
+     * Convert to Newick standard tree description.
+     * The description is for a node, and hence is to be surrounded with
+     * parenthesis. ex: (A:0.001, (B:0.001, C:0.02)90:0.005)50:0.0005
+     *
+     * @{
+     */
+   
+    /**
+     * @brief Get the parenthesis description of a subtree.
+     *
+     * @param tree The tree
+     * @param nodeId The id of node defining the subtree.
+     * @param writeId Tells if node ids must be printed.
+     *                This will overwrite bootstrap values if there are ones.
+     *                Leaves id will be added to the leave names, separated by a '_' character.
+     * @return A string in the parenthesis format.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static std::string nodeToParenthesis(const Tree& tree, int nodeId, bool writeId = false) throw (NodeNotFoundException);
+
+    /**
+     * @brief Get the parenthesis description of a subtree.
+     *
+     * @param tree The tree
+     * @param nodeId The node defining the subtree.
+     * @param bootstrap Tell is bootstrap values must be writen.
+     * If so, the content of the property with name TreeTools::BOOTSTRAP will be written as bootstrap value.
+     * The property should be a Number<double> object.
+     * Otherwise, the content of the property with name 'propertyName' will be written.
+     * In this later case, the property should be a String object.
+     * @param propertyName The name of the property to use. Only used if bootstrap = false.
+     * @return A string in the parenthesis format.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static std::string nodeToParenthesis(const Tree& tree, int nodeId, bool bootstrap, const std::string& propertyName) throw (NodeNotFoundException);
+
+    /**
+     * @brief Get the parenthesis description of a tree.
+     *
+     * @param tree The tree to convert.
+     * @param writeId Tells if node ids must be printed.
+     *                This will overwrite bootstrap values if there are ones.
+     *                Leaves id will be added to the leave names, separated by a '_' character.
+     * @return A string in the parenthesis format.
+     */
+    static std::string treeToParenthesis(const Tree& tree, bool writeId = false);
+    
+    /**
+     * @brief Get the parenthesis description of a tree.
+     *
+     * @param tree The tree to convert.
+     * @param bootstrap Tell is bootstrap values must be writen.
+     * If so, the content of the property with name TreeTools::BOOTSTRAP will be written as bootstrap value.
+     * The property should be a Number<double> object.
+     * Otherwise, the content of the property with name 'propertyName' will be written.
+     * In this later case, the property should be a String object.
+     * @param propertyName The name of the property to use. Only used if bootstrap = false.
+     * @return A string in the parenthesis format.
+     */
+    static std::string treeToParenthesis(const Tree& tree, bool bootstrap, const std::string& propertyName);
+    
+    /** @} */
+
+    /**
+     * @name Deal with identifiers
+     *
+     * @{
+     */
+
+    /**
+     * @brief Retrieve all nodes ids nodes from a subtree.
+     *
+     * @param tree The tree
+     * @param nodeId The id of the node that defines the subtree.
+     * @return A vector of ids of each node in the subtree.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static std::vector<int> getNodesId(const Tree& tree, int nodeId) throw (NodeNotFoundException);
+
+    /**
+     * @brief Retrieve all nodes ids from a subtree.
+     *
+     * @param tree The tree
+     * @param nodeId The id of the node that defines the subtree.
+     * @param nodes A vector of ids of each node in the subtree.
+     * @throw NodeNotFoundException If the node is not found.
+     */
+    static void getNodesId(const Tree& tree, int nodeId, std::vector<int>& nodes) throw (NodeNotFoundException);
+
+    /**
+     * @brief Get the maximum identifier used in a (sub)tree.
+     *
+     * This is a recursive method.
+     *
+     * @param tree The tree to check.
+     * @param id The identifier of the subtree from which the recursion will be performed.
+     * Use id=tree.getRootId() to search for the whole tree.
+     * @return The identifier number with maximum value.
+     */
+    static int getMaxId(const Tree& tree, int id);
+
+    /**
+     * @brief Get the minimum positive non-used identifier in a (sub)tree.
+     *
+     * This method uses the recursive method getNodesId, and then sort the ids.
+     *
+     * @param tree The tree to check.
+     * @param id The identifier of the subtree from which the recursion will be performed.
+     * Use id=tree.getRootId() to search for the whole tree.
+     * @return A non-used identifier number.
+     */
+    static int getMPNUId(const Tree& tree, int id);
+
+    /**
+     * @brief Check if the ids are uniques.
+     *
+     * @param tree The tree to check.
+     * @param throwException If set to true, the function throws qn exception if a duplicated is found.
+     * @return true if the tree has uniqe ids.
+     */
+    static bool checkIds(const Tree& tree, bool throwException) throw (Exception);
+
+    /** @} */
+
+
+    /**
+     * @name Topology methods
+     *
+     * @{
+     */
+
+    /**
+     * @brief Creates a sequence data set corresponding to the Matrix Representation of the input trees
+     *
+     * @author Nicolas Galtier
+     * Trees can have distinct sets of elements - missing data will be represented as 'N'.
+     * The output alignment (DNA sequences including only A, C and N)) is ready for maximum parsimony analysis
+     * according to the MRP supertree method.
+     */
+    static VectorSiteContainer* MRPEncode(const std::vector<Tree*>& vecTr);
+
+    /**
+     * @brief Tells whether two trees have the same unrooted topology
+     *
+     * @author Nicolas Galtier
+     * Note that the location of the root, if any, is ignored.
+     */
+    static bool haveSameTopology(const Tree& tr1, const Tree& tr2);
+
+    /**
+     * @brief Calculates the Robinson-Foulds topological distance between two trees
+     *
+     * The two trees must share a common set of leaves (checked if checkNames is true)
+     * Three numbers are calculated:
+     *
+     * @author Nicolas Galtier
+     * @param tr1 First input tree.
+     * @param tr2 Second input tree.
+     * @param missing_in_tr2 Output as the number of bipartitions occurring in the first tree but not the second
+     * @param missing_in_tr1 Output as the number of bipartitions occurring in the second tree but not the first
+     * @param checkNames Tell whether we should check the trees first.
+     * @return Robinson-Foulds distance = *missing_in_tr1 + *missing_in_tr2
+     * @throw Exception If checkNames is set to true and trees do not share the same leaves names.
+     */
+    static int robinsonFouldsDistance(const Tree& tr1, const Tree& tr2, bool checkNames = true, int* missing_in_tr2 = NULL, int* missing_in_tr1 = NULL) throw (Exception);
+
+    /**
+     * @brief Counts the total number of occurrences of every bipartition from the input trees
+     *
+     * Returns the list of distinct bipartitions found at least once in the set of input trees,
+     * and writes the number of occurrence of each of these bipartitions in vector bipScore.
+     *
+     * @author Nicolas Galtier
+     * @param vecTr Vector of input trees (must share a common set of leaves - not checked in this function)
+     * @param bipScore Output as the numbers of occurrences of the returned distinct bipartitions
+     * @return A BipartitionList object including only distinct bipartitions
+     */
+    static BipartitionList* bipartitionOccurrences(const std::vector<Tree*>& vecTr, std::vector<size_t>& bipScore);
+
+    /**
+     * @brief General greedy consensus tree method
+     *
+     * Calculates the consensus tree of a set of trees defined from the number of occurrences
+     * of bipartitions. Bipartitions are considered in decreasing score order.
+     * A bipartition is included if it is compatible with all previously included bipartitions, and if its score
+     * is higher than a threshold.
+     *
+     * @author Nicolas Galtier
+     * @param vecTr Vector of input trees (must share a common set of leaves - checked if checkNames is true)
+     * @param threshold Minimal acceptable score =number of occurrence of a bipartition/number of trees (0.<=threshold<=1.)
+     * @param checkNames Tell whether we should check the trees first.
+     */
+    static TreeTemplate<Node>* thresholdConsensus(const std::vector<Tree*>& vecTr, double threshold, bool checkNames = true) throw (Exception);
+
+    /**
+     * @brief Fully-resolved greedy consensus tree method
+     *
+     * Calls thresholdConsensus with threshold=0, i.e. no constraint on the number of occurrence of bipartitions.
+     * The resulting tree is fully resolved.
+     *
+     * @author Nicolas Galtier
+     * @param vecTr Vector of input trees (must share a common set of leaves - checked if checkNames is true)
+     * @param checkNames Tell whether we should check the trees first.
+     */
+    static TreeTemplate<Node>* fullyResolvedConsensus(const std::vector<Tree*>& vecTr, bool checkNames = true);
+
+    /**
+     * @brief Majority consensus tree method
+     *
+     * Calls thresholdConsensus with threshold=0.5: internal branches present in a majority of trees are kept.
+     *
+     * @author Nicolas Galtier
+     * @param vecTr Vector of input trees (must share a common set of leaves - checked if checkNames is true)
+     * @param checkNames Tell whether we should check the trees first.
+     */
+    static TreeTemplate<Node>* majorityConsensus(const std::vector<Tree*>& vecTr, bool checkNames = true);
+
+    /**
+     * @brief Strict consensus tree method
+     *
+     * Calls thresholdConsensus with threshold=1: only internal branches present in all trees are kept.
+     *
+     * @author Nicolas Galtier
+     * @param vecTr Vector of input trees (must share a common set of leaves - checked if checkNames is true)
+     * @param checkNames Tell whether we should check the trees first.
+     */
+    static TreeTemplate<Node>* strictConsensus(const std::vector<Tree*>& vecTr, bool checkNames = true);
+
+    /** @} */
+
+    /**
+     * @brief Matrix Representation Parsimony supertree method
+     *
+     * This implementation of the MRP method takes a BIONJ tree (Jukes-Cantor distances)
+     * as the starting tree and optimizes the parsimony score using only NNI (in a
+     * PHYML-like way).
+     *
+     * @author Nicolas Galtier
+     * @param vecTr A vector of trees.
+     * @return The MRP super tree.
+     */
+    static Tree* MRP(const std::vector<Tree*>& vecTr);
+
+    /**
+     * @brief Compute bootstrap values.
+     *
+     * @param tree Input tree. the BOOTSTRAP banch property of the tree will be modified if it already exists.
+     * @param vecTr A list of trees to compare to 'tree'.
+     * @param verbose Tell if a progress bar should be displayed.
+     */
+    static void computeBootstrapValues(Tree& tree, const std::vector<Tree*>& vecTr, bool verbose = true);
+	
+    /**
+     * @brief Determine the mid-point position of the root along the branch that already contains the root. Consequently, the topology of the rooted tree remains identical.
+     * 
+     * This code uses two inner functions to compute the mid-point position: statFromNode_ and bestRootPosition_.
+     * This code is inspired by a code performing a similar calculation in Seaview (Guindon et al., 2010, Mol. Biol. Evol. 27(2):221-4).
+     * 
+     * @param tree The rooted tree for which the root has to be moved to its mid-point position, along the branch where it already stands.
+     */    
+    static void constrainedMidPointRooting(Tree& tree);
+	
+    /**
+     * @name Some properties.
+     *
+     * @{
+     */
+     
+    /**
+     * @brief Bootstrap tag.
+     */
+    static const std::string BOOTSTRAP;
+
+  private:
+	  struct Moments_ {
+	    double N;
+	    double sum, squaredSum;
+	    Moments_(): N(0), sum(0), squaredSum(0) {}
+	  };	  
+
+	  static Moments_ statFromNode_(Tree& tree, int rootId);
+	  static double bestRootPosition_(Tree& tree, int nodeId1, int nodeId2, double length);
+
+
+    /** @} */
+
+};
+
+} //end of namespace bpp.
+
+#endif  //_TREETOOLS_H_
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..09f9a3c
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,366 @@
+# CMake script for Bio++ PhylLib
+# Author: Sylvain Gaillard and Julien Dutheil
+# Created: 20/08/2009
+
+# File list
+SET(CPP_FILES
+  Bpp/Phyl/App/PhylogeneticsApplicationTools.cpp
+  Bpp/Phyl/BipartitionList.cpp
+  Bpp/Phyl/BipartitionTools.cpp
+  Bpp/Phyl/Distance/AbstractAgglomerativeDistanceMethod.cpp
+  Bpp/Phyl/Distance/BioNJ.cpp
+  Bpp/Phyl/Distance/DistanceEstimation.cpp
+  Bpp/Phyl/Distance/NeighborJoining.cpp
+  Bpp/Phyl/Distance/PGMA.cpp
+  Bpp/Phyl/Distance/HierarchicalClustering.cpp
+  Bpp/Phyl/Graphics/AbstractDendrogramPlot.cpp
+  Bpp/Phyl/Graphics/AbstractTreeDrawing.cpp
+  Bpp/Phyl/Graphics/CladogramPlot.cpp
+  Bpp/Phyl/Graphics/PhylogramPlot.cpp
+  Bpp/Phyl/Graphics/TreeDrawingDisplayControler.cpp
+  Bpp/Phyl/Graphics/TreeDrawingListener.cpp
+  Bpp/Phyl/Io/IoDistanceMatrixFactory.cpp
+  Bpp/Phyl/Io/IoTreeFactory.cpp
+  Bpp/Phyl/Io/Newick.cpp
+  Bpp/Phyl/Io/NexusIoTree.cpp
+  Bpp/Phyl/Io/Nhx.cpp
+  Bpp/Phyl/Io/PhylipDistanceMatrixFormat.cpp
+  Bpp/Phyl/Io/IoPairedSiteLikelihoods.cpp
+  Bpp/Phyl/Io/IoSubstitutionModelFactory.cpp
+  Bpp/Phyl/Io/BppOSubstitutionModelFormat.cpp
+  Bpp/Phyl/Io/IoFrequenciesSetFactory.cpp
+  Bpp/Phyl/Io/BppOFrequenciesSetFormat.cpp
+  Bpp/Phyl/Io/BppORateDistributionFormat.cpp
+  Bpp/Phyl/Likelihood/AbstractDiscreteRatesAcrossSitesTreeLikelihood.cpp
+  Bpp/Phyl/Likelihood/AbstractHomogeneousTreeLikelihood.cpp
+  Bpp/Phyl/Likelihood/AbstractNonHomogeneousTreeLikelihood.cpp
+  Bpp/Phyl/Likelihood/AbstractTreeLikelihood.cpp
+  Bpp/Phyl/Likelihood/DRASDRTreeLikelihoodData.cpp
+  Bpp/Phyl/Likelihood/DRASRTreeLikelihoodData.cpp
+  Bpp/Phyl/Likelihood/DRHomogeneousMixedTreeLikelihood.cpp
+  Bpp/Phyl/Likelihood/DRHomogeneousTreeLikelihood.cpp
+  Bpp/Phyl/Likelihood/DRNonHomogeneousTreeLikelihood.cpp
+  Bpp/Phyl/Likelihood/DRTreeLikelihoodTools.cpp
+  Bpp/Phyl/Likelihood/MarginalAncestralStateReconstruction.cpp
+  Bpp/Phyl/Likelihood/NNIHomogeneousTreeLikelihood.cpp
+  Bpp/Phyl/Likelihood/PseudoNewtonOptimizer.cpp
+  Bpp/Phyl/Likelihood/RASTools.cpp
+  Bpp/Phyl/Likelihood/RHomogeneousClockTreeLikelihood.cpp
+  Bpp/Phyl/Likelihood/RHomogeneousMixedTreeLikelihood.cpp
+  Bpp/Phyl/Likelihood/RHomogeneousTreeLikelihood.cpp
+  Bpp/Phyl/Likelihood/RNonHomogeneousMixedTreeLikelihood.cpp
+  Bpp/Phyl/Likelihood/RNonHomogeneousTreeLikelihood.cpp
+  Bpp/Phyl/Likelihood/TreeLikelihoodTools.cpp
+  Bpp/Phyl/Likelihood/PairedSiteLikelihoods.cpp
+  Bpp/Phyl/Likelihood/GlobalClockTreeLikelihoodFunctionWrapper.cpp
+  Bpp/Phyl/Mapping/LaplaceSubstitutionCount.cpp
+  Bpp/Phyl/Mapping/OneJumpSubstitutionCount.cpp
+  Bpp/Phyl/Mapping/ProbabilisticSubstitutionMapping.cpp
+  Bpp/Phyl/Mapping/NaiveSubstitutionCount.cpp
+  Bpp/Phyl/Mapping/DecompositionSubstitutionCount.cpp
+  Bpp/Phyl/Mapping/UniformizationSubstitutionCount.cpp
+  Bpp/Phyl/Mapping/WeightedSubstitutionCount.cpp
+  Bpp/Phyl/Mapping/SubstitutionMappingTools.cpp
+  Bpp/Phyl/Model/StateMap.cpp
+  Bpp/Phyl/Model/BinarySubstitutionModel.cpp
+  Bpp/Phyl/Model/AbstractSubstitutionModel.cpp
+  Bpp/Phyl/Model/AbstractBiblioSubstitutionModel.cpp
+  Bpp/Phyl/Model/AbstractBiblioMixedSubstitutionModel.cpp
+  Bpp/Phyl/Model/MarkovModulatedSubstitutionModel.cpp
+  Bpp/Phyl/Model/AbstractMixedSubstitutionModel.cpp
+  Bpp/Phyl/Model/MixtureOfASubstitutionModel.cpp
+  Bpp/Phyl/Model/MixtureOfSubstitutionModels.cpp
+  Bpp/Phyl/Model/RateDistributionFactory.cpp
+  Bpp/Phyl/Model/RE08.cpp
+  Bpp/Phyl/Model/SubstitutionModelFactory.cpp
+  Bpp/Phyl/Model/SubstitutionModelSet.cpp
+  Bpp/Phyl/Model/MixedSubstitutionModelSet.cpp
+  Bpp/Phyl/Model/SubstitutionModelSetTools.cpp
+  Bpp/Phyl/Model/AbstractWordSubstitutionModel.cpp
+  Bpp/Phyl/Model/WordSubstitutionModel.cpp
+  Bpp/Phyl/Model/Nucleotide/F84.cpp
+  Bpp/Phyl/Model/Nucleotide/HKY85.cpp
+  Bpp/Phyl/Model/Nucleotide/JCnuc.cpp
+  Bpp/Phyl/Model/Nucleotide/GTR.cpp
+  Bpp/Phyl/Model/Nucleotide/K80.cpp
+  Bpp/Phyl/Model/Nucleotide/L95.cpp
+  Bpp/Phyl/Model/Nucleotide/RN95.cpp
+  Bpp/Phyl/Model/Nucleotide/RN95s.cpp
+  Bpp/Phyl/Model/Nucleotide/SSR.cpp
+  Bpp/Phyl/Model/Nucleotide/T92.cpp
+  Bpp/Phyl/Model/Nucleotide/TN93.cpp
+  Bpp/Phyl/Model/Nucleotide/gBGC.cpp
+  Bpp/Phyl/Model/Nucleotide/YpR.cpp
+  Bpp/Phyl/Model/Protein/DSO78.cpp
+  Bpp/Phyl/Model/Protein/UserProteinSubstitutionModel.cpp
+  Bpp/Phyl/Model/Protein/JCprot.cpp
+  Bpp/Phyl/Model/Protein/JTT92.cpp
+  Bpp/Phyl/Model/Protein/LG08.cpp
+  Bpp/Phyl/Model/Protein/WAG01.cpp
+  Bpp/Phyl/Model/Protein/LLG08_EHO.cpp
+  Bpp/Phyl/Model/Protein/LLG08_EX2.cpp
+  Bpp/Phyl/Model/Protein/LLG08_EX3.cpp
+  Bpp/Phyl/Model/Protein/LLG08_UL2.cpp
+  Bpp/Phyl/Model/Protein/LLG08_UL3.cpp
+  Bpp/Phyl/Model/Protein/LGL08_CAT.cpp
+  Bpp/Phyl/Model/Protein/Coala.cpp
+  Bpp/Phyl/Model/Protein/CoalaCore.cpp
+  Bpp/Phyl/Model/Codon/GY94.cpp
+  Bpp/Phyl/Model/Codon/MG94.cpp
+  Bpp/Phyl/Model/Codon/TripletSubstitutionModel.cpp
+  Bpp/Phyl/Model/Codon/AbstractCodonSubstitutionModel.cpp
+  Bpp/Phyl/Model/Codon/AbstractCodonFrequenciesSubstitutionModel.cpp
+  Bpp/Phyl/Model/Codon/AbstractCodonPhaseFrequenciesSubstitutionModel.cpp
+  Bpp/Phyl/Model/Codon/AbstractCodonDistanceSubstitutionModel.cpp
+  Bpp/Phyl/Model/Codon/AbstractCodonFitnessSubstitutionModel.cpp
+  Bpp/Phyl/Model/Codon/CodonDistanceSubstitutionModel.cpp
+  Bpp/Phyl/Model/Codon/CodonDistanceFrequenciesSubstitutionModel.cpp
+  Bpp/Phyl/Model/Codon/CodonDistancePhaseFrequenciesSubstitutionModel.cpp
+  Bpp/Phyl/Model/Codon/CodonDistanceFitnessPhaseFrequenciesSubstitutionModel.cpp
+  Bpp/Phyl/Model/Codon/CodonRateSubstitutionModel.cpp
+  Bpp/Phyl/Model/Codon/CodonRateFrequenciesSubstitutionModel.cpp
+  Bpp/Phyl/Model/Codon/YN98.cpp
+  Bpp/Phyl/Model/Codon/YNGKP_M1.cpp
+  Bpp/Phyl/Model/Codon/YNGKP_M2.cpp
+  Bpp/Phyl/Model/Codon/YNGKP_M3.cpp
+  Bpp/Phyl/Model/Codon/YNGKP_M7.cpp
+  Bpp/Phyl/Model/Codon/YNGKP_M8.cpp
+  Bpp/Phyl/Model/FrequenciesSet/FrequenciesSet.cpp
+  Bpp/Phyl/Model/FrequenciesSet/NucleotideFrequenciesSet.cpp
+  Bpp/Phyl/Model/FrequenciesSet/MvaFrequenciesSet.cpp
+  Bpp/Phyl/Model/FrequenciesSet/WordFrequenciesSet.cpp
+  Bpp/Phyl/Model/FrequenciesSet/CodonFrequenciesSet.cpp
+  Bpp/Phyl/NNITopologySearch.cpp
+  Bpp/Phyl/Node.cpp
+  Bpp/Phyl/OptimizationTools.cpp
+  Bpp/Phyl/Parsimony/AbstractTreeParsimonyScore.cpp
+  Bpp/Phyl/Parsimony/DRTreeParsimonyData.cpp
+  Bpp/Phyl/Parsimony/DRTreeParsimonyScore.cpp
+  Bpp/Phyl/PatternTools.cpp
+  Bpp/Phyl/PhyloStatistics.cpp
+  Bpp/Phyl/Simulation/MutationProcess.cpp
+  Bpp/Phyl/Simulation/NonHomogeneousSequenceSimulator.cpp
+  Bpp/Phyl/Simulation/SequenceSimulationTools.cpp
+  Bpp/Phyl/SitePatterns.cpp
+  Bpp/Phyl/TreeExceptions.cpp
+  Bpp/Phyl/TreeTemplateTools.cpp
+  Bpp/Phyl/TreeTools.cpp  
+  )
+SET(H_FILES
+  Bpp/Phyl/AncestralStateReconstruction.h
+  Bpp/Phyl/App/PhylogeneticsApplicationTools.h
+  Bpp/Phyl/BipartitionList.h
+  Bpp/Phyl/BipartitionTools.h
+  Bpp/Phyl/Distance/AbstractAgglomerativeDistanceMethod.h
+  Bpp/Phyl/Distance/DistanceMethod.h
+  Bpp/Phyl/Distance/BioNJ.h
+  Bpp/Phyl/Distance/DistanceEstimation.h
+  Bpp/Phyl/Distance/NeighborJoining.h
+  Bpp/Phyl/Distance/PGMA.h
+  Bpp/Phyl/Distance/HierarchicalClustering.h
+  Bpp/Phyl/Graphics/AbstractDendrogramPlot.h
+  Bpp/Phyl/Graphics/AbstractTreeDrawing.h
+  Bpp/Phyl/Graphics/CladogramPlot.h
+  Bpp/Phyl/Graphics/PhylogramPlot.h
+  Bpp/Phyl/Graphics/TreeDrawingDisplayControler.h
+  Bpp/Phyl/Graphics/TreeDrawing.h
+  Bpp/Phyl/Graphics/TreeDrawingListener.h
+  Bpp/Phyl/Io/IoDistanceMatrixFactory.h
+  Bpp/Phyl/Io/IoDistanceMatrix.h
+  Bpp/Phyl/Io/IoTreeFactory.h
+  Bpp/Phyl/Io/IoTree.h
+  Bpp/Phyl/Io/Newick.h
+  Bpp/Phyl/Io/Nhx.h
+  Bpp/Phyl/Io/NexusIoTree.h
+  Bpp/Phyl/Io/PhylipDistanceMatrixFormat.h
+  Bpp/Phyl/Io/IoPairedSiteLikelihoods.h
+  Bpp/Phyl/Io/IoSubstitutionModel.h
+  Bpp/Phyl/Io/IoSubstitutionModelFactory.h
+  Bpp/Phyl/Io/BppOSubstitutionModelFormat.h
+  Bpp/Phyl/Io/IoFrequenciesSet.h
+  Bpp/Phyl/Io/IoFrequenciesSetFactory.h
+  Bpp/Phyl/Io/BppOFrequenciesSetFormat.h
+  Bpp/Phyl/Io/BppORateDistributionFormat.h
+  Bpp/Phyl/Likelihood/AbstractDiscreteRatesAcrossSitesTreeLikelihood.h
+  Bpp/Phyl/Likelihood/AbstractHomogeneousTreeLikelihood.h
+  Bpp/Phyl/Likelihood/AbstractNonHomogeneousTreeLikelihood.h
+  Bpp/Phyl/Likelihood/AbstractTreeLikelihoodData.h
+  Bpp/Phyl/Likelihood/AbstractTreeLikelihood.h
+  Bpp/Phyl/Likelihood/ClockTreeLikelihood.h
+  Bpp/Phyl/Likelihood/DiscreteRatesAcrossSitesTreeLikelihood.h
+  Bpp/Phyl/Likelihood/DRASDRTreeLikelihoodData.h
+  Bpp/Phyl/Likelihood/DRASRTreeLikelihoodData.h
+  Bpp/Phyl/Likelihood/DRHomogeneousMixedTreeLikelihood.h
+  Bpp/Phyl/Likelihood/DRHomogeneousTreeLikelihood.h
+  Bpp/Phyl/Likelihood/DRNonHomogeneousTreeLikelihood.h
+  Bpp/Phyl/Likelihood/DRTreeLikelihood.h
+  Bpp/Phyl/Likelihood/DRTreeLikelihoodTools.h
+  Bpp/Phyl/Likelihood/HomogeneousTreeLikelihood.h
+  Bpp/Phyl/Likelihood/MarginalAncestralStateReconstruction.h
+  Bpp/Phyl/Likelihood/NNIHomogeneousTreeLikelihood.h
+  Bpp/Phyl/Likelihood/NonHomogeneousTreeLikelihood.h
+  Bpp/Phyl/Likelihood/PseudoNewtonOptimizer.h
+  Bpp/Phyl/Likelihood/RASTools.h
+  Bpp/Phyl/Likelihood/RHomogeneousClockTreeLikelihood.h
+  Bpp/Phyl/Likelihood/RHomogeneousMixedTreeLikelihood.h
+  Bpp/Phyl/Likelihood/RHomogeneousTreeLikelihood.h
+  Bpp/Phyl/Likelihood/RNonHomogeneousMixedTreeLikelihood.h
+  Bpp/Phyl/Likelihood/RNonHomogeneousTreeLikelihood.h
+  Bpp/Phyl/Likelihood/SitePartitionTreeLikelihood.h
+  Bpp/Phyl/Likelihood/TreeLikelihoodData.h
+  Bpp/Phyl/Likelihood/TreeLikelihood.h
+  Bpp/Phyl/Likelihood/TreeLikelihoodTools.h
+  Bpp/Phyl/Likelihood/PairedSiteLikelihoods.h
+  Bpp/Phyl/Likelihood/GlobalClockTreeLikelihoodFunctionWrapper.h
+  Bpp/Phyl/Mapping/LaplaceSubstitutionCount.h
+  Bpp/Phyl/Mapping/WeightedSubstitutionCount.h
+  Bpp/Phyl/Mapping/OneJumpSubstitutionCount.h
+  Bpp/Phyl/Mapping/ProbabilisticSubstitutionMapping.h
+  Bpp/Phyl/Mapping/NaiveSubstitutionCount.h
+  Bpp/Phyl/Mapping/DecompositionSubstitutionCount.h
+  Bpp/Phyl/Mapping/UniformizationSubstitutionCount.h
+  Bpp/Phyl/Mapping/SubstitutionRegister.h
+  Bpp/Phyl/Mapping/SubstitutionCount.h
+  Bpp/Phyl/Mapping/SubstitutionMapping.h
+  Bpp/Phyl/Mapping/SubstitutionMappingTools.h
+  Bpp/Phyl/Model/StateMap.h
+  Bpp/Phyl/Model/AbstractSubstitutionModel.h
+  Bpp/Phyl/Model/BinarySubstitutionModel.h
+  Bpp/Phyl/Model/G2001.h
+  Bpp/Phyl/Model/AbstractBiblioSubstitutionModel.h
+  Bpp/Phyl/Model/AbstractBiblioMixedSubstitutionModel.h
+  Bpp/Phyl/Model/MarkovModulatedSubstitutionModel.h
+  Bpp/Phyl/Model/MixedSubstitutionModel.h
+  Bpp/Phyl/Model/AbstractMixedSubstitutionModel.h
+  Bpp/Phyl/Model/MixtureOfASubstitutionModel.h
+  Bpp/Phyl/Model/MixtureOfSubstitutionModels.h
+  Bpp/Phyl/Model/RateDistributionFactory.h
+  Bpp/Phyl/Model/RE08.h
+  Bpp/Phyl/Model/SubstitutionModelFactory.h
+  Bpp/Phyl/Model/SubstitutionModel.h
+  Bpp/Phyl/Model/SubstitutionModelSet.h
+  Bpp/Phyl/Model/MixedSubstitutionModelSet.h
+  Bpp/Phyl/Model/SubstitutionModelSetTools.h
+  Bpp/Phyl/Model/TS98.h
+  Bpp/Phyl/Model/AbstractWordSubstitutionModel.h
+  Bpp/Phyl/Model/WordSubstitutionModel.h
+  Bpp/Phyl/Model/Nucleotide/NucleotideSubstitutionModel.h
+  Bpp/Phyl/Model/Nucleotide/F84.h
+  Bpp/Phyl/Model/Nucleotide/HKY85.h
+  Bpp/Phyl/Model/Nucleotide/JCnuc.h
+  Bpp/Phyl/Model/Nucleotide/GTR.h
+  Bpp/Phyl/Model/Nucleotide/K80.h
+  Bpp/Phyl/Model/Nucleotide/L95.h
+  Bpp/Phyl/Model/Nucleotide/RN95.h
+  Bpp/Phyl/Model/Nucleotide/RN95s.h
+  Bpp/Phyl/Model/Nucleotide/SSR.h
+  Bpp/Phyl/Model/Nucleotide/T92.h
+  Bpp/Phyl/Model/Nucleotide/TN93.h
+  Bpp/Phyl/Model/Nucleotide/gBGC.h
+  Bpp/Phyl/Model/Nucleotide/YpR.h
+  Bpp/Phyl/Model/Protein/ProteinSubstitutionModel.h
+  Bpp/Phyl/Model/Protein/DSO78.h
+  Bpp/Phyl/Model/Protein/UserProteinSubstitutionModel.h
+  Bpp/Phyl/Model/Protein/JCprot.h
+  Bpp/Phyl/Model/Protein/JTT92.h
+  Bpp/Phyl/Model/Protein/LG08.h
+  Bpp/Phyl/Model/Protein/WAG01.h
+  Bpp/Phyl/Model/Protein/LLG08_EHO.h
+  Bpp/Phyl/Model/Protein/LLG08_EX2.h
+  Bpp/Phyl/Model/Protein/LLG08_EX3.h
+  Bpp/Phyl/Model/Protein/LLG08_UL2.h
+  Bpp/Phyl/Model/Protein/LLG08_UL3.h
+  Bpp/Phyl/Model/Protein/LGL08_CAT.h
+  Bpp/Phyl/Model/Protein/Coala.h
+  Bpp/Phyl/Model/Protein/CoalaCore.h
+  Bpp/Phyl/Model/Codon/GY94.h
+  Bpp/Phyl/Model/Codon/MG94.h
+  Bpp/Phyl/Model/Codon/CodonSubstitutionModel.h
+  Bpp/Phyl/Model/Codon/TripletSubstitutionModel.h
+  Bpp/Phyl/Model/Codon/AbstractCodonSubstitutionModel.h
+  Bpp/Phyl/Model/Codon/AbstractCodonFrequenciesSubstitutionModel.h
+  Bpp/Phyl/Model/Codon/AbstractCodonPhaseFrequenciesSubstitutionModel.h
+  Bpp/Phyl/Model/Codon/AbstractCodonDistanceSubstitutionModel.h
+  Bpp/Phyl/Model/Codon/AbstractCodonFitnessSubstitutionModel.h
+  Bpp/Phyl/Model/Codon/CodonDistanceSubstitutionModel.h
+  Bpp/Phyl/Model/Codon/CodonDistanceFrequenciesSubstitutionModel.h
+  Bpp/Phyl/Model/Codon/CodonDistancePhaseFrequenciesSubstitutionModel.h
+  Bpp/Phyl/Model/Codon/CodonDistanceFitnessPhaseFrequenciesSubstitutionModel.h
+  Bpp/Phyl/Model/Codon/CodonRateSubstitutionModel.h
+  Bpp/Phyl/Model/Codon/CodonRateFrequenciesSubstitutionModel.h
+  Bpp/Phyl/Model/Codon/YN98.h
+  Bpp/Phyl/Model/Codon/YNGKP_M1.h
+  Bpp/Phyl/Model/Codon/YNGKP_M2.h
+  Bpp/Phyl/Model/Codon/YNGKP_M3.h
+  Bpp/Phyl/Model/Codon/YNGKP_M7.h
+  Bpp/Phyl/Model/Codon/YNGKP_M8.h
+  Bpp/Phyl/Model/FrequenciesSet/FrequenciesSet.h
+  Bpp/Phyl/Model/FrequenciesSet/NucleotideFrequenciesSet.h
+  Bpp/Phyl/Model/FrequenciesSet/WordFrequenciesSet.h
+  Bpp/Phyl/Model/FrequenciesSet/CodonFrequenciesSet.h
+  Bpp/Phyl/Model/FrequenciesSet/FrequenciesSet.h
+  Bpp/Phyl/Model/FrequenciesSet/NucleotideFrequenciesSet.h
+  Bpp/Phyl/Model/FrequenciesSet/ProteinFrequenciesSet.h
+  Bpp/Phyl/Model/FrequenciesSet/MvaFrequenciesSet.h
+  Bpp/Phyl/Model/FrequenciesSet/WordFrequenciesSet.h
+  Bpp/Phyl/Model/FrequenciesSet/CodonFrequenciesSet.h
+  Bpp/Phyl/Model/RateDistribution/ConstantRateDistribution.h
+  Bpp/Phyl/Model/RateDistribution/GammaDiscreteRateDistribution.h
+  Bpp/Phyl/Model/RateDistribution/GaussianDiscreteRateDistribution.h
+  Bpp/Phyl/Model/RateDistribution/ExponentialDiscreteRateDistribution.h
+  Bpp/Phyl/NNISearchable.h
+  Bpp/Phyl/NNITopologySearch.h
+  Bpp/Phyl/Node.h
+  Bpp/Phyl/NodeTemplate.h
+  Bpp/Phyl/OptimizationTools.h
+  Bpp/Phyl/Parsimony/AbstractTreeParsimonyData.h
+  Bpp/Phyl/Parsimony/AbstractTreeParsimonyScore.h
+  Bpp/Phyl/Parsimony/DRTreeParsimonyData.h
+  Bpp/Phyl/Parsimony/DRTreeParsimonyScore.h
+  Bpp/Phyl/Parsimony/TreeParsimonyData.h
+  Bpp/Phyl/Parsimony/TreeParsimonyScore.h
+  Bpp/Phyl/PatternTools.h
+  Bpp/Phyl/PhyloStatistics.h
+  Bpp/Phyl/Simulation/DetailedSiteSimulator.h
+  Bpp/Phyl/Simulation/HomogeneousSequenceSimulator.h
+  Bpp/Phyl/Simulation/MutationProcess.h
+  Bpp/Phyl/Simulation/NonHomogeneousSequenceSimulator.h
+  Bpp/Phyl/Simulation/SequenceSimulationTools.h
+  Bpp/Phyl/Simulation/SequenceSimulator.h
+  Bpp/Phyl/Simulation/SiteSimulator.h
+  Bpp/Phyl/SitePatterns.h
+  Bpp/Phyl/TopologySearch.h
+  Bpp/Phyl/TreeExceptions.h
+  Bpp/Phyl/Tree.h
+  Bpp/Phyl/TreeTemplate.h
+  Bpp/Phyl/TreeTemplateTools.h
+  Bpp/Phyl/TreeTools.h
+  )
+
+# Build the static lib
+ADD_LIBRARY(bppphyl-static STATIC ${CPP_FILES})
+SET_TARGET_PROPERTIES(bppphyl-static
+  PROPERTIES OUTPUT_NAME bpp-phyl
+  CLEAN_DIRECT_OUTPUT 1
+  )
+TARGET_LINK_LIBRARIES(bppphyl-static ${LIBS})
+
+# Build the shared lib
+ADD_LIBRARY(bppphyl-shared SHARED ${CPP_FILES})
+SET_TARGET_PROPERTIES(bppphyl-shared
+  PROPERTIES OUTPUT_NAME bpp-phyl
+  CLEAN_DIRECT_OUTPUT 1
+  VERSION ${BPPPHYL_VERSION}
+  SOVERSION ${BPPPHYL_VERSION_MAJOR}
+  )
+TARGET_LINK_LIBRARIES(bppphyl-shared ${LIBS})
+
+# Install libs
+INSTALL(TARGETS bppphyl-static bppphyl-shared DESTINATION lib${LIB_SUFFIX})
+
+# Install headers
+INSTALL(DIRECTORY Bpp/ DESTINATION include/Bpp FILES_MATCHING PATTERN "*.h")
+
+# Generate generic include files (.all)
+INSTALL(CODE "EXECUTE_PROCESS(COMMAND ${CMAKE_SOURCE_DIR}/genIncludes.sh ${CMAKE_PREFIX_PATH}/include/Bpp)")
+
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..8d53244
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,86 @@
+# CMake script for bpp-phyl unit tests
+# Author: Julien Dutheil
+# Created: 12/11/2010
+
+MACRO(TEST_FIND_LIBRARY OUTPUT_LIBS lib_name include_to_find)
+  #start:
+  FIND_PATH(${lib_name}_INCLUDE_DIR ${include_to_find})
+
+  SET(${lib_name}_NAMES ${lib_name} ${lib_name}.lib ${lib_name}.dll)
+  FIND_LIBRARY(${lib_name}_LIBRARY NAMES ${${lib_name}_NAMES})
+  IF(${lib_name}_LIBRARY)
+    MESSAGE("-- Library ${lib_name} found here:")
+    MESSAGE("   includes: ${${lib_name}_INCLUDE_DIR}")
+    MESSAGE("   dynamic libraries: ${${lib_name}_LIBRARY}")
+    MESSAGE(WARNING "Library ${lib_name} is already installed in the system tree. Test will be built against it. This may lead to unexpected results. You may want to do 'make install' before 'make test', or remove the installed version.")
+  ELSE()
+    SET(${lib_name}_LIBRARY "-L../src -lbpp-phyl")
+    SET(${lib_name}_INCLUDE_DIR "../src/")
+  ENDIF()
+  INCLUDE_DIRECTORIES(${${lib_name}_INCLUDE_DIR})
+  SET(${OUTPUT_LIBS} ${${OUTPUT_LIBS}} ${${lib_name}_LIBRARY})
+ENDMACRO(TEST_FIND_LIBRARY)
+
+#Find the bpp-phyl library library:
+TEST_FIND_LIBRARY(LIBS bpp-phyl Bpp/Phyl/Tree.h)
+
+ADD_EXECUTABLE(test_tree test_tree.cpp)
+TARGET_LINK_LIBRARIES(test_tree ${LIBS})
+ADD_TEST(test_tree "test_tree")
+
+ADD_EXECUTABLE(test_models test_models.cpp)
+TARGET_LINK_LIBRARIES(test_models ${LIBS})
+ADD_TEST(test_models "test_models")
+
+ADD_EXECUTABLE(test_detailed_simulations test_detailed_simulations.cpp)
+TARGET_LINK_LIBRARIES(test_detailed_simulations ${LIBS})
+ADD_TEST(test_detailed_simulations "test_detailed_simulations")
+
+ADD_EXECUTABLE(test_simulations test_simulations.cpp)
+TARGET_LINK_LIBRARIES(test_simulations ${LIBS})
+ADD_TEST(test_simulations "test_simulations")
+
+ADD_EXECUTABLE(test_parsimony test_parsimony.cpp)
+TARGET_LINK_LIBRARIES(test_parsimony ${LIBS})
+ADD_TEST(test_parsimony "test_parsimony")
+
+ADD_EXECUTABLE(test_likelihood test_likelihood.cpp)
+TARGET_LINK_LIBRARIES(test_likelihood ${LIBS})
+ADD_TEST(test_likelihood "test_likelihood")
+
+ADD_EXECUTABLE(test_likelihood_nh test_likelihood_nh.cpp)
+TARGET_LINK_LIBRARIES(test_likelihood_nh ${LIBS})
+ADD_TEST(test_likelihood_nh "test_likelihood_nh")
+
+ADD_EXECUTABLE(test_likelihood_clock test_likelihood_clock.cpp)
+TARGET_LINK_LIBRARIES(test_likelihood_clock ${LIBS})
+ADD_TEST(test_likelihood_clock "test_likelihood_clock")
+
+ADD_EXECUTABLE(test_mapping test_mapping.cpp)
+TARGET_LINK_LIBRARIES(test_mapping ${LIBS})
+ADD_TEST(test_mapping "test_mapping")
+
+ADD_EXECUTABLE(test_mapping_codon test_mapping_codon.cpp)
+TARGET_LINK_LIBRARIES(test_mapping_codon ${LIBS})
+ADD_TEST(test_mapping_codon "test_mapping_codon")
+
+ADD_EXECUTABLE(test_nhx test_nhx.cpp)
+TARGET_LINK_LIBRARIES(test_nhx ${LIBS})
+ADD_TEST(test_nhx "test_nhx")
+
+ADD_EXECUTABLE(test_bowker test_bowker.cpp)
+TARGET_LINK_LIBRARIES(test_bowker ${LIBS})
+ADD_TEST(test_bowker "test_bowker")
+
+IF(UNIX)
+  SET_PROPERTY(TEST test_detailed_simulations test_simulations test_parsimony test_models test_likelihood test_likelihood_nh test_likelihood_clock test_tree test_mapping test_mapping_codon test_nhx test_bowker PROPERTY ENVIRONMENT "LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH}:../src")
+ENDIF()
+
+IF(APPLE)
+  SET_PROPERTY(TEST test_detailed_simulations test_simulations test_parsimony test_models test_likelihood test_likelihood_nh test_likelihood_clock test_tree test_mapping test_mapping_codon test_nhx test_bowker PROPERTY ENVIRONMENT "DYLD_LIBRARY_PATH=$ENV{DYLD_LIBRARY_PATH}:../src")
+ENDIF()
+
+IF(WIN32)
+  SET(ENV{PATH} "$ENV{PATH};..\\src")
+ENDIF()
+
diff --git a/test/example1.mp.dnd b/test/example1.mp.dnd
new file mode 100644
index 0000000..43ccdae
--- /dev/null
+++ b/test/example1.mp.dnd
@@ -0,0 +1,2 @@
+(((s05:0.10000,s04:0.00000):0.30000,s03:0.00000):0.26667,s02:0.06667,
+s01:0.16667);
diff --git a/test/example1.ph b/test/example1.ph
new file mode 100644
index 0000000..64a5977
--- /dev/null
+++ b/test/example1.ph
@@ -0,0 +1,6 @@
+ 5 10
+s01          ATGCGTCTTA
+s02          ACGC-TCTTA
+s03          AAGC-TCCGA
+s04          TAGG-TCCGT
+s05          TAGG-TCCCT
diff --git a/test/test_bowker.cpp b/test/test_bowker.cpp
new file mode 100644
index 0000000..51acaef
--- /dev/null
+++ b/test/test_bowker.cpp
@@ -0,0 +1,163 @@
+//
+// File: test_bowker.cpp
+// Created by: Julien Dutheil
+// Created on: Wed Apr 27 14:19 2011
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for numerical calculus. This file is part of the Bio++ project.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include <Bpp/Seq/Alphabet/DNA.h>
+#include <Bpp/Seq/SequenceTools.h>
+#include <Bpp/Phyl/TreeTemplate.h>
+#include <Bpp/Phyl/Model/Nucleotide/T92.h>
+#include <Bpp/Phyl/Model/FrequenciesSet/NucleotideFrequenciesSet.h>
+#include <Bpp/Phyl/Model/FrequenciesSet/FrequenciesSet.h>
+#include <Bpp/Phyl/Model/RateDistribution/ConstantRateDistribution.h>
+#include <Bpp/Phyl/Model/SubstitutionModelSetTools.h>
+#include <Bpp/Phyl/Simulation/HomogeneousSequenceSimulator.h>
+#include <iostream>
+
+using namespace bpp;
+using namespace std;
+
+double testBowker(const NonHomogeneousSequenceSimulator& sim, size_t seqlen) {
+  auto_ptr<SiteContainer> sites(sim.simulate(seqlen));
+  auto_ptr<BowkerTest> bTest(SequenceTools::bowkerTest(sites->getSequence(0), sites->getSequence(1)));
+  return bTest->getPValue();
+}
+
+int main() {
+  auto_ptr< TreeTemplate<Node> > tree(TreeTemplateTools::parenthesisToTree("(A:0.02, B:0.02);"));
+
+  //First test homogeneous model:
+  cout << "..:: Testing with homogeneous model ::.." << endl;
+  auto_ptr<NucleicAlphabet> alphabet(new DNA());
+  SubstitutionModel* model = new T92(alphabet.get(), 3., 0.65);
+  FrequenciesSet* rootFreqs = new GCFrequenciesSet(alphabet.get(), 0.65);
+  auto_ptr<DiscreteDistribution> rdist(new ConstantRateDistribution());
+  auto_ptr<SubstitutionModelSet> modelSetH(SubstitutionModelSetTools::createHomogeneousModelSet(model, rootFreqs, tree.get()));
+  NonHomogeneousSequenceSimulator simulatorH(modelSetH.get(), rdist.get(), tree.get());
+
+  unsigned int nsim = 10000;
+  unsigned int seqlen = 2000;
+  unsigned int count05 = 0;
+  unsigned int count01 = 0;
+
+  for (unsigned int i = 0; i < nsim; ++i) {
+    ApplicationTools::displayGauge(i, nsim - 1);
+    double pvalue = testBowker(simulatorH, seqlen);
+    if (pvalue < 0.05) count05++;
+    if (pvalue < 0.01) count01++;
+  }
+  double p05 = (static_cast<double>(count05) / static_cast<double>(nsim));
+  double p01 = (static_cast<double>(count01) / static_cast<double>(nsim));
+  cout << p05 << "\t" << p01 << endl;
+  if (abs(p05 - 0.05) > 0.05) return 1;
+  if (abs(p01 - 0.01) > 0.01) return 1;
+
+  //Then test homogeneous, non-stationary model:
+  cout << "..:: Testing with homogeneous, non-stationary model ::.." << endl;
+  model = new T92(alphabet.get(), 3., 0.65);
+  rootFreqs = new GCFrequenciesSet(alphabet.get(), 0.4);
+  auto_ptr<SubstitutionModelSet> modelSetHNS(SubstitutionModelSetTools::createHomogeneousModelSet(model, rootFreqs, tree.get()));
+  NonHomogeneousSequenceSimulator simulatorHNS(modelSetHNS.get(), rdist.get(), tree.get());
+
+  count05 = 0;
+  count01 = 0;
+  for (unsigned int i = 0; i < nsim; ++i) {
+    ApplicationTools::displayGauge(i, nsim - 1);
+    double pvalue = testBowker(simulatorHNS, seqlen);
+    if (pvalue < 0.05) count05++;
+    if (pvalue < 0.01) count01++;
+  }
+  p05 = (static_cast<double>(count05) / static_cast<double>(nsim));
+  p01 = (static_cast<double>(count01) / static_cast<double>(nsim));
+  cout << p05 << "\t" << p01 << endl;
+  if (abs(p05 - 0.05) > 0.05) return 1;
+  if (abs(p01 - 0.01) > 0.01) return 1;
+
+  //Now test non-homogeneous model, with distinct GC content:
+  cout << "..:: Testing with non-homogeneous, non-stationary model ::.." << endl;
+  model = new T92(alphabet.get(), 3., 0.5);
+  rootFreqs = new GCFrequenciesSet(alphabet.get(), 0.65);
+  std::vector<std::string> globalParameterNames;
+  globalParameterNames.push_back("T92.kappa");
+  auto_ptr<SubstitutionModelSet> modelSetNHGC(SubstitutionModelSetTools::createNonHomogeneousModelSet(model, rootFreqs, tree.get(), globalParameterNames));
+  modelSetNHGC->setParameterValue("T92.theta_1", 0.3);
+  modelSetNHGC->setParameterValue("T92.theta_2", 0.8);
+  NonHomogeneousSequenceSimulator simulatorNHGC(modelSetNHGC.get(), rdist.get(), tree.get());
+
+  count05 = 0;
+  count01 = 0;
+  for (unsigned int i = 0; i < nsim; ++i) {
+    ApplicationTools::displayGauge(i, nsim - 1);
+    double pvalue = testBowker(simulatorNHGC, seqlen);
+    if (pvalue < 0.05) count05++;
+    if (pvalue < 0.01) count01++;
+  }
+  p05 = (static_cast<double>(count05) / static_cast<double>(nsim));
+  p01 = (static_cast<double>(count01) / static_cast<double>(nsim));
+  cout << p05 << "\t" << p01 << endl;
+  if (p05 < 0.7) return 1;
+  if (p01 < 0.7) return 1;
+
+  //Now test non-homogeneous model, with distinct ts/tv:
+  cout << "..:: Testing with non-homogeneous, stationary model ::.." << endl;
+  model = new T92(alphabet.get(), 3., 0.5);
+  rootFreqs = new GCFrequenciesSet(alphabet.get(), 0.5);
+  globalParameterNames.clear();
+  globalParameterNames.push_back("T92.theta");
+  auto_ptr<SubstitutionModelSet> modelSetNHTsTv(SubstitutionModelSetTools::createNonHomogeneousModelSet(model, rootFreqs, tree.get(), globalParameterNames));
+  modelSetNHTsTv->setParameterValue("T92.kappa_1", 2);
+  modelSetNHTsTv->setParameterValue("T92.kappa_2", 7);
+  NonHomogeneousSequenceSimulator simulatorNHTsTv(modelSetNHTsTv.get(), rdist.get(), tree.get());
+
+  count05 = 0;
+  count01 = 0;
+  for (unsigned int i = 0; i < nsim; ++i) {
+    ApplicationTools::displayGauge(i, nsim - 1);
+    double pvalue = testBowker(simulatorNHTsTv, seqlen);
+    if (pvalue < 0.05) count05++;
+    if (pvalue < 0.01) count01++;
+  }
+  p05 = (static_cast<double>(count05) / static_cast<double>(nsim));
+  p01 = (static_cast<double>(count01) / static_cast<double>(nsim));
+  cout << p05 << "\t" << p01 << endl;
+  if (abs(p05 - 0.05) > 0.05) return 1;
+  if (abs(p01 - 0.01) > 0.01) return 1;
+
+  //-------------
+
+  return 0;
+}
diff --git a/test/test_detailed_simulations.cpp b/test/test_detailed_simulations.cpp
new file mode 100644
index 0000000..900c08a
--- /dev/null
+++ b/test/test_detailed_simulations.cpp
@@ -0,0 +1,110 @@
+//
+// File: test_detailed_simulations.cpp
+// Created by: Julien Dutheil
+// Created on: Fri Nov 12 15:41 2010
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for numerical calculus. This file is part of the Bio++ project.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include <Bpp/Numeric/Prob/ConstantDistribution.h>
+#include <Bpp/Numeric/Matrix/Matrix.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Seq/Alphabet/DNA.h>
+#include <Bpp/Phyl/TreeTemplate.h>
+#include <Bpp/Phyl/Model/Nucleotide/GTR.h>
+#include <Bpp/Phyl/Simulation/HomogeneousSequenceSimulator.h>
+#include <iostream>
+
+using namespace bpp;
+using namespace std;
+
+int main() {
+  TreeTemplate<Node>* tree = TreeTemplateTools::parenthesisToTree("((A:0.001, B:0.002):0.003,C:0.01,D:0.1);");
+  cout << tree->getNumberOfLeaves() << endl;
+  vector<int> ids = tree->getNodesId();
+  //-------------
+
+  NucleicAlphabet* alphabet = new DNA();
+  SubstitutionModel* model = new GTR(alphabet, 1, 0.2, 0.3, 0.4, 0.4, 0.1, 0.35, 0.35, 0.2);
+  //DiscreteDistribution* rdist = new GammaDiscreteDistribution(4, 0.4, 0.4);
+  DiscreteDistribution* rdist = new ConstantDistribution(1.0);
+  HomogeneousSequenceSimulator simulator(model, rdist, tree);
+
+  unsigned int n = 100000;
+  map<int, RowMatrix<unsigned int> > counts;
+  for (size_t j = 0; j < ids.size() - 1; ++j) //ignore root, the last id
+    counts[ids[j]].resize(4, 4);
+  for (unsigned int i = 0; i < n; ++i) {
+    RASiteSimulationResult* result = simulator.dSimulate();
+    for (size_t j = 0; j < ids.size() - 1; ++j) { //ignore root, the last id
+      result->getMutationPath(ids[j]).getEventCounts(counts[ids[j]]);
+    }
+    delete result;
+  }
+  map<int, RowMatrix<double> >freqs;
+  map<int, double> sums;
+  for (size_t k = 0; k < ids.size() - 1; ++k) { //ignore root, the last id
+    RowMatrix<double>* freqsP = &freqs[ids[k]];
+    RowMatrix<unsigned int>* countsP = &counts[ids[k]];
+    freqsP->resize(4, 4);
+    for (unsigned int i = 0; i < 4; ++i)
+      for (unsigned int j = 0; j < 4; ++j)
+        (*freqsP)(i, j) = static_cast<double>((*countsP)(i, j)) / (static_cast<double>(n));
+    
+    //For now we simply compare the total number of substitutions:
+    sums[ids[k]] = MatrixTools::sumElements(*freqsP);
+  
+    cout << "Br" << ids[k] << " BrLen = " << tree->getDistanceToFather(ids[k]) << " counts = " << sums[ids[k]] << endl;
+    MatrixTools::print(*freqsP);
+  }
+  //We should compare this matrix with the expected one!
+
+  for (size_t k = 0; k < ids.size() - 1; ++k) { //ignore root, the last id
+    if (abs(sums[ids[k]] - tree->getDistanceToFather(ids[k])) > 0.01) {
+      delete tree;
+      delete alphabet;
+      delete model;
+      delete rdist;
+      return 1;
+    }
+  }
+  //-------------
+  delete tree;
+  delete alphabet;
+  delete model;
+  delete rdist;
+
+  //return (abs(obs - 0.001) < 0.001 ? 0 : 1);
+  return 0;
+}
diff --git a/test/test_likelihood.cpp b/test/test_likelihood.cpp
new file mode 100644
index 0000000..fe5081e
--- /dev/null
+++ b/test/test_likelihood.cpp
@@ -0,0 +1,101 @@
+//
+// File: test_likelihood.cpp
+// Created by: Julien Dutheil
+// Created on: Mon Apr 04 10:18 2011
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for numerical calculus. This file is part of the Bio++ project.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include <Bpp/Numeric/Prob/GammaDiscreteDistribution.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+#include <Bpp/Phyl/TreeTemplate.h>
+#include <Bpp/Phyl/Model/Nucleotide/T92.h>
+#include <Bpp/Phyl/Simulation/HomogeneousSequenceSimulator.h>
+#include <Bpp/Phyl/Likelihood/RHomogeneousTreeLikelihood.h>
+#include <Bpp/Phyl/OptimizationTools.h>
+#include <iostream>
+
+using namespace bpp;
+using namespace std;
+
+void fitModelH(SubstitutionModel* model, DiscreteDistribution* rdist, const Tree& tree, const SiteContainer& sites,
+    double initialValue, double finalValue) {
+  RHomogeneousTreeLikelihood tl(tree, sites, model, rdist);
+  tl.initialize();
+  ApplicationTools::displayResult("Test model", model->getName());
+  cout << setprecision(20) << tl.getValue() << endl;
+  ApplicationTools::displayResult("* initial likelihood", tl.getValue());
+  if (abs(tl.getValue() - initialValue) > 0.001)
+    throw Exception("Incorrect initial value.");
+  OptimizationTools::optimizeTreeScale(&tl);
+  ApplicationTools::displayResult("* likelihood after tree scale", tl.getValue());
+  OptimizationTools::optimizeNumericalParameters2(&tl, tl.getParameters(), 0, 0.000001, 10000, 0, 0);
+  cout << setprecision(20) << tl.getValue() << endl;
+  ApplicationTools::displayResult("* likelihood after full optimization", tl.getValue());
+  if (abs(tl.getValue() - finalValue) > 0.001)
+    throw Exception("Incorrect final value.");
+}
+
+int main() {
+  TreeTemplate<Node>* tree = TreeTemplateTools::parenthesisToTree("((A:0.01, B:0.02):0.03,C:0.01,D:0.1);");
+  vector<string> seqNames= tree->getLeavesNames();
+  vector<int> ids = tree->getNodesId();
+  //-------------
+
+  const NucleicAlphabet* alphabet = &AlphabetTools::DNA_ALPHABET;
+  SubstitutionModel* model = new T92(alphabet, 3.);
+  DiscreteDistribution* rdist = new GammaDiscreteDistribution(1.0, 4);
+  rdist->aliasParameters("alpha", "beta");
+
+  VectorSiteContainer sites(alphabet);
+  sites.addSequence(BasicSequence("A", "AAATGGCTGTGCACGTC", alphabet));
+  sites.addSequence(BasicSequence("B", "GACTGGATCTGCACGTC", alphabet));
+  sites.addSequence(BasicSequence("C", "CTCTGGATGTGCACGTG", alphabet));
+  sites.addSequence(BasicSequence("D", "AAATGGCGGTGCGCCTA", alphabet));
+
+  try {
+    fitModelH(model, rdist, *tree, sites, 75.031104151696752069, 65.03473753351640596065);
+  } catch (Exception& ex) {
+    cerr << ex.what() << endl;
+    return 1;
+  }  
+
+  //-------------
+  delete tree;
+  delete model;
+  delete rdist;
+
+  return 0;
+}
diff --git a/test/test_likelihood_clock.cpp b/test/test_likelihood_clock.cpp
new file mode 100644
index 0000000..2647ffa
--- /dev/null
+++ b/test/test_likelihood_clock.cpp
@@ -0,0 +1,134 @@
+//
+// File: test_likelihood_clock.cpp
+// Created by: Julien Dutheil
+// Created on: Mon Jul 12 14:57 2011
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for numerical calculus. This file is part of the Bio++ project.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include <Bpp/Numeric/Prob/GammaDiscreteDistribution.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+#include <Bpp/Phyl/TreeTemplate.h>
+#include <Bpp/Phyl/Model/Nucleotide/T92.h>
+#include <Bpp/Phyl/Simulation/HomogeneousSequenceSimulator.h>
+#include <Bpp/Phyl/Likelihood/RHomogeneousTreeLikelihood.h>
+#include <Bpp/Phyl/Likelihood/RHomogeneousClockTreeLikelihood.h>
+#include <Bpp/Phyl/OptimizationTools.h>
+#include <iostream>
+
+using namespace bpp;
+using namespace std;
+
+void fitModelH(SubstitutionModel* model, DiscreteDistribution* rdist, const Tree& tree, const SiteContainer& sites,
+    double initialValue, double finalValue) {
+  RHomogeneousTreeLikelihood tl(tree, sites, model, rdist, false);
+  tl.enableFirstOrderDerivatives(false);
+  tl.enableSecondOrderDerivatives(false);
+  tl.initialize();
+  ApplicationTools::displayResult("Test model", model->getName());
+  cout << setprecision(20) << tl.getValue() << endl;
+  ApplicationTools::displayResult("* initial likelihood", tl.getValue());
+  if (abs(tl.getValue() - initialValue) > 0.0001)
+    throw Exception("Incorrect initial value.");
+  auto_ptr<OutputStream> messenger(new StlOutputStream(new ofstream("messages.txt", ios::out)));
+  auto_ptr<OutputStream> profiler(new StlOutputStream(new ofstream("profile.txt", ios::out)));
+  profiler->setPrecision(20);
+  OptimizationTools::optimizeNumericalParameters2(&tl, tl.getParameters(), 0, 0.000001, 10000, messenger.get(), profiler.get(), false, true, 2, OptimizationTools::OPTIMIZATION_NEWTON);
+  cout << setprecision(20) << tl.getValue() << endl;
+  ApplicationTools::displayResult("* likelihood after full optimization", tl.getValue());
+  tl.getParameters().printParameters(cout);
+  if (abs(tl.getValue() - finalValue) > 0.0001)
+    throw Exception("Incorrect final value.");
+}
+
+void fitModelHClock(SubstitutionModel* model, DiscreteDistribution* rdist, const Tree& tree, const SiteContainer& sites,
+    double initialValue, double finalValue) {
+  RHomogeneousClockTreeLikelihood tl(tree, sites, model, rdist);
+  tl.enableFirstOrderDerivatives(false);
+  tl.enableSecondOrderDerivatives(false);
+  tl.initialize();
+  ApplicationTools::displayResult("Test model", model->getName());
+  cout << setprecision(20) << tl.getValue() << endl;
+  ApplicationTools::displayResult("* initial likelihood", tl.getValue());
+  if (abs(tl.getValue() - initialValue) > 0.001)
+    throw Exception("Incorrect initial value.");
+  auto_ptr<OutputStream> messenger(new StlOutputStream(new ofstream("messages.txt", ios::out)));
+  auto_ptr<OutputStream> profiler(new StlOutputStream(new ofstream("profile.txt", ios::out)));
+  profiler->setPrecision(20);
+  OptimizationTools::optimizeNumericalParametersWithGlobalClock2(&tl, tl.getParameters(), 0, 0.000001, 10000, messenger.get(), profiler.get());
+  cout << setprecision(20) << tl.getValue() << endl;
+  ApplicationTools::displayResult("* likelihood after full optimization", tl.getValue());
+  tl.getParameters().printParameters(cout);
+  if (abs(tl.getValue() - finalValue) > 0.001)
+    throw Exception("Incorrect final value.");
+}
+
+int main() {
+  TreeTemplate<Node>* tree = TreeTemplateTools::parenthesisToTree("(((A:0.01, B:0.01):0.02,C:0.03):0.01,D:0.04);");
+  vector<string> seqNames = tree->getLeavesNames();
+  vector<int> ids = tree->getNodesId();
+  //-------------
+
+  const NucleicAlphabet* alphabet = &AlphabetTools::DNA_ALPHABET;
+  SubstitutionModel* model = new T92(alphabet, 3.);
+  DiscreteDistribution* rdist = new GammaDiscreteDistribution(4, 1.0);
+  rdist->aliasParameters("alpha", "beta");
+
+  VectorSiteContainer sites(alphabet);
+  sites.addSequence(BasicSequence("A", "AAATGGCTGTGCACGTC", alphabet));
+  sites.addSequence(BasicSequence("B", "AACTGGATCTGCATGTC", alphabet));
+  sites.addSequence(BasicSequence("C", "ATCTGGACGTGCACGTG", alphabet));
+  sites.addSequence(BasicSequence("D", "CAACGGGAGTGCGCCTA", alphabet));
+
+  try {
+    fitModelH(model, rdist, *tree, sites, 93.017264552603336369, 71.265543199977557265);
+  } catch (Exception& ex) {
+    cerr << ex.what() << endl;
+    return 1;
+  }
+  try {
+    fitModelHClock(model, rdist, *tree, sites, 92.27912072473920090943, 71.26554020984087856050);
+  } catch (Exception& ex) {
+    cerr << ex.what() << endl;
+    return 1;
+  }
+
+  //-------------
+  delete tree;
+  delete model;
+  delete rdist;
+
+  return 0;
+}
diff --git a/test/test_likelihood_nh.cpp b/test/test_likelihood_nh.cpp
new file mode 100644
index 0000000..84f0a0e
--- /dev/null
+++ b/test/test_likelihood_nh.cpp
@@ -0,0 +1,156 @@
+//
+// File: test_likelihood_nh.cpp
+// Created by: Julien Dutheil
+// Created on: Thu Jul 14 11:04 2011
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for numerical calculus. This file is part of the Bio++ project.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include <Bpp/Numeric/Prob/GammaDiscreteDistribution.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+#include <Bpp/Phyl/TreeTemplate.h>
+#include <Bpp/Phyl/Model/Nucleotide/T92.h>
+#include <Bpp/Phyl/Model/FrequenciesSet/NucleotideFrequenciesSet.h>
+#include <Bpp/Phyl/Model/SubstitutionModelSetTools.h>
+#include <Bpp/Phyl/Simulation/NonHomogeneousSequenceSimulator.h>
+#include <Bpp/Phyl/Likelihood/RNonHomogeneousTreeLikelihood.h>
+#include <Bpp/Phyl/Likelihood/DRNonHomogeneousTreeLikelihood.h>
+#include <Bpp/Phyl/OptimizationTools.h>
+#include <iostream>
+
+using namespace bpp;
+using namespace std;
+
+void fitModelNH(SubstitutionModelSet* model, DiscreteDistribution* rdist, const Tree& tree, const SiteContainer& sites,
+    double initialValue, double finalValue, bool reparam) {
+  DRNonHomogeneousTreeLikelihood tl(tree, sites, model, rdist, false, reparam);
+  tl.initialize();
+  cout << setprecision(20) << tl.getValue() << endl;
+  ApplicationTools::displayResult("* initial likelihood", tl.getValue());
+  if (abs(tl.getValue() - initialValue) > 0.0001)
+    throw Exception("Incorrect initial value.");
+  OptimizationTools::optimizeTreeScale(&tl);
+  ApplicationTools::displayResult("* likelihood after tree scale", tl.getValue());
+  OptimizationTools::optimizeNumericalParameters2(&tl, tl.getParameters(), 0, 0.000001, 10000, 0, 0);
+  cout << setprecision(20) << tl.getValue() << endl;
+  ApplicationTools::displayResult("* likelihood after full optimization", tl.getValue());
+  if (abs(tl.getValue() - finalValue) > 0.0001)
+    throw Exception("Incorrect final value.");
+}
+
+int main() {
+  TreeTemplate<Node>* tree = TreeTemplateTools::parenthesisToTree("(((A:0.1, B:0.2):0.3,C:0.1):0.2,(D:0.3,(E:0.2,F:0.05):0.1):0.1);");
+  vector<string> seqNames= tree->getLeavesNames();
+  vector<int> ids = tree->getNodesId();
+  //-------------
+
+  const NucleicAlphabet* alphabet = &AlphabetTools::DNA_ALPHABET;
+  FrequenciesSet* rootFreqs = new GCFrequenciesSet(alphabet);
+  SubstitutionModel* model = new T92(alphabet, 3.);
+  std::vector<std::string> globalParameterNames;
+  globalParameterNames.push_back("T92.kappa");
+  SubstitutionModelSet* modelSet = SubstitutionModelSetTools::createNonHomogeneousModelSet(model, rootFreqs, tree, globalParameterNames);
+  //DiscreteDistribution* rdist = new ConstantDistribution(1.0, true);
+  //Very difficult to optimize on small datasets:
+  DiscreteDistribution* rdist = new GammaDiscreteDistribution(4, 1.0);
+  rdist->aliasParameters("alpha", "beta");
+
+  size_t nsites = 1000;
+  unsigned int nrep = 20;
+  size_t nmodels = modelSet->getNumberOfModels();
+  vector<double> thetas(nmodels);
+  vector<double> thetasEst1(nmodels);
+  vector<double> thetasEst2(nmodels);
+
+  for (size_t i = 0; i < nmodels; ++i) {
+    double theta = RandomTools::giveRandomNumberBetweenZeroAndEntry(0.99) + 0.005;
+    cout << "Theta" << i << " set to " << theta << endl; 
+    modelSet->setParameterValue("T92.theta_" + TextTools::toString(i + 1), theta);
+    thetas[i] = theta;
+  }
+  NonHomogeneousSequenceSimulator simulator(modelSet, rdist, tree);
+ 
+  for (unsigned int j = 0; j < nrep; j++) {
+
+    OutputStream* profiler  = new StlOutputStream(new ofstream("profile.txt", ios::out));
+    OutputStream* messenger = new StlOutputStream(new ofstream("messages.txt", ios::out));
+
+    //Simulate data:
+    auto_ptr<SiteContainer> sites(simulator.simulate(nsites));
+    //Now fit model:
+    auto_ptr<SubstitutionModelSet> modelSet2(modelSet->clone());
+    auto_ptr<SubstitutionModelSet> modelSet3(modelSet->clone());
+    RNonHomogeneousTreeLikelihood tl(*tree, *sites.get(), modelSet2.get(), rdist, true, true, false);
+    tl.initialize();
+    RNonHomogeneousTreeLikelihood tl2(*tree, *sites.get(), modelSet3.get(), rdist, true, true, true);
+    tl2.initialize();
+   
+    unsigned int c1 = OptimizationTools::optimizeNumericalParameters2(
+        &tl, tl.getParameters(), 0,
+        0.0001, 10000, messenger, profiler, false, false, 1, OptimizationTools::OPTIMIZATION_NEWTON);
+
+    unsigned int c2 = OptimizationTools::optimizeNumericalParameters2(
+        &tl2, tl2.getParameters(), 0,
+        0.0001, 10000, messenger, profiler, false, false, 1, OptimizationTools::OPTIMIZATION_NEWTON);
+
+    cout << c1 << ": " << tl.getValue() << "\t" << c2 << ": " << tl2.getValue() << endl;
+      
+    for (size_t i = 0; i < nmodels; ++i) {
+      cout << modelSet2->getModel(i)->getParameter("theta").getValue() << "\t" << modelSet3->getModel(i)->getParameter("theta").getValue() << endl;
+      //if (abs(modelSet2->getModel(i)->getParameter("theta").getValue() - modelSet3->getModel(i)->getParameter("theta").getValue()) > 0.1)
+      //  return 1;
+      thetasEst1[i] +=  modelSet2->getModel(i)->getParameter("theta").getValue();
+      thetasEst2[i] +=  modelSet3->getModel(i)->getParameter("theta").getValue();
+    }
+  }
+  thetasEst1 /= static_cast<double>(nrep);
+  thetasEst2 /= static_cast<double>(nrep);
+
+  //Now compare estimated values to real ones:
+  for (size_t i = 0; i < thetas.size(); ++i) {
+     cout << thetas[i] << "\t" << thetasEst1[i] << "\t" << thetasEst2[i] << endl;
+     double diff1 = abs(thetas[i] - thetasEst1[i]);
+     double diff2 = abs(thetas[i] - thetasEst2[i]);
+     if (diff1 > 0.2 || diff2 > 0.2)
+        return 1;
+  }
+
+  //-------------
+  delete tree;
+  delete modelSet;
+  delete rdist;
+
+  return 0;
+}
diff --git a/test/test_mapping.cpp b/test/test_mapping.cpp
new file mode 100644
index 0000000..94f5f00
--- /dev/null
+++ b/test/test_mapping.cpp
@@ -0,0 +1,296 @@
+//
+// File: test_mapping.cpp
+// Created by: Julien Dutheil
+// Created on: Thu Nov 25 16:02 2010
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for numerical calculus. This file is part of the Bio++ project.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Numeric/Prob/GammaDiscreteDistribution.h>
+#include <Bpp/Numeric/Prob/ConstantDistribution.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Seq/Alphabet/DNA.h>
+#include <Bpp/Seq/Io/Fasta.h>
+#include <Bpp/Phyl/TreeTemplate.h>
+#include <Bpp/Phyl/Model/Nucleotide/GTR.h>
+#include <Bpp/Phyl/Simulation/HomogeneousSequenceSimulator.h>
+#include <Bpp/Phyl/Likelihood/DRHomogeneousTreeLikelihood.h>
+#include <Bpp/Phyl/Mapping/SubstitutionRegister.h>
+#include <Bpp/Phyl/Mapping/SubstitutionCount.h>
+#include <Bpp/Phyl/Mapping/LaplaceSubstitutionCount.h>
+#include <Bpp/Phyl/Mapping/DecompositionSubstitutionCount.h>
+#include <Bpp/Phyl/Mapping/UniformizationSubstitutionCount.h>
+#include <Bpp/Phyl/Mapping/NaiveSubstitutionCount.h>
+#include <Bpp/Phyl/Mapping/ProbabilisticSubstitutionMapping.h>
+#include <Bpp/Phyl/Mapping/SubstitutionMappingTools.h>
+#include <iostream>
+
+using namespace bpp;
+using namespace std;
+
+int main() {
+  TreeTemplate<Node>* tree = TreeTemplateTools::parenthesisToTree("((A:0.001, B:0.002):0.008,C:0.01,D:0.1);");
+  vector<int> ids = tree->getNodesId();
+  ids.pop_back(); //Ignore root
+
+  //-------------
+
+  NucleicAlphabet* alphabet = new DNA();
+  ReversibleSubstitutionModel* model = new GTR(alphabet, 1, 0.2, 0.3, 0.4, 0.4, 0.1, 0.35, 0.35, 0.2);
+  MatrixTools::print(model->getGenerator());
+  //DiscreteDistribution* rdist = new GammaDiscreteDistribution(4, 0.4, 0.4);
+  DiscreteDistribution* rdist = new ConstantDistribution(1.0);
+  HomogeneousSequenceSimulator simulator(model, rdist, tree);
+  TotalSubstitutionRegister* totReg = new TotalSubstitutionRegister(alphabet);
+  ComprehensiveSubstitutionRegister* detReg = new ComprehensiveSubstitutionRegister(alphabet);
+
+  unsigned int n = 20000;
+  vector< vector<double> > realMap(n);
+  vector< vector< vector<double> > > realMapTotal(n);
+  vector< vector< vector<double> > > realMapDetailed(n);
+  VectorSiteContainer sites(tree->getLeavesNames(), alphabet);
+  for (unsigned int i = 0; i < n; ++i) {
+    ApplicationTools::displayGauge(i, n-1, '=');
+    auto_ptr<RASiteSimulationResult> result(simulator.dSimulate());
+    realMap[i].resize(ids.size());
+    realMapTotal[i].resize(ids.size());
+    realMapDetailed[i].resize(ids.size());
+    for (size_t j = 0; j < ids.size(); ++j) {
+      realMap[i][j] = static_cast<double>(result->getSubstitutionCount(ids[j]));
+      realMapTotal[i][j].resize(totReg->getNumberOfSubstitutionTypes());
+      realMapDetailed[i][j].resize(detReg->getNumberOfSubstitutionTypes());
+      result->getSubstitutionCount(ids[j], *totReg, realMapTotal[i][j]);
+      result->getSubstitutionCount(ids[j], *detReg, realMapDetailed[i][j]);
+      if (realMapTotal[i][j][0] != realMap[i][j]) {
+        cerr << "Error, total substitution register provides wrong result." << endl;
+        return 1;
+      }
+      if (abs(VectorTools::sum(realMapDetailed[i][j]) - realMap[i][j]) > 0.000001) {
+        cerr << "Error, detailed substitution register provides wrong result." << endl;
+        return 1;
+      }
+    }
+    auto_ptr<Site> site(result->getSite());
+    site->setPosition(i);
+    sites.addSite(*site, false);
+  }
+  ApplicationTools::displayTaskDone();
+  
+  //-------------
+  //Now build the substitution vectors with the true model:
+  //Fasta fasta;
+  //fasta.write("Simulations.fasta", sites);
+  DRHomogeneousTreeLikelihood drhtl(*tree, sites, model, rdist);
+  drhtl.initialize();
+  cout << drhtl.getValue() << endl;
+ 
+  SubstitutionCount* sCountAna = new LaplaceSubstitutionCount(model, 10);
+  Matrix<double>* m = sCountAna->getAllNumbersOfSubstitutions(0.001, 1);
+  cout << "Analytical total count:" << endl;
+  MatrixTools::print(*m);
+  delete m;
+  ProbabilisticSubstitutionMapping* probMapAna = 
+    SubstitutionMappingTools::computeSubstitutionVectors(drhtl, *sCountAna);
+
+  //Simple:
+  SubstitutionCount* sCountTot = new NaiveSubstitutionCount(totReg);
+  m = sCountTot->getAllNumbersOfSubstitutions(0.001,1);
+  cout << "Simple total count:" << endl;
+  MatrixTools::print(*m);
+  delete m;
+  ProbabilisticSubstitutionMapping* probMapTot = 
+    SubstitutionMappingTools::computeSubstitutionVectors(drhtl, *sCountTot);
+
+  SubstitutionCount* sCountDet = new NaiveSubstitutionCount(detReg);
+  m = sCountDet->getAllNumbersOfSubstitutions(0.001,1);
+  cout << "Detailed count, type 1:" << endl;
+  MatrixTools::print(*m);
+  delete m;
+  ProbabilisticSubstitutionMapping* probMapDet = 
+    SubstitutionMappingTools::computeSubstitutionVectors(drhtl, *sCountDet);
+
+  //Decomposition:
+  SubstitutionCount* sCountDecTot = new DecompositionSubstitutionCount(model, totReg);
+  m = sCountDecTot->getAllNumbersOfSubstitutions(0.001,1);
+  cout << "Total count, decomposition method:" << endl;
+  MatrixTools::print(*m);
+  delete m;
+  ProbabilisticSubstitutionMapping* probMapDecTot = 
+    SubstitutionMappingTools::computeSubstitutionVectors(drhtl, *sCountDecTot);
+
+  SubstitutionCount* sCountDecDet = new DecompositionSubstitutionCount(model, detReg);
+  m = sCountDecDet->getAllNumbersOfSubstitutions(0.001,1);
+  cout << "Detailed count, decomposition method, type 1:" << endl;
+  MatrixTools::print(*m);
+  delete m;
+  ProbabilisticSubstitutionMapping* probMapDecDet = 
+    SubstitutionMappingTools::computeSubstitutionVectors(drhtl, *sCountDecDet);
+
+  //Uniformization
+  SubstitutionCount* sCountUniTot = new UniformizationSubstitutionCount(model, totReg);
+  m = sCountUniTot->getAllNumbersOfSubstitutions(0.001,1);
+  cout << "Total count, uniformization method:" << endl;
+  MatrixTools::print(*m);
+  delete m;
+  ProbabilisticSubstitutionMapping* probMapUniTot = 
+    SubstitutionMappingTools::computeSubstitutionVectors(drhtl, *sCountUniTot);  
+
+  SubstitutionCount* sCountUniDet = new UniformizationSubstitutionCount(model, detReg);
+  m = sCountUniDet->getAllNumbersOfSubstitutions(0.001,1);
+  cout << "Detailed count, uniformization method, type 1:" << endl;
+  MatrixTools::print(*m);
+  delete m;
+  ProbabilisticSubstitutionMapping* probMapUniDet = 
+    SubstitutionMappingTools::computeSubstitutionVectors(drhtl, *sCountUniDet);
+
+  //Check saturation:
+  cout << "checking saturation..." << endl;
+  m = sCountUniDet->getAllNumbersOfSubstitutions(0.001,1);
+  cout << "Total count, uniformization method:" << endl;
+  MatrixTools::print(*m);
+  cout << MatrixTools::sumElements(*m) << endl;
+  delete m;
+  m = sCountUniDet->getAllNumbersOfSubstitutions(0.01,1);
+  cout << "Total count, uniformization method:" << endl;
+  MatrixTools::print(*m);
+  cout << MatrixTools::sumElements(*m) << endl;
+  delete m;
+  m = sCountUniDet->getAllNumbersOfSubstitutions(0.1,1);
+  cout << "Total count, uniformization method:" << endl;
+  MatrixTools::print(*m);
+  cout << MatrixTools::sumElements(*m) << endl;
+  delete m;
+  m = sCountUniDet->getAllNumbersOfSubstitutions(1,1);
+  cout << "Total count, uniformization method:" << endl;
+  MatrixTools::print(*m);
+  cout << MatrixTools::sumElements(*m) << endl;
+  delete m;
+  m = sCountUniDet->getAllNumbersOfSubstitutions(2,1);
+  cout << "Total count, uniformization method:" << endl;
+  MatrixTools::print(*m);
+  cout << MatrixTools::sumElements(*m) << endl;
+  delete m;
+  m = sCountUniDet->getAllNumbersOfSubstitutions(3,1);
+  cout << "Total count, uniformization method:" << endl;
+  MatrixTools::print(*m);
+  cout << MatrixTools::sumElements(*m) << endl;
+  delete m;
+  m = sCountUniDet->getAllNumbersOfSubstitutions(4,1);
+  cout << "Total count, uniformization method:" << endl;
+  MatrixTools::print(*m);
+  cout << MatrixTools::sumElements(*m) << endl;
+  delete m;
+  m = sCountUniDet->getAllNumbersOfSubstitutions(10,1);
+  cout << "Total count, uniformization method:" << endl;
+  MatrixTools::print(*m);
+  cout << MatrixTools::sumElements(*m) << endl;
+  delete m;
+
+
+
+  //Check per branch:
+  
+  //1. Total:
+  for (unsigned int j = 0; j < ids.size(); ++j) {
+    double totalReal = 0;
+    double totalObs1 = 0;
+    double totalObs2 = 0;
+    double totalObs3 = 0;
+    double totalObs4 = 0;
+    double totalObs5 = 0;
+    double totalObs6 = 0;
+    double totalObs7 = 0;
+    for (unsigned int i = 0; i < n; ++i) {
+      totalReal += realMap[i][j];
+      totalObs1 += probMapAna->getNumberOfSubstitutions(ids[j], i, 0);
+      totalObs2 += probMapTot->getNumberOfSubstitutions(ids[j], i, 0);
+      totalObs3 += VectorTools::sum(probMapDet->getNumberOfSubstitutions(ids[j], i));
+      totalObs4 += probMapDecTot->getNumberOfSubstitutions(ids[j], i, 0);
+      totalObs5 += VectorTools::sum(probMapDecDet->getNumberOfSubstitutions(ids[j], i));
+      totalObs6 += probMapUniTot->getNumberOfSubstitutions(ids[j], i, 0);
+      totalObs7 += VectorTools::sum(probMapUniDet->getNumberOfSubstitutions(ids[j], i));
+    }
+    if (tree->isLeaf(ids[j])) cout << tree->getNodeName(ids[j]) << "\t";
+    cout << tree->getDistanceToFather(ids[j]) << "\t" << totalReal << "\t" << totalObs1 << "\t" << totalObs2 << "\t" << totalObs3 << "\t" << totalObs4 << "\t" << totalObs5 << "\t" << totalObs6 << "\t" << totalObs7 << endl;
+    if (abs(totalReal - totalObs1) / totalReal > 0.1) return 1;
+    if (abs(totalReal - totalObs2) / totalReal > 0.1) return 1;
+    if (abs(totalReal - totalObs3) / totalReal > 0.1) return 1;
+    if (abs(totalReal - totalObs4) / totalReal > 0.1) return 1;
+    if (abs(totalReal - totalObs5) / totalReal > 0.1) return 1;
+    if (abs(totalReal - totalObs6) / totalReal > 0.1) return 1;
+    if (abs(totalReal - totalObs7) / totalReal > 0.1) return 1;
+  }
+  //2. Detail:
+  for (unsigned int j = 0; j < ids.size(); ++j) {
+    vector<double> real(4, 0);
+    vector<double> obs1(4, 0);
+    vector<double> obs2(4, 0);
+    vector<double> obs3(4, 0);
+    for (unsigned int i = 0; i < n; ++i) {
+      real += realMapDetailed[i][j];
+      //VectorTools::print(real);
+      vector<double> c = probMapDet->getNumberOfSubstitutions(ids[j], i);
+      //VectorTools::print(c);
+      obs1 += probMapDet->getNumberOfSubstitutions(ids[j], i);
+      obs2 += probMapDecDet->getNumberOfSubstitutions(ids[j], i);
+      obs3 += probMapUniDet->getNumberOfSubstitutions(ids[j], i);
+    }
+    if (tree->isLeaf(ids[j])) cout << tree->getNodeName(ids[j]) << "\t";
+    cout << tree->getDistanceToFather(ids[j]) << "\t";
+    for (unsigned int t = 0; t < 4; ++t) {
+      cout << obs1[t] << "/" << real[t] << "\t";
+      cout << obs2[t] << "/" << real[t] << "\t";
+      cout << obs3[t] << "/" << real[t] << "\t";
+    }
+    cout << endl;
+    //if (abs(totalReal - totalObs) / totalReal > 0.1) return 1;
+  }
+
+  //-------------
+  delete tree;
+  delete alphabet;
+  delete model;
+  delete rdist;
+  delete sCountTot;
+  delete sCountDet;
+  delete probMapTot;
+  delete probMapDet;
+  delete probMapDecTot;
+  delete probMapDecDet;
+  delete probMapUniTot;
+  delete probMapUniDet;
+  //return (abs(obs - 0.001) < 0.001 ? 0 : 1);
+  return 0;
+}
diff --git a/test/test_mapping_codon.cpp b/test/test_mapping_codon.cpp
new file mode 100644
index 0000000..c5286de
--- /dev/null
+++ b/test/test_mapping_codon.cpp
@@ -0,0 +1,229 @@
+//
+// File: test_mapping_codon.cpp
+// Created by: Julien Dutheil
+// Created on: Sat Mar 19 9:36 2011
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for numerical calculus. This file is part of the Bio++ project.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include <Bpp/App/ApplicationTools.h>
+#include <Bpp/Numeric/Prob/ConstantDistribution.h>
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+#include <Bpp/Seq/Alphabet/StandardCodonAlphabet.h>
+#include <Bpp/Seq/Io/Fasta.h>
+#include <Bpp/Seq/GeneticCode/StandardGeneticCode.h>
+#include <Bpp/Phyl/TreeTemplate.h>
+#include <Bpp/Phyl/Model/Nucleotide/JCnuc.h>
+#include <Bpp/Phyl/Model/Codon/CodonRateSubstitutionModel.h>
+#include <Bpp/Phyl/Model/FrequenciesSet/CodonFrequenciesSet.h>
+#include <Bpp/Phyl/Simulation/HomogeneousSequenceSimulator.h>
+#include <Bpp/Phyl/Likelihood/DRHomogeneousTreeLikelihood.h>
+#include <Bpp/Phyl/Mapping/SubstitutionRegister.h>
+#include <Bpp/Phyl/Mapping/NaiveSubstitutionCount.h>
+#include <Bpp/Phyl/Mapping/LaplaceSubstitutionCount.h>
+#include <Bpp/Phyl/Mapping/UniformizationSubstitutionCount.h>
+#include <Bpp/Phyl/Mapping/DecompositionSubstitutionCount.h>
+#include <Bpp/Phyl/Mapping/ProbabilisticSubstitutionMapping.h>
+#include <Bpp/Phyl/Mapping/SubstitutionMappingTools.h>
+#include <iostream>
+
+using namespace bpp;
+using namespace std;
+
+int main() {
+  TreeTemplate<Node>* tree = TreeTemplateTools::parenthesisToTree("((A:0.001, B:0.002):0.008,C:0.01,D:0.1);");
+  vector<int> ids = tree->getNodesId();
+  ids.pop_back(); //Ignore root
+
+  //-------------
+
+  CodonAlphabet* alphabet = new StandardCodonAlphabet(&AlphabetTools::DNA_ALPHABET);
+  GeneticCode* gc = new StandardGeneticCode(&AlphabetTools::DNA_ALPHABET);
+  //SubstitutionModel* model = new YN98(gc, CodonFrequenciesSet::getFrequenciesSetForCodons(CodonFrequenciesSet::F0, *alphabet));
+  SubstitutionModel* model = new CodonRateSubstitutionModel(
+        dynamic_cast<const CodonAlphabet*>(gc->getSourceAlphabet()),
+        new JCnuc(dynamic_cast<CodonAlphabet*>(alphabet)->getNucleicAlphabet()));
+  MatrixTools::printForR(model->getGenerator(), "g");
+  DiscreteDistribution* rdist = new ConstantDistribution(1.0);
+  HomogeneousSequenceSimulator simulator(model, rdist, tree);
+  TotalSubstitutionRegister* totReg = new TotalSubstitutionRegister(alphabet);
+  DnDsSubstitutionRegister* dndsReg = new DnDsSubstitutionRegister(gc);
+
+  unsigned int n = 20000;
+  vector< vector<double> > realMap(n);
+  vector< vector< vector<double> > > realMapTotal(n);
+  vector< vector< vector<double> > > realMapDnDs(n);
+  VectorSiteContainer sites(tree->getLeavesNames(), alphabet);
+  for (unsigned int i = 0; i < n; ++i) {
+    ApplicationTools::displayGauge(i, n-1, '=');
+    RASiteSimulationResult* result = simulator.dSimulate();
+    realMap[i].resize(ids.size());
+    realMapTotal[i].resize(ids.size());
+    realMapDnDs[i].resize(ids.size());
+    for (size_t j = 0; j < ids.size(); ++j) {
+      realMap[i][j] = static_cast<double>(result->getSubstitutionCount(ids[j]));
+      realMapTotal[i][j].resize(totReg->getNumberOfSubstitutionTypes());
+      realMapDnDs[i][j].resize(dndsReg->getNumberOfSubstitutionTypes());
+      result->getSubstitutionCount(ids[j], *totReg, realMapTotal[i][j]);
+      result->getSubstitutionCount(ids[j], *dndsReg, realMapDnDs[i][j]);
+      if (realMapTotal[i][j][0] != realMap[i][j]) {
+        cerr << "Error, total substitution register provides wrong result." << endl;
+        return 1;
+      }
+      //if (abs(VectorTools::sum(realMapDetailed[i][j]) - realMap[i][j]) > 0.000001) {
+      //  cerr << "Error, detailed substitution register provides wrong result." << endl;
+      //  return 1;
+      //}
+    }
+    auto_ptr<Site> site(result->getSite());
+    site->setPosition(i);
+    sites.addSite(*site, false);
+    delete result;
+  }
+  ApplicationTools::displayTaskDone();
+  
+  //-------------
+  //Now build the substitution vectors with the true model:
+  //Fasta fasta;
+  //fasta.write("Simulations.fasta", sites);
+  DRHomogeneousTreeLikelihood drhtl(*tree, sites, model, rdist);
+  drhtl.initialize();
+  cout << drhtl.getValue() << endl;
+ 
+  SubstitutionCount* sCountAna = new LaplaceSubstitutionCount(model, 10);
+  Matrix<double>* m = sCountAna->getAllNumbersOfSubstitutions(0.001,1);
+  cout << "Analytical total count:" << endl;
+  MatrixTools::print(*m);
+  delete m;
+  ProbabilisticSubstitutionMapping* probMapAna = 
+    SubstitutionMappingTools::computeSubstitutionVectors(drhtl, *sCountAna);
+
+  SubstitutionCount* sCountTot = new NaiveSubstitutionCount(totReg);
+  m = sCountTot->getAllNumbersOfSubstitutions(0.001,1);
+  cout << "Simple total count:" << endl;
+  MatrixTools::print(*m);
+  delete m;
+  ProbabilisticSubstitutionMapping* probMapTot = 
+    SubstitutionMappingTools::computeSubstitutionVectors(drhtl, *sCountTot);
+
+  SubstitutionCount* sCountDnDs = new NaiveSubstitutionCount(dndsReg);
+  m = sCountDnDs->getAllNumbersOfSubstitutions(0.001,1);
+  cout << "Detailed count, type 1:" << endl;
+  MatrixTools::print(*m);
+  delete m;
+  ProbabilisticSubstitutionMapping* probMapDnDs = 
+    SubstitutionMappingTools::computeSubstitutionVectors(drhtl, *sCountDnDs);
+
+  SubstitutionCount* sCountUniTot = new UniformizationSubstitutionCount(model, totReg);
+  m = sCountUniTot->getAllNumbersOfSubstitutions(0.001,1);
+  cout << "Total count, uniformization method:" << endl;
+  MatrixTools::print(*m);
+  delete m;
+  ProbabilisticSubstitutionMapping* probMapUniTot = 
+    SubstitutionMappingTools::computeSubstitutionVectors(drhtl, *sCountUniTot);
+
+  SubstitutionCount* sCountUniDnDs = new UniformizationSubstitutionCount(model, dndsReg);
+  m = sCountUniDnDs->getAllNumbersOfSubstitutions(0.001,2);
+  cout << "Detailed count, uniformization method, type 2:" << endl;
+  MatrixTools::print(*m);
+  delete m;
+  ProbabilisticSubstitutionMapping* probMapUniDnDs = 
+    SubstitutionMappingTools::computeSubstitutionVectors(drhtl, *sCountUniDnDs);
+
+  //Check per branch:
+  
+  /*
+  //1. Total:
+  for (unsigned int j = 0; j < ids.size(); ++j) {
+    double totalReal = 0;
+    double totalObs1 = 0;
+    double totalObs2 = 0;
+    double totalObs3 = 0;
+    double totalObs4 = 0;
+    double totalObs5 = 0;
+    for (unsigned int i = 0; i < n; ++i) {
+      totalReal += realMap[i][j];
+      totalObs1 += probMapAna->getNumberOfSubstitutions(ids[j], i, 0);
+      totalObs2 += probMapTot->getNumberOfSubstitutions(ids[j], i, 0);
+      //totalObs3 += VectorTools::sum(probMapDet->getNumberOfSubstitutions(ids[j], i));
+      totalObs4 += probMapDecTot->getNumberOfSubstitutions(ids[j], i, 0);
+      //totalObs5 += VectorTools::sum(probMapDecDet->getNumberOfSubstitutions(ids[j], i));
+    }
+    if (tree->isLeaf(ids[j])) cout << tree->getNodeName(ids[j]) << "\t";
+    cout << tree->getDistanceToFather(ids[j]) << "\t" << totalReal << "\t" << totalObs1 << "\t" << totalObs2 << "\t" << totalObs3 << "\t" << totalObs4 << "\t" << totalObs5 << endl;
+    if (abs(totalReal - totalObs1) / totalReal > 0.1) return 1;
+    if (abs(totalReal - totalObs2) / totalReal > 0.1) return 1;
+    if (abs(totalReal - totalObs3) / totalReal > 0.1) return 1;
+    if (abs(totalReal - totalObs4) / totalReal > 0.1) return 1;
+  }
+  //2. Detail:
+  for (unsigned int j = 0; j < ids.size(); ++j) {
+    vector<double> real(4, 0);
+    vector<double> obs1(4, 0);
+    vector<double> obs2(4, 0);
+    for (unsigned int i = 0; i < n; ++i) {
+      real += realMapDetailed[i][j];
+      //VectorTools::print(real);
+      //vector<double> c = probMapDet->getNumberOfSubstitutions(ids[j], i);
+      //VectorTools::print(c);
+      //obs1 += probMapDet->getNumberOfSubstitutions(ids[j], i);
+      //obs2 += probMapDecDet->getNumberOfSubstitutions(ids[j], i);
+    }
+    if (tree->isLeaf(ids[j])) cout << tree->getNodeName(ids[j]) << "\t";
+    cout << tree->getDistanceToFather(ids[j]) << "\t";
+    for (unsigned int t = 0; t < 4; ++t) {
+      cout << obs1[t] << "/" << real[t] << "\t";
+      cout << obs2[t] << "/" << real[t] << "\t";
+    }
+    cout << endl;
+    //if (abs(totalReal - totalObs) / totalReal > 0.1) return 1;
+  }
+  */
+
+  //-------------
+  delete tree;
+  delete alphabet;
+  delete model;
+  delete rdist;
+  delete sCountTot;
+  delete sCountDnDs;
+  delete probMapAna;
+  delete probMapTot;
+  delete probMapDnDs;
+  delete probMapUniTot;
+  delete probMapUniDnDs;
+  //return (abs(obs - 0.001) < 0.001 ? 0 : 1);
+  return 0;
+}
diff --git a/test/test_models.cpp b/test/test_models.cpp
new file mode 100644
index 0000000..052f0d6
--- /dev/null
+++ b/test/test_models.cpp
@@ -0,0 +1,128 @@
+//
+// File: test_models.cpp
+// Created by: Julien Dutheil
+// Created on: Tue Jan 22 22:18 2013
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for numerical calculus. This file is part of the Bio++ project.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include <Bpp/Phyl/Model/Nucleotide/GTR.h>
+#include <Bpp/Phyl/Model/Codon/YN98.h>
+#include <Bpp/Phyl/Model/FrequenciesSet/CodonFrequenciesSet.h>
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+#include <Bpp/Seq/Alphabet/StandardCodonAlphabet.h>
+#include <Bpp/Seq/GeneticCode/StandardGeneticCode.h>
+#include <Bpp/Numeric/Function/Functions.h>
+#include <Bpp/Numeric/Function/ReparametrizationFunctionWrapper.h>
+#include <Bpp/Numeric/ParameterList.h>
+#include <Bpp/Numeric/AbstractParametrizable.h>
+#include <Bpp/Numeric/Random/RandomTools.h>
+#include <iostream>
+
+using namespace bpp;
+using namespace std;
+
+class DummyFunction:
+  public virtual Function,
+  public AbstractParametrizable
+{
+  public:
+    DummyFunction(const SubstitutionModel& model):
+      AbstractParametrizable("")
+    {
+      addParameters_(model.getParameters());
+    }
+
+    DummyFunction* clone() const { return new DummyFunction(*this); }
+
+    void setParameters(const ParameterList& pl) throw (bpp::ParameterNotFoundException
+, bpp::ConstraintException, bpp::Exception) {
+      matchParametersValues(pl);
+    }
+
+    double getValue() const throw (Exception) { return 0; }
+
+    void fireParameterChanged(const bpp::ParameterList&) {}
+
+};
+
+bool testModel(SubstitutionModel& model) {
+  ParameterList pl = model.getParameters();
+  DummyFunction df(model);
+  ReparametrizationFunctionWrapper redf(&df, pl, false);
+
+  //Try to modify randomly each parameter and check that the new parameter apply correctly:
+  for (unsigned int i = 0; i < 10; ++i) {
+    //Get random parameters (unconstrained):
+    ParameterList pl2 = redf.getParameters();
+    for (size_t j = 0; j < pl.size(); ++j) {
+      double value = (RandomTools::flipCoin() ? 1. : -1) * RandomTools::giveRandomNumberBetweenZeroAndEntry(1);
+      pl2[j].setValue(value);
+    }
+    //Apply unconstrained parameters:
+    redf.setParameters(pl2);
+    //Retrieve transformed parameters:
+    pl2 = df.getParameters();
+    //pl2.printParameters(cout);
+    //Now apply the new parameters and retrieve them again:
+    model.matchParametersValues(pl2);
+    ParameterList pl3 = model.getParameters();
+    //Compare the two lists:
+    for (size_t j = 0; j < pl.size(); ++j) {
+      if (abs(pl2[j].getValue() - pl3[j].getValue()) > 0.0000001) {
+        cerr << "ERROR for parameter " << pl2[j].getName() << ": " << pl2[j].getValue() << "<>" << pl3[j].getValue() << endl;
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+int main() {
+  //Nucleotide models:
+  GTR gtr(&AlphabetTools::DNA_ALPHABET);
+  if (!testModel(gtr)) return 1;
+
+  //Codon models:
+  StandardGeneticCode gc(&AlphabetTools::DNA_ALPHABET);
+  const CodonAlphabet* codonAlphabet = new StandardCodonAlphabet(&AlphabetTools::DNA_ALPHABET);
+  FrequenciesSet* fset = CodonFrequenciesSet::getFrequenciesSetForCodons(CodonFrequenciesSet::F3X4, *codonAlphabet);
+  YN98 yn98(&gc, fset);
+  if (!testModel(yn98)) return 1;
+
+  delete codonAlphabet;
+
+  return 0;
+}
diff --git a/test/test_nhx.cpp b/test/test_nhx.cpp
new file mode 100644
index 0000000..6ecd18c
--- /dev/null
+++ b/test/test_nhx.cpp
@@ -0,0 +1,82 @@
+//
+// File: test_nhx.cpp
+// Created by: Julien Dutheil
+// Created on: Fri Dec 31 15:43 2010
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for numerical calculus. This file is part of the Bio++ project.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include <Bpp/Phyl/TreeTemplate.h>
+#include <Bpp/Phyl/TreeTemplateTools.h>
+#include <Bpp/Phyl/Io/Nhx.h>
+#include <string>
+#include <vector>
+#include <iostream>
+
+using namespace bpp;
+using namespace std;
+
+int main() {
+  //Get some leaf names:
+  vector<string> leaves(5);
+  for (size_t i = 0; i < leaves.size(); ++i)
+    leaves[i] = "leaf" + TextTools::toString(i);
+  
+  //Generate a random tree, without branch lengths:
+  TreeTemplate<Node>* tree = TreeTemplateTools::getRandomTree(leaves, true);
+
+  //Now assign random properties:
+  vector<Node*> nodes = tree->getNodes();
+  for (size_t i = 0; i < nodes.size(); ++i) {
+    nodes[i]->setDistanceToFather(RandomTools::giveRandomNumberBetweenZeroAndEntry(1.0));
+    nodes[i]->setNodeProperty("GN", BppString("Gene" + TextTools::toString(i)));
+    nodes[i]->setNodeProperty("AC", BppString("XXXXXX"));
+    nodes[i]->setBranchProperty("B", Number<double>(floor(RandomTools::giveRandomNumberBetweenZeroAndEntry(100.) + 0.5)));
+    nodes[i]->setBranchProperty("W", Number<int>(static_cast<int>(floor(RandomTools::giveRandomNumberBetweenZeroAndEntry(5.) + 0.5))));
+  }
+  
+  //Convert tree to string and read it again:
+  Nhx nhxParser(true);
+  ofstream out("randomTree.nhx", ios::out);
+  nhxParser.write(*tree, out);
+  out.close();
+  TreeTemplate<Node>* tree2 = nhxParser.read("randomTree.nhx");
+  ofstream out2("randomTree2.nhx", ios::out);
+  nhxParser.write(*tree2, out2);
+  out2.close();
+
+  delete tree;
+  delete tree2;
+  return 0;
+}
diff --git a/test/test_parsimony.cpp b/test/test_parsimony.cpp
new file mode 100644
index 0000000..b9f988f
--- /dev/null
+++ b/test/test_parsimony.cpp
@@ -0,0 +1,69 @@
+//
+// File: test_parsimony.cpp
+// Created by: Julien Dutheil
+// Created on: Wed 03/10 16:47 2012
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for numerical calculus. This file is part of the Bio++ project.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+#include <Bpp/Seq/Io/Phylip.h>
+#include <Bpp/Phyl/Tree.h>
+#include <Bpp/Phyl/Io/Newick.h>
+#include <Bpp/Phyl/Parsimony/DRTreeParsimonyScore.h>
+#include <iostream>
+
+using namespace bpp;
+using namespace std;
+
+int main() {
+  try {
+    Newick treeReader;
+    auto_ptr<Tree> tree(treeReader.read("example1.mp.dnd"));
+    Phylip alnReader(false, false);
+    auto_ptr<SiteContainer> sites(alnReader.readAlignment("example1.ph", &AlphabetTools::DNA_ALPHABET));
+
+    DRTreeParsimonyScore pars(*tree, *sites, true, true);
+  
+    cout << "Parsimony score: " << pars.getScore() << endl;
+
+    if (pars.getScore() != 9) return 1;
+    
+  } catch (Exception& ex) {
+    cerr << ex.what() << endl;
+    return 1;
+  }  
+
+  return 0;
+}
diff --git a/test/test_simulations.cpp b/test/test_simulations.cpp
new file mode 100644
index 0000000..f0d78f7
--- /dev/null
+++ b/test/test_simulations.cpp
@@ -0,0 +1,147 @@
+//
+// File: test_simulations.cpp
+// Created by: Julien Dutheil
+// Created on: Fri Jan 21 17:21 2011
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for numerical calculus. This file is part of the Bio++ project.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include <Bpp/Numeric/Matrix/MatrixTools.h>
+#include <Bpp/Seq/Alphabet/AlphabetTools.h>
+#include <Bpp/Phyl/TreeTemplate.h>
+#include <Bpp/Phyl/Model/Nucleotide/T92.h>
+#include <Bpp/Phyl/Model/FrequenciesSet/NucleotideFrequenciesSet.h>
+#include <Bpp/Phyl/Model/RateDistribution/ConstantRateDistribution.h>
+#include <Bpp/Phyl/Model/RateDistribution/GammaDiscreteRateDistribution.h>
+#include <Bpp/Phyl/Model/SubstitutionModelSetTools.h>
+#include <Bpp/Phyl/Simulation/HomogeneousSequenceSimulator.h>
+#include <Bpp/Phyl/Likelihood/RNonHomogeneousTreeLikelihood.h>
+#include <Bpp/Phyl/OptimizationTools.h>
+#include <iostream>
+
+using namespace bpp;
+using namespace std;
+
+int main() {
+  TreeTemplate<Node>* tree = TreeTemplateTools::parenthesisToTree("((A:0.01, B:0.02):0.03,C:0.01,D:0.1);");
+  vector<string> seqNames= tree->getLeavesNames();
+  vector<int> ids = tree->getNodesId();
+  //-------------
+
+  NucleicAlphabet* alphabet = new DNA();
+  SubstitutionModel* model = new T92(alphabet, 3.);
+  FrequenciesSet* rootFreqs = new GCFrequenciesSet(alphabet);
+  std::vector<std::string> globalParameterNames;
+  globalParameterNames.push_back("T92.kappa");
+  SubstitutionModelSet* modelSet = SubstitutionModelSetTools::createNonHomogeneousModelSet(model, rootFreqs, tree, globalParameterNames);
+  DiscreteDistribution* rdist = new ConstantRateDistribution();
+  vector<double> thetas;
+  for (unsigned int i = 0; i < modelSet->getNumberOfModels(); ++i) {
+    double theta = RandomTools::giveRandomNumberBetweenZeroAndEntry(0.99) + 0.005;
+    cout << "Theta" << i << " set to " << theta << endl; 
+    modelSet->setParameterValue("T92.theta_" + TextTools::toString(i + 1), theta);
+    thetas.push_back(theta);
+  }
+  NonHomogeneousSequenceSimulator simulator(modelSet, rdist, tree);
+
+  unsigned int n = 100000;
+  OutputStream* profiler  = new StlOutputStream(new ofstream("profile.txt", ios::out));
+  OutputStream* messenger = new StlOutputStream(new ofstream("messages.txt", ios::out));
+
+  //Check fast simulation first:
+  
+  //Generate data set:
+  VectorSiteContainer sites(seqNames, alphabet);
+  for (unsigned int i = 0; i < n; ++i) {
+    auto_ptr<Site> site(simulator.simulate());
+    site->setPosition(i);
+    sites.addSite(*site, false);
+  }
+
+  //Now fit model:
+  SubstitutionModelSet* modelSet2 = modelSet->clone();
+  RNonHomogeneousTreeLikelihood tl(*tree, sites, modelSet2, rdist);
+  tl.initialize();
+
+  OptimizationTools::optimizeNumericalParameters2(
+      &tl, tl.getParameters(), 0,
+      0.0001, 10000, messenger, profiler, false, false, 1, OptimizationTools::OPTIMIZATION_NEWTON);
+
+  //Now compare estimated values to real ones:
+  for (size_t i = 0; i < thetas.size(); ++i) {
+    cout << thetas[i] << "\t" << modelSet2->getModel(i)->getParameter("theta").getValue() << endl;
+    double diff = abs(thetas[i] - modelSet2->getModel(i)->getParameter("theta").getValue());
+    if (diff > 0.1)
+      return 1;
+  }
+  delete modelSet2;
+
+  //Now try detailed simulations:
+
+  //Generate data set:
+  VectorSiteContainer sites2(seqNames, alphabet);
+  for (unsigned int i = 0; i < n; ++i) {
+    RASiteSimulationResult* result = simulator.dSimulate();
+    auto_ptr<Site> site(result->getSite());
+    site->setPosition(i);
+    sites2.addSite(*site, false);
+    delete result;
+  }
+
+  //Now fit model:
+  SubstitutionModelSet* modelSet3 = modelSet->clone();
+  RNonHomogeneousTreeLikelihood tl2(*tree, sites2, modelSet3, rdist);
+  tl2.initialize();
+
+  OptimizationTools::optimizeNumericalParameters2(
+      &tl2, tl2.getParameters(), 0,
+      0.0001, 10000, messenger, profiler, false, false, 1, OptimizationTools::OPTIMIZATION_NEWTON);
+
+  //Now compare estimated values to real ones:
+  for (size_t i = 0; i < thetas.size(); ++i) {
+    cout << thetas[i] << "\t" << modelSet3->getModel(i)->getParameter("theta").getValue() << endl;
+    double diff = abs(thetas[i] - modelSet3->getModel(i)->getParameter("theta").getValue());
+    if (diff > 0.1)
+      return 1;
+  }
+  delete modelSet3;
+
+  //-------------
+  delete tree;
+  delete alphabet;
+  delete modelSet;
+  delete rdist;
+
+  return 0;
+}
diff --git a/test/test_tree.cpp b/test/test_tree.cpp
new file mode 100644
index 0000000..3e3e8ef
--- /dev/null
+++ b/test/test_tree.cpp
@@ -0,0 +1,245 @@
+//
+// File: test_tree.cpp
+// Created by: Julien Dutheil
+// Created on: Sun Nov 14 10:20 2010
+//
+
+/*
+Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
+
+This software is a computer program whose purpose is to provide classes
+for numerical calculus. This file is part of the Bio++ project.
+
+This software is governed by the CeCILL  license under French law and
+abiding by the rules of distribution of free software.  You can  use, 
+modify and/ or redistribute the software under the terms of the CeCILL
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info". 
+
+As a counterpart to the access to the source code and  rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty  and the software's author,  the holder of the
+economic rights,  and the successive licensors  have only  limited
+liability. 
+
+In this respect, the user's attention is drawn to the risks associated
+with loading,  using,  modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean  that it is complicated to manipulate,  and  that  also
+therefore means  that it is reserved for developers  and  experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or 
+data to be ensured and,  more generally, to use and operate it in the 
+same conditions as regards security. 
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL license and that you accept its terms.
+*/
+
+#include <Bpp/Phyl/TreeTemplate.h>
+#include <Bpp/Phyl/TreeTemplateTools.h>
+#include <Bpp/Phyl/Io/Newick.h>
+#include <string>
+#include <vector>
+#include <iostream>
+
+using namespace bpp;
+using namespace std;
+
+int main() {
+  //Get some leaf names:
+  vector<string> leaves(100);
+  for (size_t i = 0; i < leaves.size(); ++i)
+    leaves[i] = "leaf" + TextTools::toString(i);
+  
+  for (unsigned int j = 0; j < 1000; ++j) {
+    //Generate a random tree, without branch lengths:
+    TreeTemplate<Node>* tree = TreeTemplateTools::getRandomTree(leaves, true);
+    TreeTemplate<Node>* tree2 = new TreeTemplate<Node>(*tree);
+    if (!tree->hasSameTopologyAs(*tree2))
+      return 1; //Error!!!
+    tree2->getRootNode()->swap(0,1);
+    //cout << "First test passed." << endl;
+    if (!tree->hasSameTopologyAs(*tree2))
+      return 1; //Error!!!
+    //cout << "Second test passed." << endl;
+  
+    //Convert tree to string and read it again:
+    string newick = TreeTemplateTools::treeToParenthesis(*tree);
+    TreeTemplate<Node>* tree3 = TreeTemplateTools::parenthesisToTree(newick);
+    if (!tree->hasSameTopologyAs(*tree3))
+      return 1; //Error!!!
+    //cout << "Third test passed." << endl;
+    
+    //-------------
+    delete tree;
+    delete tree2;
+    delete tree3;
+  }
+
+  //Try to parse a string:
+  TreeTemplate<Node>* tree4 = TreeTemplateTools::parenthesisToTree("((A:1,B:2):3,C:4);");
+  cout << TreeTemplateTools::treeToParenthesis(*tree4) << endl;
+  delete tree4;
+
+  TreeTemplate<Node>* tree5 = TreeTemplateTools::parenthesisToTree("((A:1,B:2):3,C:4):5;");
+  cout << TreeTemplateTools::treeToParenthesis(*tree5) << endl;
+  delete tree5;
+
+  Newick tReader;
+  istringstream iss6("((A,B),C);");
+  TreeTemplate<Node>* tree6 = tReader.read(iss6);
+  cout << TreeTemplateTools::treeToParenthesis(*tree6) << endl;
+  delete tree6;
+  
+  istringstream iss7("((A:1,B:2):3,C:4):5;");
+  TreeTemplate<Node>* tree7 = tReader.read(iss7);
+  cout << TreeTemplateTools::treeToParenthesis(*tree7) << endl;
+  delete tree7;
+
+  istringstream iss8("((A,B)aa,C)2;");
+  tReader.enableExtendedBootstrapProperty("ESS");
+  TreeTemplate<Node>* tree8 = tReader.read(iss8);
+  cout << TreeTemplateTools::treeToParenthesis(*tree8) << endl;
+  vector<int> ids = tree8->getNodesId();
+  for (size_t i = 0; i < ids.size(); ++i) {
+    cout << "Node " << ids[i] << ":" << endl;
+    vector<string> nodePpt = tree8->getNode(ids[i])->getNodePropertyNames();
+    for (size_t j = 0; j < nodePpt.size(); ++j)
+      if (tree8->getNode(ids[i])->hasNodeProperty(nodePpt[j]))
+        cout << "N: " << nodePpt[j] << "=" << dynamic_cast<BppString*>(tree8->getNode(ids[i])->getNodeProperty(nodePpt[j]))->toSTL() << endl;
+    vector<string> branchPpt = tree8->getNode(ids[i])->getBranchPropertyNames();
+    for (size_t j = 0; j < branchPpt.size(); ++j)
+      if (tree8->getNode(ids[i])->hasBranchProperty(branchPpt[j]))
+        cout << "B: " << branchPpt[j] << "=" << dynamic_cast<BppString*>(tree8->getNode(ids[i])->getBranchProperty(branchPpt[j]))->toSTL() << endl;
+  }
+  delete tree8;
+
+  //Test file parsing:
+  TreeTemplate<Node>* tree9 = TreeTemplateTools::getRandomTree(leaves, true);
+  Newick tWriter;
+  tWriter.write(*tree9, "tmp_tree.dnd");
+  Tree* test = tReader.read("tmp_tree.dnd");
+  if (!TreeTools::haveSameTopology(*tree9, *test))
+    return 1;
+  cout << "Newick I/O ok." << endl;
+
+  //Multiple trees:
+  vector<Tree *> trees;
+  for (unsigned int i = 0; i < 100; ++i) {
+    trees.push_back(TreeTemplateTools::getRandomTree(leaves, true));
+  }
+  tWriter.write(trees, "tmp_trees.dnd");
+
+  vector<Tree *> trees2;
+  tReader.read("tmp_trees.dnd", trees2);
+
+  for (unsigned int i = 0; i < 100; ++i) {
+    if (!TreeTools::haveSameTopology(*trees[i], *trees2[i]))
+    {
+      cerr << "Tree " << i << " failed to write and/or read!" << endl;
+      return 1;
+    }
+  }
+  cout << "Newick multiple I/O ok." << endl;
+
+  for (unsigned int i = 0; i < 100; ++i) {
+    delete trees[i];
+    delete trees2[i];
+  }
+
+  //Try newick read on non-file:
+  cout << "Testing parsing a directory..." << endl;
+  try {
+    Tree* tmp = tReader.read("test/");
+    cerr << "Arg, reading on directory should fail!" << endl;
+    if (tmp != NULL) {
+      cerr << "Output of read on directory is not NULL!" << endl;
+    }
+    return 1;
+  } catch(Exception& ex) {
+    cout << "Ok, reading on directory throws exception!" << endl;
+  }
+
+  cout << "Testing parsing a directory for multiple trees..." << endl;
+  try {
+    vector<Tree*> treesTmp;
+    tReader.read("test/", treesTmp);
+    if (treesTmp.size() != 0) {
+      cerr << "Output of multiple read on directory is not 0!" << endl;
+      return 1;
+    } else {
+      cout << "Ok, reading on directory returns a vector of size 0!" << endl;
+    }
+  } catch(Exception& ex) {
+    cout << "Error, no exception should be thrown here!" << endl;
+  }
+
+  //Now try some weird cases, to see if we handle them properly:
+  //single node tree:
+  cout << "Testing a tree with a node of degree 2:" << endl;
+  TreeTemplate<Node>* weird1 = TreeTemplateTools::parenthesisToTree("((A:1):2.0,B);");
+  if (weird1->getNodes().size() != 4) {
+    cout << "Error, tree has " << weird1->getNodes().size() << " node(s) instead of 4!" << endl;
+    VectorTools::print(weird1->getLeavesNames());
+    return 1;
+  }
+  cout << TreeTemplateTools::treeToParenthesis(*weird1) << endl;
+  delete weird1;
+
+  cout << "Testing a tree with a node of degree 2, without branch length:" << endl;
+  TreeTemplate<Node>* weird2 = TreeTemplateTools::parenthesisToTree("((A),B);");
+  if (weird2->getNodes().size() != 4) {
+    cout << "Error, tree has " << weird2->getNodes().size() << " node(s) instead of 4!" << endl;
+    VectorTools::print(weird2->getLeavesNames());
+    return 1;
+  }
+  cout << TreeTemplateTools::treeToParenthesis(*weird2) << endl;
+  delete weird2;
+
+  cout << "Testing a tree with several single nodes:" << endl;
+  TreeTemplate<Node>* weird3 = TreeTemplateTools::parenthesisToTree("((((((A)):1)):3),B);");
+  if (weird3->getNodes().size() != 8) {
+    cout << "Error, tree has " << weird3->getNodes().size() << " node(s) instead of 8!" << endl;
+    VectorTools::print(weird3->getLeavesNames());
+    return 1;
+  }
+  cout << TreeTemplateTools::treeToParenthesis(*weird3) << endl;
+  delete weird3;
+
+  cout << "Testing a tree with a single leaf:" << endl;
+  TreeTemplate<Node>* weird4 = TreeTemplateTools::parenthesisToTree("(A:1.0);");
+  if (weird4->getNodes().size() != 2) {
+    cout << "Error, tree has " << weird4->getNodes().size() << " node(s) instead of 2!" << endl;
+    VectorTools::print(weird4->getLeavesNames());
+    return 1;
+  }
+  cout << TreeTemplateTools::treeToParenthesis(*weird4) << endl;
+  delete weird4;
+
+  cout << "Testing a tree with a single node:" << endl;
+  TreeTemplate<Node>* weird5 = TreeTemplateTools::parenthesisToTree("((A:1.0));");
+  if (weird5->getNodes().size() != 3) {
+    cout << "Error, tree has " << weird5->getNodes().size() << " node(s) instead of 3!" << endl;
+    VectorTools::print(weird5->getLeavesNames());
+    return 1;
+  }
+  cout << TreeTemplateTools::treeToParenthesis(*weird5) << endl;
+  delete weird5;
+
+  cout << "Testing a tree with a single node and branch lengths:" << endl;
+  TreeTemplate<Node>* weird6 = TreeTemplateTools::parenthesisToTree("((A:1.0):2.0);");
+  if (weird6->getNodes().size() != 3) {
+    cout << "Error, tree has " << weird6->getNodes().size() << " node(s) instead of 3!" << endl;
+    VectorTools::print(weird6->getLeavesNames());
+    return 1;
+  }
+  cout << TreeTemplateTools::treeToParenthesis(*weird6) << endl;
+  delete weird6;
+
+
+
+
+  return 0;
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/libbpp-phyl.git



More information about the debian-med-commit mailing list