-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRBCD_size1_gc_u.cpp
290 lines (288 loc) · 9.78 KB
/
RBCD_size1_gc_u.cpp
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
#include <math.h>
#include "mex.h"
#define EPSILON 2.220446e-16
/**
* RBCD size 1 with general constraints
**/
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
/** input args
* [1] Matrix A
* [2] Vettor b
* [3] dimension d
* [4] max iters
* [5] precision of KKT conditions
* here the lower and upper bounds are
* set by the input parameters
* if the number of inputs is 5, then it has default constraint [0,1]
* if the number of inputs is 7, then the last two are constraints
* if lower is greater than upper, then there will be no constraints
* [6] lower bound l
* [7] upper bound u
* [8] initial value of out_x
* [9] random parameter alpha
*/
// first check the number of input values
if(nrhs!=9){mexErrMsgTxt("Input Value Error"); return;}
// [1]
double *in_A;
mwIndex *irs;// for sparse matrix
mwIndex *jcs;// for sparse matrix
// [2]
double *in_b;
// [3]
long int in_d;
// [4]
long int in_max_iter;
// [5]
double in_precision;
// [6]
double lower;
// [7]
double upper;
// [8]
double in_init;
// [9]
double in_alpha;
/** ouput args
* [1] the minimizer out_x
* [2] the KKT condition residual
* the length will be adjusted in the end,
* and final output is *r
*/
// [1]
double *out_x;
// [2]
double residual;
// parameters in the function
long int i,j,epoch;//loop
double df;
double RV;//random variable for RBCD
// get input args
// [1]
in_A = mxGetPr(prhs[0]);if(in_A==NULL){mexErrMsgTxt("pointer in_A is null"); return;}
irs = mxGetIr(prhs[0]);if(irs==NULL){mexErrMsgTxt("pointer irs is null"); return;}
jcs = mxGetJc(prhs[0]);if(jcs==NULL){mexErrMsgTxt("pointer jcs is null"); return;}
// [2]
in_b = mxGetPr(prhs[1]);if(in_b==NULL){mexErrMsgTxt("pointer in_b is null"); return;}
// [3]
in_d = mxGetScalar(prhs[2]);if(in_d<=1){mexErrMsgTxt("pointer in_d is null"); return;}
// [4]
in_max_iter = mxGetScalar(prhs[3]);if(in_max_iter<=0){mexErrMsgTxt("max_iter can not be 0"); return;}
// [5]
in_precision = mxGetScalar(prhs[4]);if(in_max_iter<=0){mexErrMsgTxt("precisionr can not be 0"); return;}
// [6]
lower = mxGetScalar(prhs[5]);
// [7]
upper = mxGetScalar(prhs[6]);
// [8]
in_init = mxGetScalar(prhs[7]);
// [9]
in_alpha = mxGetScalar(prhs[8]);
/* make sure that the upper bound is larger than the lower bound
* if the lower bound is greater,
* then we solve for an unconstrained problem, with init 0
*/
if (lower>=upper){mexPrintf("Bounds Error, Results without constraints\n");in_init=0;}
/* if the in_init is out of the bound, set it as lower */
else if ((in_init<lower)||(in_init>upper)){in_init=lower;}
/* Non-Zero elements, is the value of last entry of jcs
* lengths of in_A and irs are both NZmax
* length of jcs is in_d + 1, and the last entry of jcs has value NZmax
*/
double sparsity = jcs[in_d]/double(in_d*in_d);
mexPrintf("RBCD size 1.cpp...Sparsity = %.5f.\n",sparsity);
// [1] allocate output, and init as all in_init
plhs[0] = mxCreateDoubleMatrix(in_d,1,mxREAL);
out_x = mxGetPr(plhs[0]);if(out_x==NULL){mexErrMsgTxt("pointer out_x is null"); return;}
for (i=0;i<in_d;i++){
out_x[i] = in_init;
}
// [2] pre-allocate output of residual, length as max_iter
double* out_r=new double[in_max_iter]; if(out_r==NULL){mexErrMsgTxt("pointer out_r is null"); return;}
// in-code parameters
// allocate gradient, will delete later
double* grad=new double[in_d]; if(grad==NULL){mexErrMsgTxt("pointer grad is null"); return;}
// allocate diagonal, for solving small block problem
double* diag_A=new double[in_d]; if(diag_A==NULL){mexErrMsgTxt("pointer diag_A is null"); return;}
/*grad and residual of init loop
*out_x is initialized as in_init
*in the loop the elements from the diagonal are also extracted
*/
// init gradient as 0s
// extract i th element in diagonal
for (i=0;i<in_d;i++){
grad[i]=0;
// i th diag_A[]
diag_A[i]=0;
for (j=jcs[i];j<jcs[i+1];j++){
if (irs[j]==i){
diag_A[i]=in_A[j];
//mexPrintf("diag_A[%d]=%.5f;\n",i,in_A[j]);
}
}
}
// update gradient
for (j=0;j<in_d;j++){
for (i=jcs[j];i<jcs[j+1];i++){
grad[irs[i]] += in_A[i]*in_init;
}
}
// get the residual of KKT condition
residual = 0;
// if with constraints
if (lower<upper){
for (i=0;i<in_d;i++){
// i th residual
df = grad[i]-in_b[i];
if (in_init<=lower+2*EPSILON){
if (df<0){
residual += df*df;
}
}
else if (in_init>=upper-2*EPSILON){
if (df>0){
residual += df*df;
}
}
else {
residual += df*df;
}
}
}
// if without constraints
else{
for (i=0;i<in_d;i++){
// i th residual
df = grad[i]-in_b[i];
residual += df*df;
}
}
residual = sqrt(residual);
out_r[0] = residual;
mexPrintf("init: 0, residual=%.15f\n",residual);
epoch=1;
/* if the bounds are defined, and lower<upper
* we take them as [lower,upper]
* then do the following
*/
if (lower<upper){
while ((residual>in_precision)&&(epoch<in_max_iter)){
// KKT condition is calculated every in_d/2 updates, i.e. one epoch
for (long int loop_number=0;loop_number<in_d;loop_number++){
// get the random index i, in the range of [0,in_d-1]
RV = ((double)rand())/((double)RAND_MAX+1.0);
i=RV*(in_d);
/*calc temporal grad
*Since A is symmetric, A(i,:)*x(i) can be
*replaced by A(:,i)*x(i)
*/
for (j=jcs[i];j<jcs[i+1];j++){
grad[irs[j]] -= in_A[j]*out_x[i];
}
// descent
out_x[i] = (in_b[i]-grad[i])/diag_A[i];
// bounds
if (out_x[i]>upper){
out_x[i] = upper;
}
else if (out_x[i]<lower){
out_x[i] = lower;
}
// update temporal grad
for (j=jcs[i];j<jcs[i+1];j++){
grad[irs[j]] += in_A[j]*out_x[i];
}
}
// init gradient as 0s
for (i=0;i<in_d;i++){
grad[i]=0;
}
// update true gradient
for (j=0;j<in_d;j++){
for (i=jcs[j];i<jcs[j+1];i++){
grad[irs[i]] += in_A[i]*out_x[j];
}
}
// get the residual
residual = 0;
for (i=0;i<in_d;i++){
// i th residual
df = grad[i]-in_b[i];
if (out_x[i]<=lower+2*EPSILON){
if (df<0){
residual += df*df;
}
}
else if (out_x[i]>=upper-2*EPSILON){
if (df>0){
residual += df*df;
}
}
else {
residual += df*df;
}
}
residual = sqrt(residual);
out_r[epoch] = residual;
//mexPrintf("epoch:%5d, residual=%.15f\n",epoch,residual);
epoch++;
}
}
/* if the bounds are defined, but lower>=upper
* we take them as unconstrained
* then do the following
*/
else if (lower>=upper){
while ((residual>in_precision)&&(epoch<in_max_iter)){
// KKT condition is calculated every in_d/2 updates, i.e. one epoch
for (long int loop_number=0;loop_number<in_d;loop_number++){
// get the random index i, in the range of [0,in_d-1]
RV = ((double)rand())/((double)RAND_MAX+1.0);
i=RV*(in_d);
/*calc temporal grad
*Since A is symmetric, A(i,:)*x(i) can be
*replaced by A(:,i)*x(i)
*/
for (j=jcs[i];j<jcs[i+1];j++){
grad[irs[j]] -= in_A[j]*out_x[i];
}
// descent
// without bounds
out_x[i] = (in_b[i]-grad[i])/diag_A[i];
// update temporal grad
for (j=jcs[i];j<jcs[i+1];j++){
grad[irs[j]] += in_A[j]*out_x[i];
}
}
// init gradient as 0s
for (i=0;i<in_d;i++){
grad[i]=0;
}
// update true gradient
for (j=0;j<in_d;j++){
for (i=jcs[j];i<jcs[j+1];i++){
grad[irs[i]] += in_A[i]*out_x[j];
}
}
// get the residual
residual = 0;
for (i=0;i<in_d;i++){
// i th residual
df = grad[i]-in_b[i];
residual += df*df;
}
residual = sqrt(residual);
out_r[epoch] = residual;
//mexPrintf("epoch:%5d, residual=%.15f\n",epoch,residual);
epoch++;
}
}
plhs[1] = mxCreateDoubleMatrix(epoch,1,mxREAL);
double* r = mxGetPr(plhs[1]);if(r==NULL){mexErrMsgTxt("pointer r is null"); return;}
for (i=0;i<epoch;i++){
r[i]=out_r[i];
}
delete grad; delete out_r; delete diag_A;
mexPrintf("epoch:%5d, residual=%.15f\nEnd of RBCD size 1.cpp\n",epoch-1,residual);
}