alpaqa develop
Nonconvex constrained optimization
Loading...
Searching...
No Matches
l1-norm.hpp
Go to the documentation of this file.
1#pragma once
2
6#include <cassert>
7#include <cmath>
8#include <stdexcept>
9
11
12/// ℓ₁-norm.
13/// @ingroup grp_Functions
14/// @tparam Weight
15/// Type of weighting factors. Either scalar or vector.
16template <Config Conf, class Weight = typename Conf::real_t>
17 requires(std::is_same_v<Weight, typename Conf::real_t> ||
18 std::is_same_v<Weight, typename Conf::vec> ||
19 std::is_same_v<Weight, typename Conf::rvec> ||
20 std::is_same_v<Weight, typename Conf::crvec> ||
21 std::is_same_v<Weight, typename Conf::mat> ||
22 std::is_same_v<Weight, typename Conf::rmat> ||
23 std::is_same_v<Weight, typename Conf::crmat>)
24struct L1Norm {
27 static constexpr bool scalar_weight = std::is_same_v<weight_t, real_t>;
28
29 L1Norm(weight_t λ) : λ{std::move(λ)} {
30 const char *msg = "L1Norm::λ must be nonnegative";
31 if constexpr (scalar_weight) {
32 if (λ < 0 || !std::isfinite(λ))
33 throw std::invalid_argument(msg);
34 } else {
35 if ((λ.array() < 0).any() || !λ.allFinite())
36 throw std::invalid_argument(msg);
37 }
38 }
39
41 requires(scalar_weight)
42 : λ{1} {}
44 requires(!scalar_weight)
45 = default;
46
48
49 real_t prox(crmat in, rmat out, real_t γ = 1) {
50 assert(in.cols() == 1);
51 assert(out.cols() == 1);
52 assert(in.size() == out.size());
53 using vec_util::norm_1;
54 const length_t n = in.size();
55 if constexpr (scalar_weight) {
56 assert(λ >= 0);
57 if (λ == 0) {
58 out = in;
59 return 0;
60 }
61 auto step = vec::Constant(n, λ * γ);
62 out = vec::Zero(n).cwiseMax(in - step).cwiseMin(in + step);
63 return λ * norm_1(out.reshaped());
64 } else {
65 if constexpr (std::is_same_v<weight_t, vec>)
66 if (λ.size() == 0)
67 λ = weight_t::Ones(n);
68 assert(λ.cols() == 1);
69 assert(in.size() == λ.size());
70 assert((λ.array() >= 0).all());
71 auto step = λ * γ;
72 out = vec::Zero(n).cwiseMax(in - step).cwiseMin(in + step);
73 return norm_1(out.cwiseProduct(λ).reshaped());
74 }
75 }
76
78 rmat out, real_t γ) {
79 return self.prox(std::move(in), std::move(out), γ);
80 }
81};
82
83/// ℓ₁-norm of complex numbers.
84/// @ingroup grp_Functions
85/// @tparam Weight
86/// Type of weighting factors. Either scalar or vector.
87template <Config Conf, class Weight = typename Conf::real_t>
88 requires(std::is_same_v<Weight, typename Conf::real_t> ||
89 std::is_same_v<Weight, typename Conf::vec> ||
90 std::is_same_v<Weight, typename Conf::rvec> ||
91 std::is_same_v<Weight, typename Conf::crvec> ||
92 std::is_same_v<Weight, typename Conf::mat> ||
93 std::is_same_v<Weight, typename Conf::rmat> ||
94 std::is_same_v<Weight, typename Conf::crmat>)
98 static constexpr bool scalar_weight = std::is_same_v<weight_t, real_t>;
99
100 L1NormComplex(weight_t λ) : λ{std::move(λ)} {
101 const char *msg = "L1NormComplex::λ must be nonnegative";
102 if constexpr (scalar_weight) {
103 if (λ < 0 || !std::isfinite(λ))
104 throw std::invalid_argument(msg);
105 } else {
106 if ((λ.array() < 0).any() || !λ.allFinite())
107 throw std::invalid_argument(msg);
108 }
109 }
110
112 requires(scalar_weight)
113 : λ{1} {}
115 requires(!scalar_weight)
116 = default;
117
119
120 real_t prox(crcmat in, rcmat out, real_t γ = 1) {
121 assert(in.cols() == 1);
122 assert(out.cols() == 1);
123 assert(in.size() == out.size());
124 using vec_util::norm_1;
125 const length_t n = in.size();
126 if constexpr (scalar_weight) {
127 assert(λ >= 0);
128 if (λ == 0) {
129 out = in;
130 return 0;
131 }
132 auto soft_thres = [γλ{γ * λ}](cplx_t x) {
133 auto mag2 = x.real() * x.real() + x.imag() * x.imag();
134 return mag2 <= γλ * γλ ? 0 : x * (1 - γλ / std::sqrt(mag2));
135 };
136 out = in.unaryExpr(soft_thres);
137 return λ * norm_1(out.reshaped());
138 } else {
139 if constexpr (std::is_same_v<weight_t, vec>)
140 if (λ.size() == 0)
141 λ = weight_t::Ones(n);
142 assert(λ.cols() == 1);
143 assert(in.size() == λ.size());
144 assert((λ.array() >= 0).all());
145 auto soft_thres = [γ](cplx_t x, real_t λ) {
146 real_t γλ = γ * λ;
147 auto mag2 = x.real() * x.real() + x.imag() * x.imag();
148 return mag2 <= γλ * γλ ? 0 : x * (1 - γλ / std::sqrt(mag2));
149 };
150 out = in.binaryExpr(λ, soft_thres);
151 return norm_1(out.cwiseProduct(λ).reshaped());
152 }
153 }
154
155 /// Note: a complex vector in ℂⁿ is represented by a real vector in ℝ²ⁿ.
156 real_t prox(crmat in, rmat out, real_t γ = 1) {
157 assert(in.rows() % 2 == 0);
158 assert(out.rows() % 2 == 0);
160 util::start_lifetime_as_array<cplx_t>(in.data(), in.size() / 2),
161 in.rows() / 2,
162 in.cols(),
163 };
165 util::start_lifetime_as_array<cplx_t>(out.data(), out.size() / 2),
166 out.rows() / 2,
167 out.cols(),
168 };
169 return prox(cplx_in, cplx_out, γ);
170 }
171
173 crmat in, rmat out, real_t γ) {
174 return self.prox(std::move(in), std::move(out), γ);
175 }
176};
177
178} // namespace alpaqa::functions
#define USING_ALPAQA_CONFIG(Conf)
Definition config.hpp:77
struct alpaqa::prox_fn prox
Compute the proximal mapping.
auto norm_1(const Eigen::MatrixBase< Derived > &v)
Get the 1-norm of the given vector.
Definition config.hpp:212
std::decay_t< decltype(Tag)> tag_t
typename Conf::crcmat crcmat
Definition config.hpp:102
typename Conf::crmat crmat
Definition config.hpp:97
typename Conf::rmat rmat
Definition config.hpp:96
typename Conf::cmcmat cmcmat
Definition config.hpp:100
typename Conf::real_t real_t
Definition config.hpp:86
typename Conf::rcmat rcmat
Definition config.hpp:101
typename Conf::length_t length_t
Definition config.hpp:103
constexpr const auto inf
Definition config.hpp:112
typename Conf::cplx_t cplx_t
Definition config.hpp:87
typename Conf::mcmat mcmat
Definition config.hpp:99
ℓ₁-norm of complex numbers.
Definition l1-norm.hpp:95
real_t prox(crmat in, rmat out, real_t γ=1)
Note: a complex vector in ℂⁿ is represented by a real vector in ℝ²ⁿ.
Definition l1-norm.hpp:156
friend real_t alpaqa_tag_invoke(tag_t< alpaqa::prox >, L1NormComplex &self, crmat in, rmat out, real_t γ)
Definition l1-norm.hpp:172
real_t prox(crcmat in, rcmat out, real_t γ=1)
Definition l1-norm.hpp:120
real_t prox(crmat in, rmat out, real_t γ=1)
Definition l1-norm.hpp:49
friend real_t alpaqa_tag_invoke(tag_t< alpaqa::prox >, L1Norm &self, crmat in, rmat out, real_t γ)
Definition l1-norm.hpp:77