-
Notifications
You must be signed in to change notification settings - Fork 6
/
varselect_thermo.m
158 lines (128 loc) · 3.6 KB
/
varselect_thermo.m
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
function [binaries, energies, state_out] = varselect_thermo(inputs, data, phis, a, b, atau, btau, way3, target, gibdraws, thermdraws, state_in)
% uses a thermodynamic 'spin flip' Monte Carlo sampler for variable
% selection in a large input dataset
% 'm' is the length of the dataset and 'n' is the number of inputs
[~, n] = size(inputs);
% one basis function for every main effect and two way interaction in this
% version. more terms possibly added later . . .
vecsize = n + n*(n-1)/2;
if way3
vecsize = vecsize + n*(n-1)*(n-2)/6;
end
binaries = zeros(thermdraws, vecsize);
energies = zeros(thermdraws, 1);
% get the initial distribution of spins
if nargin == 13
spinvec = state_in;
else
spinvec = round(rand(1, vecsize));
end
% the full-sized interaction matrix
mtx = zeros(vecsize, n);
mtx(1:n,1:n) = eye(n);
ind = n+1;
for i=1:n-1
for j=i+1:n
mtx(ind, i) = 1;
mtx(ind, j) = 1;
ind = ind + 1;
end
end
if way3
ind = n + n*(n-1)/2 + 1;
for i=1:n-2
for j=i+1:n-1
for k=j+1:n
mtx(ind, i) = 1;
mtx(ind, j) = 1;
mtx(ind, k) = 1;
ind = ind + 1;
end
end
end
end
datsize = length(data);
X = zeros(datsize, vecsize);
for i=1:datsize
phind = ceil(inputs(i,:)*499);
phind = phind + (phind == 0);
for j=1:vecsize
phi = 1;
for k=1:n
num = mtx(j,k);
if num
x = 499*inputs(i,k) - phind(k) + 1;
phi = phi*(phis{num}.zero(phind(k)) + phis{num}.one(phind(k))*x + phis{num}.two(phind(k))*x^2 + phis{num}.three(phind(k))*x^3);
end
end
X(i,j) = phi;
end
end
% calculate the initial energy & add it to the distribution along with its
% configuration
binaries(1,:) = spinvec;
damtx = zeros(sum(spinvec),n);
Xin = zeros(datsize, sum(spinvec));
ind = 1;
for j=1:vecsize
if (spinvec(j))
damtx(ind,:) = mtx(j,:);
Xin(:,ind) = X(:,j);
ind = ind + 1;
end
end
[~, ~, ~, ~, ~, energies(1)] = gibbs(inputs, data, phis, Xin, damtx, a, b, atau, btau, gibdraws);
temp = abs(energies(1)/2);
accept = 1;
for i=2:thermdraws
flipper = randi(vecsize);
if spinvec(flipper)
spinvec(flipper) = 0;
else
spinvec(flipper) = 1;
end
damtx = zeros(sum(spinvec),n);
Xin = zeros(datsize, sum(spinvec));
ind = 1;
for j=1:vecsize
if (spinvec(j))
damtx(ind,:) = mtx(j,:);
Xin(:,ind) = X(:,j);
ind = ind + 1;
end
end
[~, ~, ~, ~, ~, energie] = gibbs(inputs, data, phis, Xin, damtx, a, b, atau, btau, gibdraws);
% Metropolis
if energie < energies(i-1)
binaries(i,:) = spinvec;
energies(i) = energie;
accept = accept + 1;
elseif rand < exp((energies(i-1) - energie)/temp)
binaries(i,:) = spinvec;
energies(i) = energie;
accept = accept + 1;
else
binaries(i,:) = binaries(i-1,:);
energies(i) = energies(i-1);
spinvec = binaries(i,:);
end
if mod(i, 100) == 0
if accept/100 < target
temp = 2*temp;
elseif accept/100 > target
temp = 0.5*temp;
end
disp(temp)
accept = 0;
% if accept/100 < 0.8*target
% temp = 1.5*temp;
% elseif accept/100 > 1.2*target
% temp = 0.5*temp;
% end
% disp(temp)
% accept = 0;
end
disp([i energies(i)])
end
state_out = binaries(thermdraws,:);
end