-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterval.c
124 lines (100 loc) · 3.44 KB
/
interval.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#ifndef INTERVAL_C
#define INTERVAL_C
#include "interval.h"
#include "bracket.h"
#include "brent.h"
#include "expfam.h"
#include "gfunc.h"
#include "normal.h"
#include "zero.h"
#include <math.h>
static const double times_std = 7;
static const double reps = 1e-5;
static const double aeps = 1e-5;
static const int maxiter = 100;
#ifndef DBL_TRUE_MIN
#define DBL_TRUE_MIN 4.9406564584124654E-324
#endif
static void find_first_interval(struct ExpFam *ef, struct Normal *normal,
double *a, double *b);
static double g_function_root(double x, void *args);
static void shrink_interval(struct ExpFam *ef, struct Normal *normal, double *a,
double xmax, double *b, double fxmax);
static inline double neg_func_base(double x, void *args)
{
void **args_ = args;
liknorm_func_base *fb = (liknorm_func_base *)args_[0];
return -(*fb)(x, args_[1]);
}
static inline void find_maximum(double *x0, double *fx0, liknorm_func_base *f,
void *args, double a, double b, double rtol,
double atol, int maxiter)
{
void *args_[] = {(void *)f, args};
liknorm_find_minimum(x0, fx0, &neg_func_base, args_, a, b, rtol, atol,
maxiter);
*fx0 = -(*fx0);
}
void liknorm_find_interval(struct ExpFam *ef, struct Normal *normal,
double *left, double *right)
{
double a, b;
double xmax, fxmax;
void *args[] = {ef, normal};
double fleft, fright;
find_first_interval(ef, normal, &a, &b);
liknorm_find_bracket(&liknorm_g_function_func_base, args, a, b,
ef->lower_bound, ef->upper_bound, left, right, &fleft,
&fright);
a = fmin(a, *left);
b = fmax(b, *right);
find_maximum(&xmax, &fxmax, &liknorm_g_function_func_base, args, a, b, reps,
aeps, maxiter);
shrink_interval(ef, normal, &a, xmax, &b, fxmax);
*left = a;
*right = b;
}
static void find_first_interval(struct ExpFam *ef, struct Normal *normal,
double *a, double *b)
{
double std = sqrt(1 / normal->tau);
double mu = normal->eta / normal->tau;
double smallest_step;
/* initial reasonable interval */
*a = mu - times_std * std;
*b = mu + times_std * std;
*a = fmax(*a, ef->lower_bound);
*b = fmin(*b, ef->upper_bound);
smallest_step = fmax(fabs(*a), fabs(*b)) * reps + aeps;
if (*b - *a < smallest_step)
{
if (*a - ef->lower_bound >= *b - ef->lower_bound)
*a -= smallest_step;
else
*b += smallest_step;
}
}
static double g_function_root(double x, void *args)
{
void **args_ = args;
liknorm_func_base *fb = (liknorm_func_base *)args_[0];
double *fxmax = args_[1];
return *fxmax - (*fb)(x, args_[2]) + log(DBL_TRUE_MIN);
}
static void shrink_interval(struct ExpFam *ef, struct Normal *normal, double *a,
double xmax, double *b, double fxmax)
{
void *args[] = {ef, normal};
double fa = liknorm_g_function_func_base(*a, args);
double fb = liknorm_g_function_func_base(*b, args);
void *args_[] = {(void *)&liknorm_g_function_func_base, &fxmax, args};
if (fxmax - fa < log(DBL_TRUE_MIN))
{
*a = liknorm_zero(*a, xmax, 1e-5, &g_function_root, args_);
}
if (fxmax - fb < log(DBL_TRUE_MIN))
{
*b = liknorm_zero(*b, xmax, 1e-5, &g_function_root, args_);
}
}
#endif