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