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>)
27 static constexpr bool scalar_weight = std::is_same_v<weight_t, real_t>;
30 const char *
msg =
"L1Norm::λ must be nonnegative";
31 if constexpr (scalar_weight) {
32 if (λ < 0 || !std::isfinite(λ))
33 throw std::invalid_argument(
msg);
35 if ((λ.array() < 0).any() || !λ.allFinite())
36 throw std::invalid_argument(
msg);
41 requires(scalar_weight)
44 requires(!scalar_weight)
55 if constexpr (scalar_weight) {
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);
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>)
98 static constexpr bool scalar_weight = std::is_same_v<weight_t, real_t>;
101 const char *
msg =
"L1NormComplex::λ must be nonnegative";
102 if constexpr (scalar_weight) {
103 if (λ < 0 || !std::isfinite(λ))
104 throw std::invalid_argument(
msg);
106 if ((λ.array() < 0).any() || !λ.allFinite())
107 throw std::invalid_argument(
msg);
112 requires(scalar_weight)
115 requires(!scalar_weight)
126 if constexpr (scalar_weight) {
133 auto mag2 = x.real() * x.real() + x.imag() * x.imag();
137 return λ * norm_1(out.reshaped());
139 if constexpr (std::is_same_v<weight_t, vec>)
141 λ = weight_t::Ones(n);
144 assert((λ.array() >= 0).all());
147 auto mag2 = x.real() * x.real() + x.imag() * x.imag();
151 return norm_1(out.cwiseProduct(λ).reshaped());
158 assert(out.rows() % 2 == 0);
160 util::start_lifetime_as_array<cplx_t>(
in.data(),
in.size() / 2),
165 util::start_lifetime_as_array<cplx_t>(out.data(), out.size() / 2),
174 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.
std::decay_t< decltype(Tag)> tag_t
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
ℓ₁-norm of complex numbers.
real_t prox(crmat in, rmat out, real_t γ=1)
Note: a complex vector in ℂⁿ is represented by a real vector in ℝ²ⁿ.
friend real_t alpaqa_tag_invoke(tag_t< alpaqa::prox >, L1NormComplex &self, crmat in, rmat out, real_t γ)
real_t prox(crcmat in, rcmat out, real_t γ=1)
L1NormComplex(weight_t λ)
real_t prox(crmat in, rmat out, real_t γ=1)
friend real_t alpaqa_tag_invoke(tag_t< alpaqa::prox >, L1Norm &self, crmat in, rmat out, real_t γ)