File: [local] / OpenXM / src / hgm / fisher-bingham / src / ko-fbd.c (download)
Revision 1.1, Thu Mar 27 05:24:28 2014 UTC (10 years, 2 months ago) by takayama
Branch: MAIN
CVS Tags: RELEASE_1_3_1_13b, HEAD
A manual and a library for nk_fb_ten_c.
nk_fb_gen_c-ja.texi generated from nk_fb_gen_c.oxg gives an explanation
how to make a maximal likelihood estimate (MLE) for the Fisher-Bingham distribution
with this package.
(commit by proxy of T.Koyama, H.Nakayama, K.Nishiyama).
|
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
#include<gsl/gsl_errno.h>
#include<gsl/gsl_eigen.h>
#include<gsl/gsl_statistics.h>
#include <gsl/gsl_cdf.h>
#include "ko-perturbation.h"
#include "ko-time.h"
#define MAXDIM 10 /* maximum size of the matrix x */
#define NDATA 100 /* number of sample data for computing confidence interval */
int dim; /* dimension of the sphere */
double eps_pert = 0.00001;
int flag_verbose = 0;
int flag_confidence = 0;
int flag_time =0;
extern void pow_series(const double *x,const double *y,const double r, double *ans); /* defined in ko-fbd-ps.c */
extern int maxdeg;
extern void runge_kutta(double *g, const double *g0dev, const double *xdiag0, const double *ydiag0,const double r); /* defined in ko-fbd-rk.c */
static void
get_xdiag(double **x, const double *y, double *xdiag, double *ydiag, double **P)
{
gsl_eigen_symmv_workspace *w = gsl_eigen_symmv_alloc( dim+1);
gsl_matrix *A = gsl_matrix_alloc(dim+1, dim+1);
gsl_vector *eval = gsl_vector_alloc(dim+1);
gsl_matrix *evec = gsl_matrix_alloc(dim+1, dim+1);
int i,j;
for(i=0; i<dim+1; i++){
for(j=0; j<dim+1; j++){
gsl_matrix_set(A, i, j, x[i][j]);
}
}
gsl_eigen_symmv(A, eval, evec, w);
gsl_eigen_symmv_sort(eval,evec, GSL_EIGEN_SORT_VAL_DESC);
for(i=0; i<dim+1; i++){ xdiag[i] = gsl_vector_get(eval, i);}
for(i=0; i<dim+1; i++){
ydiag[i] = 0.0;
for(j=0; j<dim+1; j++){
ydiag[i] += gsl_matrix_get(evec, j, i)*y[j]; /* ydiag = evec' * y */
}
}
for (i=0; i<dim+1; i++) {
for (j=0; j<dim+1; j++){
P[i][j] = gsl_matrix_get(evec, i,j);
}
}
gsl_eigen_symmv_free(w);
gsl_matrix_free(A);
gsl_vector_free(eval);
gsl_matrix_free(evec);
}
static double
move_near0(double *xdiag, double *ydiag, double *xdiag0, double *ydiag0)
{
int i;
double sum, r;
sum = 0.0;
for(i=0; i<dim+1; i++){
sum += fabs(xdiag[i]) + ydiag[i]*ydiag[i];
}
r = sum;
for(i=0; i<dim+1; i++){
xdiag0[i] = xdiag[i]/(r*r);
ydiag0[i] = ydiag[i]/r;
}
return r;
}
static void
dev_max_eigen(const double *g0,const double max_eigen, double *g0dev)
{
int i;
double tmp = exp(-max_eigen);
for(i=0; i<2*dim+2; i++)
g0dev[i] = g0[i]*tmp;
}
static void
g2fdiag(double *fdiag, const double *g, const double r, const double *xdiag0)
{
double tmp;
int i;
tmp = exp(r*r*xdiag0[0]);
for(i=0; i<2*dim+2; i++){fdiag[i] = g[i]*tmp;}
tmp = pow(r, dim+1);
for(i=0; i<dim+1; i++){fdiag[i] /= tmp; }
tmp *= r;
for(i=0; i<dim+1; i++){fdiag[i+dim+1] /= tmp; }
}
static void
fdiag2f(double *f, const double *fdiag, const double *xdiag, const double *ydiag, double **P)
{
double h[dim+1][dim+1];
int i,j,k;
for(i=0; i<2*dim+2; i++){ f[i] =0.0;}
for(i=0; i<dim+1; i++){ f[0] += fdiag[i+dim+1];}
for(i=0; i<dim+1; i++){
for(j=0; j<dim+1; j++){
f[i+1] += P[i][j]*fdiag[j];
}
}
for(i=0; i<dim+1; i++){
for(j = i+1; j<dim+1; j++){
h[i][j] = -(ydiag[i]*fdiag[j]-ydiag[j]*fdiag[i])/(xdiag[i]-xdiag[j]);
}
}
for(i=0; i<dim; i++){
for(j=0; j<dim+1; j++){
f[i+dim+2] += P[i][j]*P[i][j]*fdiag[j+dim+1];
}
for(j=0; j<dim+1; j++){
for(k = j+1; k<dim+1; k++){
f[i+dim+2] += P[i][j] * P[i][k]*h[j][k];
}
}
}
}
double
*ko_fbd(double **x, double *y)
{
if(flag_time) ko_time_init(3, "total", "power-series","runge-kutta");
if(flag_time) ko_time_start("total");
int i,j;
double r;
double xdiag[dim+1], ydiag[dim+1];
double xdiag0[dim+1], ydiag0[dim+1];
double g0[2*dim+2], g0dev[2*dim+2], g[2*dim+2];
double fdiag[2*dim+2];
double *f = (double *)malloc(sizeof(double) *(2*dim+2));
double **P, *Py;
P = (double **)malloc(sizeof(double *) * (dim+1));
Py = (double *)malloc(sizeof(double) * (dim+1)*(dim+1));
for (i=0; i<dim+1; i++) { /* initialize */
P[i] = Py + i*(dim+1);
for (j=0; j<dim+1; j++){
P[i][j] = 0.0;
}
}
get_xdiag(x, y, xdiag, ydiag, P);
r=move_near0(xdiag, ydiag, xdiag0, ydiag0);
if(flag_time)
ko_time_start("power-series");
pow_series(xdiag0, ydiag0, 1.0, g0);
if(flag_time)
ko_time_end("power-series");
dev_max_eigen(g0,xdiag0[0], g0dev);
if(flag_time)
ko_time_start("runge-kutta");
runge_kutta(g,g0dev, xdiag0, ydiag0, r);
if(flag_time)
ko_time_end("runge-kutta");
g2fdiag(fdiag,g,r,xdiag0);
fdiag2f(f,fdiag,xdiag,ydiag,P);
if(flag_verbose){
printf("diagnalization:\n");
print_vec(2,dim+1,
"\txdiag: ", xdiag,
"\tydiag: ", ydiag
);
printf("\tP:\n");
for(i=0; i<dim+1; i++)
print_vec(1,dim+1, "\t\t", P[i]);
printf("initial point of Runge-Kutta:\n");
print_vec(2,dim+1,
"\txdiag0: ", xdiag0,
"\tydiag0: ", ydiag0
);
printf("maximal eigenvalue:%g\n", xdiag0[0]);
printf("move from r=1 to r=%f\n", r);
print_vec(4,2*dim+2,
"power seriese:\n\t", g0,
"initial values of Runge-Kutta:\n\t", g0dev,
"output of Runge-Kutta:\n\t", fdiag,
"f:\n\t", f
);
}
if(flag_confidence){ /*perturbation*/
double *g0devp;
int ii;
double err[2*dim+2];
double fp[NDATA][2*dim+2];
double fpt[2*dim+2][NDATA];
double mean, sd, cdfinv;
perturbation_init(2*dim+2, eps_pert);
printf("perturbation:\n");
for(ii=0; ii< NDATA; ii++){
double *g0p = perturbation(g0,err);
dev_max_eigen(g0p,xdiag0[0], g0dev);
runge_kutta(g, g0dev, xdiag0, ydiag0, r);
g2fdiag(fdiag, g,r,xdiag0);
fdiag2f(fp[ii],fdiag,xdiag,ydiag,P);
if(flag_verbose>1)
print_vec(2,2*dim+2,
"error= ", err,
"f= ", fp[ii]
);
free(g0p);
}
perturbation_free();
for(i=0; i<NDATA; i++){
for(j=0; j<2*dim+2; j++){
fpt[j][i] = fp[i][j];
}
}
if(flag_verbose){
printf("eps_pert=%e, NDATA=%d\n", eps_pert, NDATA);
printf("eps_pert * exp(-max_eigen) = %g\n", eps_pert * exp(-xdiag0[0]));
printf(" i: f[i], mean, sd, confidence interval\n");
for(i=0; i< 2*dim+2; i++){
mean = gsl_stats_mean(fpt[i], 1, NDATA);
sd = gsl_stats_sd(fpt[i], 1, NDATA);
cdfinv = gsl_cdf_gaussian_Pinv (1.0-0.025, sd);
printf("f[%d]:\t%10g,\t%10g,\t %10e,\t[%10g, %10g]\n",i, f[i], mean, sd, mean-cdfinv, mean+cdfinv);
}
}else{
printf(" mean, sd, confidence interval\n");
mean = gsl_stats_mean(fpt[0], 1, NDATA);
sd = gsl_stats_sd(fpt[0], 1, NDATA);
cdfinv = gsl_cdf_gaussian_Pinv (1.0-0.25, sd);
printf("\t%10g,\t %10e,\t[%10g, %10g]\n",mean, sd, mean-cdfinv, mean+cdfinv);
}
}
free(*P); free(P);
if(flag_time) ko_time_end("total");
if(flag_time) ko_time_print();
return f;
}
#ifdef _HGD
double*
fbnd(int d, double x0[MAXDIM][MAXDIM], double y0[], int maxd, int w[])
{
dim = d;
maxdeg = maxd;
flag_verbose=1;
double **X, *Xy, *Y;
int M = dim+1;
X = (double **)malloc(sizeof(double *) * M); /* memory allocation */
Xy = (double *)malloc(sizeof(double) * M*M);
Y = (double *)malloc(sizeof(double) * M);
int i,j;
for (i=0; i<M; i++) { /* initializing */
X[i] = Xy + i*M;
Y[i] = y0[i];
for (j=0; j<M; j++){
X[i][j] = x0[i][j];
}
}
double *ans = ko_fbd( X, Y);
free(*X); free(X); free(Y);
return ans;
}
#endif