1 changed files with 158 additions and 0 deletions
			
			
		| @ -0,0 +1,158 @@ | |||
| #include <vector> | |||
| #include <tuple> | |||
| #include <cmath> | |||
| 
 | |||
| #include "src/utility/macros.h" | |||
| #include "src/utility/ConstantsComparator.h" | |||
| #include "src/exceptions/InvalidArgumentException.h" | |||
| 
 | |||
| namespace storm { | |||
|     namespace utility { | |||
|         namespace numerical { | |||
|             template<typename ValueType> | |||
|             std::tuple<uint_fast64_t, uint_fast64_t, ValueType, std::vector<ValueType>> getFoxGlynnCutoff(ValueType lambda, ) { | |||
|                 storm::utility::ConstantsComparator<ValueType> comparator; | |||
|                  | |||
|                 ValueType underflow, overflow, accuracy = 0; | |||
|                  | |||
|                 STORM_LOG_THROW(!comparator.isZero(lambda), storm::exceptions::InvalidArgumentException, "Error in Fox-Glynn algorithm: lambda must not be zero."); | |||
|                  | |||
|                 // This code is more or less taken from PRISM. According to their implementation, for lambda smaller than | |||
|                 // 400, we compute the result using the naive method. | |||
|                 if (lambda < 400) { | |||
|                     ValueType eToPowerMinusLambda = std::exp(-lambda); | |||
|                     ValueType targetValue = (1 - (this->accuracy / 2.0)) / eToPowerMinusLambda; | |||
|                     std::vector<ValueType> weights; | |||
|                      | |||
|                     ValueType exactlyKEvents = 1; | |||
|                     ValueType atMostKEvents = exactlyKEvents; | |||
|                     weights.push_back(exactlyKEvents * eToPowerMinusLambda); | |||
|                      | |||
|                     uint_fast64_t currentK = 1; | |||
|                     do { | |||
|                         exactlyKEvents *= lambda / k; | |||
|                         atMostKEvents += exactlyKEvents; | |||
|                         weights.push_back(exactlyKEvents * eToPowerMinusLambda); | |||
|                         ++k; | |||
|                     } while (atMostKEvents < targetValue); | |||
|                      | |||
|                     return std::make_tuple(0, k - 1, 1.0, weights); | |||
|                 } else { | |||
|                     STORM_LOG_THROW(accuracy >= 1e-10, storm::exceptions::InvalidArgumentException, "Error in Fox-Glynn algorithm: the accuracy must not be below 1e-10."); | |||
|                      | |||
|                     ValueType factor = 1e+10; | |||
|                     ValueType m = std::floor(lambda); | |||
|                      | |||
|                     // Now start the Finder algorithm to find the truncation points. | |||
|                     { | |||
|                         // Factors used by the corollaries explained in Fox & Glynns paper. | |||
|                         // Square root of pi. | |||
|                         Type sqrtpi = 1.77245385090551602729; | |||
|                          | |||
|                         // Square root of 2. | |||
|                         Type sqrt2 = 1.41421356237309504880; | |||
|                          | |||
|                         // Square root of lambda. | |||
|                         Type sqrtLambda = std::sqrt(lambda); | |||
|                          | |||
|                         Type a_Lambda = (1.0 + 1.0 / lambda) * exp(0.0625) * sqrt2; // a_\lambda. | |||
|                         Type b_Lambda = (1.0 + 1.0 / lambda) * exp(0.125 / lambda); // b_\lambda. | |||
|                     } | |||
|                 } | |||
|                  | |||
|                     // Use Fox Glynn algorithm for lambda>400. | |||
|                     if (accuracy < 1e-10) { | |||
|                         LOG4CPLUS_ERROR(logger, "Given Value accuracy must at least be 1e-10."); | |||
|                         throw storm::exceptions::InvalidArgumentException("Error while computing FoxGlynn values. accuracy < 1e-10."); | |||
|                     } | |||
|                     // Factor from Fox&Glynns paper. The paper does not explain where it comes from. | |||
|                     Type factor = 1e+10; | |||
|                      | |||
|                     // Run the FINDER algorithm. | |||
|                     Type m = floor(lambda); | |||
|                     { | |||
|                         // Factores used by the corollaries explained in Fox&Glynns paper. | |||
|                         Type sqrtpi = 1.77245385090551602729; // Squareroot of PI. | |||
|                         Type sqrt2 = 1.41421356237309504880; // Squareroot of 2. | |||
|                         Type sqrtLambda = sqrt(lambda); // Sqareroot of Lambda. | |||
|                         Type a_Lambda = (1.0 + 1.0 / lambda) * exp(0.0625) * sqrt2; // a_\lambda. | |||
|                         Type b_Lambda = (1.0 + 1.0 / lambda) * exp(0.125 / lambda); // b_\lambda. | |||
|                          | |||
|                         // Use Corollary 1 from the paper to find the right truncation point. | |||
|                         Type k = 4; | |||
|                         res = a_Lambda*dkl*exp(-k*k / 2.0) / (k*sqrt2*sqrtpi); | |||
|                         /* Normally: Iterate between the bounds stated above to find the right truncationpoint. | |||
|                          * This is a modification to the Fox-Glynn paper. The search for the right truncationpoint is only | |||
|                          * terminated by the error condition and not by the upper bound. Thus the calculation can be more accurate. | |||
|                          */ | |||
|                         while (res > accuracy / 2.0) | |||
|                         { | |||
|                             k++; | |||
|                             Type dkl = 1.0 / (1 - exp(-(2.0 / 9.0)*(k*sqrt2*sqrtLambda + 1.5))); // d(k,Lambda) from the paper. | |||
|                             Type res = a_Lambda*dkl*exp(-k*k / 2.0) / (k*sqrt2*sqrtpi); // Right hand side of the equation in Corollary 1. | |||
|                              | |||
|                         } | |||
|                          | |||
|                         // Left hand side of the equation in Corollary 1. | |||
|                         this->rightTrunk = (int)ceil(m + k*sqrt2*sqrtLambda + 1.5); | |||
|                          | |||
|                         // Use Corollary 2 to find left truncation point. | |||
|                         Type res; | |||
|                         k = 4; | |||
|                          | |||
|                         do | |||
|                         { | |||
|                             res = b_Lambda*exp(-k*-k / 2.0) / (k*sqrt2*sqrtpi); // Right hand side of the equation in Corollary 2 | |||
|                             k++; | |||
|                         } while (res > accuracy / 2.0); | |||
|                          | |||
|                         this->leftTrunk = (int)(m - k*sqrtLambda - 1.5); // Left hand side of the equation in Corollary 2. | |||
|                          | |||
|                         // Check for underflow. | |||
|                         if ((int)(m - k*sqrtLambda - 1.5) < 0.0) { | |||
|                             LOG4CPLUS_ERROR(logger, "Underflow while computing left truncation point."); | |||
|                             throw storm::exceptions::OutOfRangeException("Error while computing FoxGlynn values. Underflow of left Truncation point."); | |||
|                         } | |||
|                          | |||
|                     } | |||
|                     //End of FINDER algorithm. | |||
|                      | |||
|                     // Use WEIGHTER algorithm to determine weights. | |||
|                     // Down from m | |||
|                     for (Type j = m; j > this->leftTrunk; j--) | |||
|                         this->weights.at(j - 1 - this->leftTrunk) = (j / lambda)*this->weights.at(j - this->leftTrunk); | |||
|                     // Up from m | |||
|                     for (Type j = m; j < this->rightTrunk; j++) | |||
|                         this->weights.at(j + 1 - this->leftTrunk) = (lambda / (j + 1))*this->weights.at(j - this->leftTrunk); | |||
|                      | |||
|                     // Compute total weight. | |||
|                     // Add up weights from smallest to largest to avoid roundoff errors. | |||
|                     this->totalWeight = 0.0; | |||
|                     Type s = this->leftTrunk; | |||
|                     Type t = this->rightTrunk; | |||
|                     while (s < t) | |||
|                     { | |||
|                         if (this->weights.at(s - this->leftTrunk) <= this->weights.at(t - this->leftTrunk)) | |||
|                         { | |||
|                             this->totalWeight += this->weights.at(s - this->leftTrunk); | |||
|                             s++; | |||
|                         } | |||
|                         else | |||
|                         { | |||
|                             this->totalWeight += this->weights.at(t - this->leftTrunk); | |||
|                             t--; | |||
|                         } | |||
|                     } | |||
|                      | |||
|                     this->totalWeight += this->weights.at(s - this->leftTrunk); | |||
|                      | |||
|                     LOG4CPLUS_INFO(logger, "Left truncationpoint: " << this->leftTrunk << "."); | |||
|                     LOG4CPLUS_INFO(logger, "Right truncationpoint: " << this->rightTrunk << "."); | |||
|                     LOG4CPLUS_INFO(logger, "Total Weight:" << this->totalWeight << "."); | |||
|                     LOG4CPLUS_INFO(logger, "10. Weight: " << this->weights.at(9) << "."); | |||
|                 } | |||
|                  | |||
|             } | |||
|         } | |||
|     } | |||
| } | |||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue