LCOV - code coverage report
Current view: top level - builds/barbot/Cosmos/src/Simulator/RareEvents - foxglynn.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 97 0.0 %
Date: 2021-06-16 15:43:28 Functions: 0 4 0.0 %

          Line data    Source code
       1             : /**
       2             : *       WARNING: Do Not Remove This Section
       3             : *
       4             : *       $LastChangedRevision: 415 $
       5             : *       $LastChangedDate: 2010-12-18 17:21:05 +0100 (Sa, 18. Dez 2010) $
       6             : *       $LastChangedBy: davidjansen $
       7             : *
       8             : *   Modified by Benoît Barbot on 25/01/2014 to integrate it into Cosmos
       9             : *
      10             : *       MRMC is a model checker for discrete-time and continuous-time Markov
      11             : *       reward models. It supports reward extensions of PCTL and CSL (PRCTL
      12             : *       and CSRL), and allows for the automated verification of properties
      13             : *       concerning long-run and instantaneous rewards as well as cumulative
      14             : *       rewards.
      15             : *
      16             : *       Copyright (C) The University of Twente, 2004-2008.
      17             : *       Copyright (C) RWTH Aachen, 2008-2009.
      18             : *       Authors: Ivan Zapreev
      19             : *
      20             : *       This program is free software; you can redistribute it and/or
      21             : *       modify it under the terms of the GNU General Public License
      22             : *       as published by the Free Software Foundation; either version 2
      23             : *       of the License, or (at your option) any later version.
      24             : *
      25             : *       This program is distributed in the hope that it will be useful,
      26             : *       but WITHOUT ANY WARRANTY; without even the implied warranty of
      27             : *       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      28             : *       GNU General Public License for more details.
      29             : *
      30             : *       You should have received a copy of the GNU General Public License
      31             : *       along with this program; if not, write to the Free Software
      32             : *       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
      33             : *       MA  02110-1301, USA.
      34             : *
      35             : *       Main contact:
      36             : *               Lehrstuhl für Informatik 2, RWTH Aachen University
      37             : *               Ahornstrasse 55, 52074 Aachen, Germany
      38             : *               E-mail: info@mrmc-tool.org
      39             : *
      40             : *       Old contact:
      41             : *               Formal Methods and Tools Group, University of Twente,
      42             : *               P.O. Box 217, 7500 AE Enschede, The Netherlands,
      43             : *               Phone: +31 53 4893767, Fax: +31 53 4893247,
      44             : *               E-mail: mrmc@cs.utwente.nl
      45             : *
      46             : *       Source description: Calculate left/right truncation pts. and
      47             : *               weights based on Fox&Glynn algorithm.
      48             : *       Uses: Definition of foxglynn - foxglynn.h
      49             : *       Reference: "Computing Poisson Probabilities", Bennett L. Fox and
      50             : *                       Peter W. Glynn,
      51             : *                       Communications of the ACM , vol. 31, pp. 440-445
      52             : *                                                               (1988 ).
      53             : */
      54             : 
      55             : #include "foxglynn.hpp"
      56             : 
      57             : #include <stdio.h>
      58             : #include <stdlib.h>
      59             : #include <math.h>
      60             : 
      61             : /*The pi constant*/
      62             : static const double pi = 3.14159265358979323846264;
      63             : static const double lambda_25 = 25.0;
      64             : static const double lambda_400 = 400.0;
      65             : 
      66             : /*****************************************************************************
      67             : Name            : finder
      68             : Role            : The FINDER function from the Fox-Glynn algorithm
      69             : @param          : int m: the middle point from weighter.
      70             : @param          : double lambda: (rate of uniformization)*(mission time)
      71             : @param          : double tau: underflow
      72             : @param          : double omega: overflow
      73             : @param          : double epsilon: error bound
      74             : @param          : double * pw_m: pointer to the initial value in the array of sets, will be set here
      75             : @param          : FoxGlynn *: return by reference
      76             : @return         : TRUE if everything is fine, otherwise FALSE.
      77             :               This is the F parameter of Fox-Glynn finder function.
      78             : remark      : This implementation is based on the original Fox-Glynn paper with
      79             :               small modifications.
      80             :               The most remarkable alterations are the removal of terminating indices for the search for the
      81             :               truncation points. This will result in higher accuracy when needed.
      82             :               It can be shown that the introduced error converges to a value below the requested error level
      83             :               (for epsilon > 0). Hence the algorithm will always terminate.
      84             : ******************************************************************************/
      85           0 : bool FoxGlynn::finder(const int m, const double lambda, const double tau, const double omega,
      86             :                    const double epsilon, double * pw_m)
      87             : {
      88           0 :         const double sqrt_2_pi = sqrt( 2.0 * pi );
      89           0 :         const double sqrt_2 = sqrt(2.0);
      90           0 :         const double sqrt_lambda = sqrt(lambda);
      91           0 :         double lambda_max, k, k_rtp = HUGE_VAL, k_prime, c_m_inf, result, al, dkl, bl;
      92             : 
      93             :         /*Simple bad cases, when we quit*/
      94           0 :         if( lambda == 0.0 )
      95             :         {
      96           0 :           fprintf(stderr,"ERROR: Fox-Glynn: lambda = 0, terminating the algorithm\n");
      97           0 :         return false;
      98             :         }
      99             :         /* The requested error level must not be smaller than the minimum machine precision
     100             :            (needed to guarantee the convergence of the error conditions) */
     101           0 :         if( epsilon < tau)
     102             :         {
     103           0 :           fprintf(stderr,"ERROR: Fox-Glynn: epsilon < tau, invalid error level, terminating the algorithm\n");
     104           0 :           fprintf(stderr,"epsilon %e, tau %e\n",epsilon,tau);
     105           0 :           return false;
     106             :         }
     107             :         /* zero is used as left truncation point for lambda <= 25 */
     108           0 :         left = 0;
     109           0 :         lambda_max = lambda;
     110             : 
     111             :         /* for lambda below 25 the exponential can be smaller than tau */
     112             :         /* if that is the case we expect underflows and warn the user */
     113           0 :         if( 0.0 < lambda && lambda <= lambda_25 )
     114             :         {
     115           0 :                 if( exp( -lambda ) <= tau )
     116             :                 {
     117           0 :                         fprintf(stderr,"ERROR: Fox-Glynn: 0 < lambda < 25, underflow. The results are UNRELIABLE.\n");
     118             :                 }
     119             :         }
     120             : 
     121           0 :         bl = (1.0 + 1.0/lambda) * exp(1.0 / (8.0 * lambda));
     122             : 
     123             :         /****Compute pFG->right truncation point****/
     124             :         /*According to Fox-Glynn, if lambda < 400 we should take lambda = 400,
     125             :           otherwise use the original value. This is for computing the right truncation point*/
     126           0 :         if(lambda < lambda_400)
     127           0 :                 lambda_max = lambda_400;
     128           0 :         k = 4;
     129           0 :         al = (1.0+1.0/lambda_max) * exp(1.0/16.0) * sqrt_2;
     130           0 :         dkl = exp(-2.0/9.0 * (k * sqrt(2.0 * lambda_max) + 1.5 ));
     131           0 :         dkl = 1.0 / (1.0 - dkl);
     132             :         /* find right truncation point */
     133             : 
     134             :         /* This loop is a modification to the original Fox-Glynn paper.
     135             :            The search for the right truncation point is only terminated by
     136             :            the error condition and not by the stop index from the FG paper.
     137             :            This can yield more accurate results if neccesary.*/
     138           0 :         while((epsilon/2.0) < ((al * dkl * exp(-(k*k)/2.0))/(k*sqrt_2_pi)))
     139             :         {
     140           0 :                 k++;
     141           0 :                 dkl = exp(-2.0/9.0 * (k * sqrt_2 * sqrt(lambda_max) + 1.5 ));
     142           0 :                 dkl = 1.0 / (1.0 - dkl);
     143             :         }
     144           0 :         k_rtp = k;
     145           0 :         right = (int)ceil(m + k_rtp * sqrt_2 * sqrt(lambda_max) + 1.5 );
     146             : 
     147             : 
     148             :         /****Compute pFG->left truncation point****/
     149             :         /* compute the left truncation point for lambda > 25 */
     150             :         /* for lambda <= 25 we use zero as left truncation point */
     151           0 :         if(lambda > lambda_25)
     152             :         {
     153             :                 /*Start looking for the left truncation point*/
     154             :                 /* start search at k=4 (taken from original Fox-Glynn paper */
     155           0 :                 k = 4;
     156             :                 /* increase the left truncation point as long as we fulfill the error condition */
     157             : 
     158             :                 /* This loop is a modification to the original Fox-Glynn paper.
     159             :                    The search for the left truncation point is only terminated by
     160             :                    the error condition and not by the stop index from the FG paper.
     161             :                    This can yield more accurate results if neccesary.*/
     162           0 :                 while((epsilon/2.0) < ((bl * exp(-(k*k)/2.0))/(k * sqrt_2_pi)))
     163           0 :                         k++;
     164             :                 /*Finally the left truncation point is found*/
     165           0 :                 left = (int)floor(m - k*sqrt(lambda)- 1.5 );
     166             :                 /* for small lambda the above calculation can yield negative truncation points, crop them here */
     167           0 :                 if(left < 0)left = 0;
     168             :                 /* perform underflow check */
     169           0 :                 k_prime = k + 3.0 / (2.0 * sqrt_lambda);
     170             :                 /*We take the c_m_inf = 0.02935 / sqrt( m ), as for lambda >= 25
     171             :                  c_m = 1 / ( sqrt( 2.0 * pi * m ) ) * exp( m - lambda - 1 / ( 12.0 * m ) ) => c_m_inf*/
     172           0 :                 c_m_inf = 0.02935 / sqrt((double) m);
     173           0 :                 result = 0.0;
     174           0 :                 if( 0.0 < k_prime && k_prime <= sqrt_lambda / 2.0 )
     175             :                 {
     176           0 :                         result = c_m_inf * exp( - pow(k_prime,2.0) / 2.0 - pow(k_prime, 3.0) / (3.0 * sqrt_lambda) );
     177             :                 }
     178             :                 else
     179             :                 {
     180           0 :                         if( k_prime <= sqrt( m + 1.0 ) / m )
     181             :                         {
     182           0 :                                 double result_1 = c_m_inf * pow(
     183           0 :                                         1.0 - k_prime / sqrt((double) (m + 1)),
     184           0 :                                         k_prime * sqrt((double) (m + 1)));
     185           0 :                                 double result_2 = exp( - lambda );
     186             :                                 /*Take the maximum*/
     187           0 :                                 result = ( result_1 > result_2 ? result_1 : result_2);
     188             :                         }
     189             :                         else
     190             :                         {
     191             :                                 /*NOTE: It will be an underflow error*/;
     192           0 :                                 fprintf(stderr,"ERROR: Fox-Glynn: lambda >= 25, underflow. The results are UNRELIABLE.\n");
     193             :                         }
     194             :                 }
     195           0 :                 if ( result * omega / ( 1.0e+10 * ( right - left ) ) <= tau )
     196             :                 {
     197           0 :                         fprintf(stderr,"ERROR: Fox-Glynn: lambda >= 25, underflow. The results are UNRELIABLE.\n");
     198             :                 }
     199             :         }
     200             : 
     201             : 
     202             : 
     203             :         /*We still have to perform an underflow check for the right truncation point when lambda >= 400*/
     204           0 :         if( lambda >= lambda_400 )
     205             :         {
     206           0 :                 k_prime = k_rtp * sqrt_2 + 3.0 / (2.0 * sqrt_lambda);
     207             :                 /*We take the c_m_inf = 0.02935 / sqrt( m ), as for lambda >= 25
     208             :                  c_m = 1 / ( sqrt( 2.0 * pi * m ) ) * exp( m - lambda - 1 / ( 12.0 * m ) ) => c_m_inf*/
     209           0 :                 c_m_inf = 0.02935 / sqrt((double) m);
     210           0 :                 result = c_m_inf * exp( - pow( k_prime + 1.0 , 2.0 ) / 2.0 );
     211           0 :                 if( result * omega / ( 1.0e+10 * ( right - left ) ) <= tau)
     212             :                 {
     213           0 :                         fprintf(stderr,"ERROR: Fox-Glynn: lambda >= 400, underflow. The results are UNRELIABLE.\n");
     214             :                 }
     215             :         }
     216             :         /*Time to set the initial value for weights*/
     217           0 :         *pw_m = omega / ( 1.0e+10 * ( right - left ) );
     218             : 
     219           0 :         return true;
     220             : }
     221             : 
     222             : /*****************************************************************************
     223             : Name            : weighter
     224             : Role            : The WEIGHTER function from the Fox-Glynn algorithm
     225             : @param          : double lambda: (rate of uniformization)*(mission time)
     226             : @param          : double tau: underflow
     227             : @param          : double omega: overflow
     228             : @param          : double epsilon: error bound
     229             : @param          : FoxGlynn *: return by reference
     230             : @return         : TRUE if everything is fine, otherwise FALSE.
     231             :               This is the F parameter of Fox-Glynn finder function.
     232             : remark      :
     233             : ******************************************************************************/
     234           0 : bool FoxGlynn::weighter(const double lambda, const double tau, const double omega, const double epsilon)
     235             : {
     236             :         /*The magic m point*/
     237           0 :         const int m = (int)floor(lambda);
     238           0 :         double w_m = 0;
     239             :         int j, s, t;
     240             : 
     241           0 :         if( ! finder( m, lambda, tau, omega, epsilon, &w_m ) )
     242           0 :                 return false;
     243             : 
     244             :         /*Allocate space for weights*/
     245           0 :         weights = (double *) calloc((size_t) (right - left + 1),
     246             :                         sizeof(double));
     247             :         /*Set an initial weight*/
     248           0 :         weights[ m - left ] = w_m;
     249             : 
     250             :         /*Fill the left side of the array*/
     251           0 :         for( j = m; j > left; j-- )
     252           0 :                 weights[ ( j - left ) - 1  ] = ( j / lambda ) * weights[ j - left ];
     253             : 
     254             :         /*Fill the right side of the array, have two cases lambda < 400 & lambda >= 400*/
     255           0 :         if( lambda < lambda_400 )
     256             :         {
     257             :                 /*Perform the underflow check, according to Fox-Glynn*/
     258           0 :                 if( right > 600 )
     259             :                 {
     260           0 :                         fprintf(stderr,"ERROR: Fox-Glynn: pFG->right > 600, underflow is possible\n");
     261           0 :                         return false;
     262             :                 }
     263             :                 /*Compute weights*/
     264           0 :                 for( j = m; j < right; j++ )
     265             :                 {
     266           0 :                         double q = lambda / ( j + 1 );
     267           0 :                         if( weights[ j - left ] > tau / q )
     268             :                         {
     269           0 :                                 weights[ ( j - left ) + 1  ] = q * weights[ j - left ];
     270             :                         }else{
     271           0 :                                 right = j;
     272           0 :                                 break; /*It's time to compute W*/
     273             :                         }
     274             :                 }
     275             :         }else{
     276             :                 /*Compute weights*/
     277           0 :                 for( j = m; j < right; j++ )
     278           0 :                         weights[ ( j - left ) + 1  ] = ( lambda / ( j + 1 ) ) * weights[ j - left ];
     279             :         }
     280             : 
     281             :         /*It is time to compute the normalization weight W*/
     282           0 :         total_weight = 0.0;
     283           0 :         s = left;
     284           0 :         t = right;
     285             : 
     286           0 :         while( s < t )
     287             :         {
     288           0 :                 if( weights[ s - left ] <= weights[ t - left ] )
     289             :                 {
     290           0 :                         total_weight += weights[ s - left ];
     291           0 :                         s++;
     292             :                 }else{
     293           0 :                         total_weight += weights[ t - left ];
     294           0 :                         t--;
     295             :                 }
     296             :         }
     297           0 :         total_weight += weights[ s - left ];
     298             : 
     299             :         /* printf("Fox-Glynn: ltp = %d, rtp = %d, w = %10.15le \n", pFG->left, pFG->right, pFG->total_weight); */
     300             : 
     301           0 :         return true;
     302             : }
     303             : 
     304             : /*****************************************************************************
     305             : Name            : fox_glynn
     306             : Role            : get poisson probabilities.
     307             : @param          : double lambda: (rate of uniformization)*(mission time)
     308             : @param          : double tau: underflow
     309             : @param          : double omega: overflow
     310             : @param          : double epsilon: error bound
     311             : @param          : FoxGlynn **: return a new FoxGlynn structure by reference
     312             : @return : TRUE if it worked fine, otherwise false
     313             : remark          :
     314             : ******************************************************************************/
     315           0 : FoxGlynn::FoxGlynn(const double lambda, const double tau, const double omega, const double epsilon):
     316           0 : isValid(false),left(0),right(0),total_weight(0.0),weights(NULL)
     317             : {
     318             :         /* printf("Fox-Glynn: lambda = %3.3le, epsilon = %1.8le\n",lambda, epsilon); */
     319           0 :         isValid = weighter(lambda, tau, omega, epsilon);
     320           0 : }
     321             : 
     322             : 
     323             : /**
     324             : * Fries the memory allocated for the FoxGlynn structure
     325             : * @param fg the structure to free
     326             : */
     327           0 : FoxGlynn::~FoxGlynn()
     328             : {
     329           0 :         if( weights )free(weights);
     330           0 : }

Generated by: LCOV version 1.13