dehnert
7 years ago
3 changed files with 301 additions and 132 deletions
-
24src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp
-
275src/storm/utility/numerical.cpp
-
134src/storm/utility/numerical.h
@ -0,0 +1,275 @@ |
|||
#include "storm/utility/numerical.h"
|
|||
|
|||
#include <cmath>
|
|||
#include <boost/math/constants/constants.hpp>
|
|||
|
|||
#include "storm/utility/macros.h"
|
|||
#include "storm/utility/constants.h"
|
|||
#include "storm/exceptions/InvalidArgumentException.h"
|
|||
#include "storm/exceptions/PrecisionExceededException.h"
|
|||
|
|||
namespace storm { |
|||
namespace utility { |
|||
namespace numerical { |
|||
|
|||
template<typename ValueType> |
|||
FoxGlynnResult<ValueType>::FoxGlynnResult() : left(0), right(0), totalWeight(storm::utility::zero<ValueType>()) { |
|||
// Intentionally left empty.
|
|||
} |
|||
|
|||
/*!
|
|||
* The following implementation of Fox and Glynn's algorithm is taken from David Jansen's patched version |
|||
* in MRMC, which is based on his paper: |
|||
* |
|||
* https://pms.cs.ru.nl/iris-diglib/src/getContent.php?id=2011-Jansen-UnderstandingFoxGlynn
|
|||
* |
|||
* We have only adapted the code to match more of C++'s and our coding guidelines. |
|||
*/ |
|||
|
|||
template<typename ValueType> |
|||
FoxGlynnResult<ValueType> foxGlynnFinder(ValueType lambda, ValueType epsilon) { |
|||
ValueType tau = std::numeric_limits<ValueType>::min(); |
|||
ValueType omega = std::numeric_limits<ValueType>::max(); |
|||
ValueType const sqrt_2_pi = boost::math::constants::root_two_pi<ValueType>(); |
|||
ValueType const log10_e = std::log10(boost::math::constants::e<ValueType>()); |
|||
|
|||
uint64_t m = static_cast<uint64_t>(lambda); |
|||
|
|||
int64_t left = 0; |
|||
int64_t right = 0; |
|||
|
|||
// tau is only used in underflow checks, which we are going to do in the logarithm domain.
|
|||
tau = log(tau); |
|||
|
|||
// In error bound comparisons, we always compare with epsilon*sqrt_2_pi.
|
|||
epsilon *= sqrt_2_pi; |
|||
|
|||
// Compute left truncation point.
|
|||
if (m < 25) { |
|||
// For lambda below 25 the exponential can be smaller than tau. If that is the case we expect
|
|||
// underflows and warn the user.
|
|||
if (-lambda <= tau) { |
|||
STORM_LOG_WARN("Fox-Glynn: 0 < lambda < 25, underflow near Poi(" << lambda << ", 0) = " << std::exp(-lambda) << ". The results are unreliable."); |
|||
} |
|||
|
|||
// Zero is used as left truncation point for lambda <= 25.
|
|||
left = 0; |
|||
} else { |
|||
// Compute the left truncation point for lambda >= 25 (for lambda < 25 we use zero as left truncation point).
|
|||
|
|||
ValueType const bl = (1 + 1 / lambda) * std::exp((1/lambda) * 0.125); |
|||
ValueType const sqrt_lambda = std::sqrt(lambda); |
|||
int64_t k; |
|||
|
|||
// Start looking for the left truncation point:
|
|||
// * start search at k=4 (taken from original Fox-Glynn paper)
|
|||
// * increase the left truncation point until we fulfil the error condition
|
|||
|
|||
for (k = 4;; ++k) { |
|||
ValueType max_err; |
|||
|
|||
left = m - static_cast<int64_t>(std::ceil(k*sqrt_lambda + 0.5)); |
|||
|
|||
// For small lambda the above calculation can yield negative truncation points, crop them here.
|
|||
if (left <= 0) { |
|||
left = 0; |
|||
break; |
|||
} |
|||
|
|||
|