lkl_srcdet/rate_solvers.c
2025-03-04 11:54:21 +03:00

301 lines
5.8 KiB
C

double lkl_rate_condition(double r, double * s, double * b, int size)
{
int i;
double res;
res = 0.;
for (i = 0; i < size; i++)
{
res += s[i]/(s[i]*r + b[i]);
};
return res;
}
double lkl_rate_condition_pkr(double r, double * pk, int size)
{
int i;
double res;
res = 0.;
for (i = 0; i < size; i++)
{
res += pk[i]/(pk[i]*r + 1.);
};
return res;
}
double get_lkl_pkr(double r, double *pk, int size)
{
int i;
double res;
res = 0.;
for (i = 0; i < size; i++)
{
res = res + log(pk[i]*r + 1.);
};
return res;
}
double r8_epsilon ( )
/****************************************************************************
Purpose:
R8_EPSILON returns the R8 roundoff unit.
Discussion:
The roundoff unit is a number R which is a power of 2 with the
property that, to the precision of the computer's arithmetic,
1 < 1 + R
but
1 = ( 1 + R / 2 )
Licensing:
This code is distributed under the GNU LGPL license.
Modified:
01 September 2012
Author:
John Burkardt
Parameters:
Output, double R8_EPSILON, the R8 round-off unit.
*/
{
const double value = 2.220446049250313E-016;
return value;
}
double brent (double rate, double exposure, double *sp, double *bp, int ssize)
//****************************************************************************
//
// Purpose:
//
// ZERO seeks the root of a function F(X) in an interval [A,B].
//
// Discussion:
//
// The interval [A,B] must be a change of sign interval for F.
// That is, F(A) and F(B) must be of opposite signs. Then
// assuming that F is continuous implies the existence of at least
// one value C between A and B for which F(C) = 0.
//
// The location of the zero is determined to within an accuracy
// of 6 * MACHEPS * abs ( C ) + 2 * T.
//
// Thanks to Thomas Secretin for pointing out a transcription error in the
// setting of the value of P, 11 February 2013.
//
// Licensing:
//
// This code is distributed under the GNU LGPL license.
//
// Modified:
//
// 11 February 2013
//
// Author:
//
// Original FORTRAN77 version by Richard Brent.
// C++ version by John Burkardt.
//
// Reference:
//
// Richard Brent,
// Algorithms for Minimization Without Derivatives,
// Dover, 2002,
// ISBN: 0-486-41998-3,
// LC: QA402.5.B74.
//
// Parameters:
//
// Input, double A, B, the endpoints of the change of sign interval.
//
// Input, double T, a positive error tolerance.
//
// Input, func_base& F, the name of a user-supplied c++ functor
// whose zero is being sought. The input and output
// of F() are of type double.
//
// Output, double ZERO, the estimated value of a zero of
// the function F.
//
{
double a, b, t;
double c;
double d;
double e;
double fa;
double fb;
double fc;
double m;
double macheps;
double p;
double q;
double r;
double s;
double sa;
double sb;
double tol;
int i = 0;
//
// Make local copies of A and B.
//
a = 0.;
b = ssize/exposure;
t = 1e-7;
sa = a;
sb = b;
fa = lkl_rate_condition(sa, sp, bp, ssize) - exposure;
fb = lkl_rate_condition(sb, sp, bp, ssize) - exposure;
c = sa;
fc = fa;
e = sb - sa;
d = e;
macheps = r8_epsilon ( );
for ( ; ; )
{
i += 1;
if ( fabs ( fc ) < fabs ( fb ) )
{
sa = sb;
sb = c;
c = sa;
fa = fb;
fb = fc;
fc = fa;
}
tol = 2.0 * macheps * fabs ( sb ) + t;
m = 0.5 * ( c - sb );
if ( fabs ( m ) <= tol || fb == 0.0 )
{
break;
}
if ( fabs ( e ) < tol || fabs ( fa ) <= fabs ( fb ) )
{
e = m;
d = e;
}
else
{
s = fb / fa;
if ( sa == c )
{
p = 2.0 * m * s;
q = 1.0 - s;
}
else
{
q = fa / fc;
r = fb / fc;
p = s * ( 2.0 * m * q * ( q - r ) - ( sb - sa ) * ( r - 1.0 ) );
q = ( q - 1.0 ) * ( r - 1.0 ) * ( s - 1.0 );
}
if ( 0.0 < p )
{
q = - q;
}
else
{
p = - p;
}
s = e;
e = d;
if ( 2.0 * p < 3.0 * m * q - fabs ( tol * q ) &&
p < fabs ( 0.5 * s * q ) )
{
d = p / q;
}
else
{
e = m;
d = e;
}
}
sa = sb;
fa = fb;
if ( tol < fabs ( d ) )
{
sb = sb + d;
}
else if ( 0.0 < m )
{
sb = sb + tol;
}
else
{
sb = sb - tol;
}
fb = lkl_rate_condition(sb, sp, bp, ssize) - exposure;
if ( ( 0.0 < fb && 0.0 < fc ) || ( fb <= 0.0 && fc <= 0.0 ) )
{
c = sa;
fc = fa;
e = sb - sa;
d = e;
}
}
/*printf("it counter %d\n", i);*/
return sb;
}
double get_phc_solution(double r, double e, double *s, double *b, int size)
{
int i;
double rnew = r;
for (i = 0; i < 200; i++)
{
rnew = lkl_rate_condition(r, s, b, size)*r/e;
if ((fabs(rnew - r) < 1e-7) | (rnew*e < 1.)) break;
r = rnew;
};
/*printf("it counter %d\n", i);*/
//printf("%d %e %e\n", size, s[0], r);
return rnew;
}
double get_phc_solution_pkr(double r, double e, double *pk, int size)
{
int i;
double rnew = r;
for (i = 0; i < 200; i++)
{
rnew = lkl_rate_condition_pkr(r, pk, size)*r/e;
//printf("rnew %d %f\n", i, rnew*e);
if ((fabs(rnew - r) < 1e-7) | (rnew*e < 0.001)) break;
//if ((fabs(rnew - r) < 1e-7) | (rnew*e < 1.)) break;
r = rnew;
};
/*printf("it counter %d\n", i);*/
//printf("%d %e %e\n", size, s[0], r);
return rnew;
}