forked from milkha/Splines_in_Stan
-
Notifications
You must be signed in to change notification settings - Fork 0
/
b_spline.stan
74 lines (68 loc) · 2.61 KB
/
b_spline.stan
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
functions {
vector build_b_spline(real[] t, real[] ext_knots, int ind, int order);
vector build_b_spline(real[] t, real[] ext_knots, int ind, int order) {
// INPUTS:
// t: the points at which the b_spline is calculated
// ext_knots: the set of extended knots
// ind: the index of the b_spline
// order: the order of the b-spline
vector[size(t)] b_spline;
vector[size(t)] w1 = rep_vector(0, size(t));
vector[size(t)] w2 = rep_vector(0, size(t));
if (order==1)
for (i in 1:size(t)) // B-splines of order 1 are piece-wise constant
b_spline[i] = (ext_knots[ind] <= t[i]) && (t[i] < ext_knots[ind+1]);
else {
if (ext_knots[ind] != ext_knots[ind+order-1])
w1 = (to_vector(t) - rep_vector(ext_knots[ind], size(t))) /
(ext_knots[ind+order-1] - ext_knots[ind]);
if (ext_knots[ind+1] != ext_knots[ind+order])
w2 = 1 - (to_vector(t) - rep_vector(ext_knots[ind+1], size(t))) /
(ext_knots[ind+order] - ext_knots[ind+1]);
// Calculating the B-spline recursively as linear interpolation of two lower-order splines
b_spline = w1 .* build_b_spline(t, ext_knots, ind, order-1) +
w2 .* build_b_spline(t, ext_knots, ind+1, order-1);
}
return b_spline;
}
}
data {
int num_data; // number of data points
int num_knots; // num of knots
vector[num_knots] knots; // the sequence of knots
int spline_degree; // the degree of spline (is equal to order - 1)
real Y[num_data];
real X[num_data];
}
transformed data {
int num_basis = num_knots + spline_degree - 1; // total number of B-splines
matrix[num_basis, num_data] B; // matrix of B-splines
vector[spline_degree + num_knots] ext_knots_temp;
vector[2*spline_degree + num_knots] ext_knots; // set of extended knots
ext_knots_temp = append_row(rep_vector(knots[1], spline_degree), knots);
ext_knots = append_row(ext_knots_temp, rep_vector(knots[num_knots], spline_degree));
for (ind in 1:num_basis)
B[ind,:] = to_row_vector(build_b_spline(X, to_array_1d(ext_knots), ind, spline_degree + 1));
B[num_knots + spline_degree - 1, num_data] = 1;
}
parameters {
row_vector[num_basis] a_raw;
real a0; // intercept
real<lower=0> sigma;
real<lower=0> tau;
}
transformed parameters {
row_vector[num_basis] a; // spline coefficients
vector[num_data] Y_hat;
a = a_raw*tau;
Y_hat = a0*to_vector(X) + to_vector(a*B);
}
model {
// Priors
a_raw ~ normal(0, 1);
a0 ~ normal(0, 1);
tau ~ normal(0, 1);
sigma ~ normal(0, 1);
//Likelihood
Y ~ normal(Y_hat, sigma);
}