-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathlib_ormp.cpp
More file actions
296 lines (252 loc) · 9.28 KB
/
Copy pathlib_ormp.cpp
File metadata and controls
296 lines (252 loc) · 9.28 KB
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
291
292
293
/*
* Copyright (c) 2011, Marc Lebrun <marc.lebrun@cmla.ens-cachan.fr>
* All rights reserved.
*
* This program is free software: you can use, modify and/or
* redistribute it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later
* version. You should have received a copy of this license along
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lib_ormp.cpp
* @brief ORMP process, based on the SPAMS toolbox by Julien Mairal
*
* @author Marc Lebrun <marc.lebrun@cmla.ens-cachan.fr>
**/
#include <iostream>
#include <math.h>
#ifdef _OPENMP
#include <omp.h>
#endif
#include "lib_ormp.h"
using namespace std;
#define MIN(a,b) (((a) > (b)) ? (b) : (a))
/**
* @brief compute an Orthogonal Recursive Matching Pursuit
*
* @param X : (Np x n) X[i] is the vector to be represented in D
* @param D : (k x n) dictionary (D[j] is the j-th atom)
* @param A : (k x Np) sparse coordinates : A[j][i] is the
* coordinate of X[i] on D[j]
**/
//! The matrix are accessed in column order i.e. X[i] is the i-th column of X
//! CONVENTION : we will denote by A_B the variable containing the
//! matrix transpose(A)*B (which contains the scalar products between the columns of A
//! and the columns of B.
void ormp_process(matD_t &X,
matD_t &D,
matU_t &ind_v,
matD_t &val_v,
unsigned L,
const double eps)
{
//! Declarations
const unsigned n = X[0].size();
const unsigned Np = X.size();
const unsigned k = D.size();
//! Initializations
if (L <= 0)
return;
L = MIN(n, MIN(L,k));
#pragma omp parallel shared(ind_v, val_v, X, D)
{
//! Declarations
vecD_t norm(k), scores(k), x_T(k);
matD_t A(L, vecD_t(L)), D_ELj(k, vecD_t(L)), D_D(k, vecD_t(k)), D_DLj(k, vecD_t(L));
//! Compute the scalar products between the atoms of the dictionary
for (unsigned j = 0; j < k; j++)
{
iterD_t it_D_D = D_D[j].begin();
for (unsigned i = 0; i < k; i++, it_D_D++)
{
iterD_t D_i = D[i].begin();
iterD_t D_j = D[j].begin();
long double val = 0;
for (unsigned s = 0; s < n; s++, D_i++, D_j++)
val += (long double) (*D_i) * (long double) (*D_j);
(*it_D_D) = (double) val;
}
}
#pragma omp for schedule(dynamic) nowait
for (unsigned i = 0; i < Np; ++i)
{
//! Initialization
ind_v[i].clear();
val_v[i].clear();
iterD_t X_i = X[i].begin();
//! Compute the norm of X[i]
long double normX = 0.0l;
for (iterD_t it_x = X_i; it_x < X[i].end(); it_x++)
normX += (long double) (*it_x) * (long double) (*it_x);
//! Compute the scalar products between X[i] and the elements
//! of the dictionary
for (unsigned j = 0; j < k; j++)
{
iterD_t it_d = D[j].begin();
iterD_t it_x = X_i;
long double val = 0.0l;
for (unsigned s = 0; s < n; s++, it_d++, it_x++)
val += (long double) (*it_d) * (long double) (*it_x);
x_T[j] = (double)val;
}
coreORMP(D, D_D, scores, norm, A, D_ELj, D_DLj, x_T,
ind_v[i], val_v[i], eps, (double) normX);
} //! End of I-lop
} //! End of parallel section
}
/**
* @brief Sub function of ormp_process
*
* @param D : dictionary;
* @param D_D : precomputed matrix D * D';
* @param scores[i] = <x, e_i^j>^2
* @param norm[i] = ||t_i^j||^2 = 1 - \sum_{p=0}^{j_1} <d_i, e_l_p>^2
* @param A : sparse coordinates
* @param D_ELj[i][j] : equals <d_i, e_l_j> at the end of the j-loop
* @param D_DLj[i][s] = <d_i, d_l_s>
* @param x_T[i] = <x, t_i^j> = <x, d_i> - \sum_{p=0}^{j-1} <d_i, e_l_p> <x, e_l_p>
* @param ind : will contain index of atoms of D at the end of the j-loop
* @param coord[q] = \alpha_l_q = \sum_{p=q}^j <x, e_l_p> a_{pq} : coordinate
* of x on d_l_q at the end of the j-loop
* @param eps : break condition
* @param normr = ||x||^2 - \sum_{p=0}^j <x, e_l_p>^2
*
* @return none.
**/
void coreORMP(matD_t &D,
matD_t &D_D,
vecD_t &scores,
vecD_t &norm,
matD_t &A,
matD_t &D_ELj,
matD_t &D_DLj,
vecD_t &x_T,
vecU_t &ind,
vecD_t &coord,
const double eps,
double normr)
{
//! Declarations
const unsigned L = A.size();
const unsigned p = D.size();
if (normr <= eps || L == 0)
return;
//! Initializations
scores = x_T;
for (iterD_t it = norm.begin(); it < norm.end(); it++)
*it = 1.0l;
for (matD_t::iterator it_A = A.begin(); it_A < A.end(); it_A++)
for (iterD_t it = it_A->begin(); it < it_A->end(); it++)
*it = 0.0l;
//! Declarations
iterD_t A_j, it_A_j, it_D_ELj_lj, it_gs, x_T_i, norm_i, scores_i, it_A_j_tmp;
iterD_t D_lj, it_D_DLj;
matD_t::iterator it_D_ELj, it_A;
vecD_t x_el;
//! Loop over j
unsigned j;
for (j = 0; j < L; j++)
{
//! Initialization
const unsigned lj = ind_fmax(scores);
A_j = A[j].begin();
//! Stop if we cannot inverse norm[lj]
if (norm[lj] < 1e-6)
break;
const long double invNorm = 1.0l / (long double) sqrtl(norm[lj]);
const long double x_elj = (long double) x_T[lj] * invNorm;
const long double delta = x_elj * x_elj;
x_el.push_back(x_elj);
coord.push_back(x_elj); //! The coordinate of x on the last chosen vector
normr = (double) ((long double) normr - delta);//! Update of the residual
ind.push_back(lj); //! Memorize the chosen index
//! Gram-Schmidt Algorithm, Update of A
it_A_j = A_j;
it_D_ELj_lj = D_ELj[lj].begin();
for (unsigned i = 0; i < j; i++, it_A_j++, it_D_ELj_lj++)
(*it_A_j) = (*it_D_ELj_lj);
it_A_j = A_j;
for (unsigned i = 0; i < j; i++, it_A_j++)
{
long double sum = 0.0l;
it_A = A.begin() + i;
it_A_j_tmp = it_A_j;
for (unsigned s = 0; s < j - i; s++, it_A++, it_A_j_tmp++)
sum -= (long double) (*it_A)[i] * (long double) (*it_A_j_tmp);
(*it_A_j) = (double) (sum * invNorm);
}
(*it_A_j) = (double) invNorm;
if (j == L-1 || (normr <= eps))
{
j++;
break;
}
//! Update of D_DLj
it_D_DLj = D_D[lj].begin();
for (unsigned i = 0; i < p; i++, it_D_DLj++)
D_DLj[i][j] = (*it_D_DLj);
//! Compute the scalar product D[j]_D[lj] and memorize it now
long double val = 0.0l;
D_lj = D[lj].begin();
for (iterD_t D_j = D[j].begin(); D_j < D[j].end(); D_j++, D_lj++)
val += (long double) (*D_j) * (long double) (*D_lj);
D_DLj[j][j] = (double) val;
//! Update of D_ELj, x_T, norm, and scores.
x_T_i = x_T.begin();
norm_i = norm.begin();
scores_i = scores.begin();
it_D_ELj = D_ELj.begin();
for (unsigned i = 0; i < p; i++, x_T_i++, norm_i++, scores_i++, it_D_ELj++)
{
long double val = 0;
it_A_j = A_j;
it_gs = D_DLj[i].begin();
for (unsigned s = 0; s < j + 1; s++, it_A_j++, it_gs++)
val += (long double) (*it_A_j) * (long double) (*it_gs);
(*it_D_ELj)[j] = (double) val;
(*x_T_i) = (double) ((long double) (*x_T_i) - x_elj * val);
(*norm_i) = (double) ((long double) (*norm_i) - val * val);
(*scores_i) = (double) ((long double) (*x_T_i) * (long double) (*x_T_i) \
/ (long double) (*norm_i));
}
for (iterU_t ind_s = ind.begin(); ind_s <= ind.begin() + j; ind_s++)
scores[*ind_s] = double();
}
//! Compute the final coordinates of x on the chosen atoms of the dictionary
iterD_t it_coord = coord.begin();
for (unsigned i = 0; i < j; i++, it_coord++)
{
long double sum = 0;
matD_t::iterator it_a = A.begin() + i;
iterD_t it_x = x_el.begin() + i;
for (unsigned s = 0; s < j - i; s++, it_a++, it_x++)
sum += (long double) (*it_a)[i] * (long double) (*it_x);
(*it_coord) = (double) sum;
}
}
/**
* @brief Find the index of the maximum absolute value
* of a table
*
* @param V : table of values.
*
* @return : return the index of the maximum absolute
* value of V.
**/
unsigned ind_fmax(vecD_t &V)
{
double val = 0.0f;
unsigned ind = 0;
iterD_t it_v;
unsigned j = 0;
//! Find the index of the maximum of V
for (it_v = V.begin(); it_v < V.end(); it_v++, j++)
if (val < fabs(*it_v))
{
val = fabs(*it_v);
ind = j;
}
return ind;
}