-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathem.c
90 lines (67 loc) · 1.65 KB
/
em.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
/*
* Copyright 2015 Jarad Niemi
*
* Licensed under GNU GPLv2
*
* EM for hierarchical normal model
* y_i \sim N(\theta_i,\sigma^2)
* \theta_i \sim N(\mu,\tau^2)
*/
#include <math.h>
#include <stdio.h>
#include <string.h>
#include "timer.h"
#define N 1000
#define SIGMA2 1.0
#define MU 0.5
#define TAU2 1.0
#define NREPS 100
// http://stackoverflow.com/questions/5287009/gaussian-random-number-generator
// I don't even use this.
double rnorm(double mean, double sd)
{
double v1,v2,s;
do {
v1 = 2.0 * ((double) rand()/RAND_MAX) - 1;
v2 = 2.0 * ((double) rand()/RAND_MAX) - 1;
s = v1*v1 + v2*v2;
} while ( s >= 1.0 );
if (s == 0.0)
return 0.0;
else
return mean + sd*(1*sqrt(-2.0 * log(s) / s));
}
int main(int argc, char** argv)
{
int i,j;
const unsigned int n=N;
const unsigned int nreps=NREPS;
double v, mu=MU, tau2=TAU2, sigma2=SIGMA2, y[n], theta[n];
memset(y, 0, n*sizeof(double));
memset(theta, 0, n*sizeof(double));
// Fill with data
for (i=0; i<n; i++) y[i] = rnorm(mu,sqrt(sigma2+tau2));
StartTimer();
// initial values
mu = 0.3;
tau2 = 1.3;
#pragma acc data copy(mu,tau2) create(v,theta)
#pragma acc kernels
for (i=0; i<nreps; i++) {
v = 1.0/(1.0/tau2+1.0/sigma2);
// E-step
for (j=0; j<n; j++) theta[j] = v*(mu/tau2+y[j]/sigma2);
// M-step
mu = 0.0;
for (j=0;j<n; j++) mu += theta[j];
mu /= n;
tau2 = 0.0;
for (j=0;j<n; j++) tau2 += (theta[j]-mu)*(theta[j]-mu);
tau2 /= n;
tau2 += v;
}
double runtime = GetTimer();
printf(" mu= %f\n", mu);
printf(" tau2= %f\n", tau2);
printf(" total: %f s\n", runtime / 1000);
}