-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathproj.h
More file actions
59 lines (50 loc) · 1.87 KB
/
Copy pathproj.h
File metadata and controls
59 lines (50 loc) · 1.87 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
#ifndef MC_L1_PROJ_H
#define MC_L1_PROJ_H
#include "blaze/Math.h"
#include "macros.h"
namespace minicore {
// Implemements projection to L1 ball
// Algorithm 2 in D Sculley, Web-scale K-means clustering
template<typename VT, bool TF>
INLINE double sum_min_theta(const blaze::DenseVector<VT, TF> &vector, double theta) {
return blaze::sum(blaze::max(0., blaze::abs(*vector) - theta));
}
template<typename VT, bool TF>
INLINE double sum_min_theta(const blaze::SparseVector<VT, TF> &vector, double theta) {
return std::accumulate((*vector).begin(),(*vector).end(), 0., [theta](double sum, const auto &pair) {return sum + std::max(0., pair.value() - theta);});
}
// Perform L1-ball projection
template<typename VT, bool TF>
INLINE void set_min_theta(blaze::DenseVector<VT, TF> &vector, double theta) {
for(size_t i = 0; i < (*vector).size(); ++i) {
auto &v = (*vector)[i];
if(v > theta) v -= theta;
else if(v < -theta) v += theta;
else v = 0.;
}
}
template<typename VT, bool TF>
INLINE void set_min_theta(blaze::SparseVector<VT, TF> &vector, double theta) {
(*vector).erase([theta](auto &x) {
if(x < -theta) x += theta;
else if(x > theta) x -= theta;
else x = 0.;
return x == 0.;
});
}
template<typename VT, bool TF>
void eps_l1(blaze::Vector<VT, TF> &vector, double radius, double eps=1e-10) {
auto &v = *vector;
double l1n = blaze::l1Norm(v);
if(l1n <= radius + eps) return;
double lower = 0., current = l1n, upper = blaze::maxNorm(v);
static constexpr bool is_sparse = blaze::IsSparseVector_v<VT>;
while(current < radius || current > (radius * (1. + eps))) {
double theta = .5 * upper + .5 * lower;
current = sum_min_theta(v, theta);
if(current <= theta) upper = theta;
else lower = theta;
}
}
} // namespace minicore
#endif