5#include <guanaqo/lifetime.hpp>
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>)
30 const char *msg =
"L1Norm::λ must be nonnegative";
32 if (
λ < 0 || !std::isfinite(
λ))
33 throw std::invalid_argument(msg);
35 if ((
λ.array() < 0).any() || !
λ.allFinite())
36 throw std::invalid_argument(msg);
50 assert(in.cols() == 1);
51 assert(out.cols() == 1);
52 assert(in.size() == out.size());
61 auto step = vec::Constant(n,
λ * γ);
62 out = vec::Zero(n).cwiseMax(in - step).cwiseMin(in + step);
63 return λ * norm_1(out.reshaped());
65 if constexpr (std::is_same_v<weight_t, vec>)
67 λ = weight_t::Ones(n);
68 assert(
λ.cols() == 1);
69 assert(in.size() ==
λ.size());
70 assert((
λ.array() >= 0).all());
72 out = vec::Zero(n).cwiseMax(in - step).cwiseMin(in + step);
73 return norm_1(out.cwiseProduct(
λ).reshaped());
79 return self.
prox(std::move(in), std::move(out), γ);
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>)
101 const char *msg =
"L1NormComplex::λ must be nonnegative";
103 if (
λ < 0 || !std::isfinite(
λ))
104 throw std::invalid_argument(msg);
106 if ((
λ.array() < 0).any() || !
λ.allFinite())
107 throw std::invalid_argument(msg);
121 assert(in.cols() == 1);
122 assert(out.cols() == 1);
123 assert(in.size() == out.size());
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));
136 out = in.unaryExpr(soft_thres);
137 return λ * norm_1(out.reshaped());
139 if constexpr (std::is_same_v<weight_t, vec>)
141 λ = weight_t::Ones(n);
142 assert(
λ.cols() == 1);
143 assert(in.size() ==
λ.size());
144 assert((
λ.array() >= 0).all());
147 auto mag2 = x.real() * x.real() + x.imag() * x.imag();
148 return mag2 <= γλ * γλ ? 0 : x * (1 - γλ / std::sqrt(mag2));
150 out = in.binaryExpr(
λ, soft_thres);
151 return norm_1(out.cwiseProduct(
λ).reshaped());
157 assert(in.rows() % 2 == 0);
158 assert(out.rows() % 2 == 0);
159 using guanaqo::start_lifetime_as_array;
161 start_lifetime_as_array<cplx_t>(in.data(), in.size() / 2),
166 start_lifetime_as_array<cplx_t>(out.data(), out.size() / 2),
170 return prox(cplx_in, cplx_out, γ);
175 return self.
prox(std::move(in), std::move(out), γ);
#define USING_ALPAQA_CONFIG(Conf)
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.
typename Conf::crcmat crcmat
typename Conf::crmat crmat
typename Conf::cmcmat cmcmat
typename Conf::real_t real_t
typename Conf::rcmat rcmat
typename Conf::length_t length_t
typename Conf::cplx_t cplx_t
typename Conf::mcmat mcmat
real_t prox(crmat in, rmat out, real_t γ=1)
Note: a complex vector in ℂⁿ is represented by a real vector in ℝ²ⁿ.
real_t prox(crcmat in, rcmat out, real_t γ=1)
L1NormComplex(weight_t λ)
static constexpr bool scalar_weight
friend real_t guanaqo_tag_invoke(tag_t< alpaqa::prox >, L1NormComplex &self, crmat in, rmat out, real_t γ)
real_t prox(crmat in, rmat out, real_t γ=1)
static constexpr bool scalar_weight
friend real_t guanaqo_tag_invoke(tag_t< alpaqa::prox >, L1Norm &self, crmat in, rmat out, real_t γ)