@@ -80,6 +80,7 @@ void reset_fv_set(std::vector<std::pair<Index, Index>>& fvset, std::size_t n, st
8080// * S, T, Tau: [H x n]
8181// * A : [K x d]
8282// * b : [K]
83+ // * rho : [d]
8384// - Pre-computed
8485// * r: [n]
8586// * p: [K]
@@ -139,6 +140,7 @@ class ReHLineSolver
139140 const Index m_L;
140141 const Index m_H;
141142 const Index m_K;
143+ const Index m_W;
142144
143145 // Input matrices and vectors
144146 RMatrix m_X;
@@ -149,7 +151,7 @@ class ReHLineSolver
149151 ConstRefMat m_Tau;
150152 RMatrix m_A;
151153 ConstRefVec m_b;
152- Scalar m_rho; // l1_ratio / (1 - l1_ratio)
154+ ConstRefVec m_rho;
153155
154156 // Pre-computed
155157 Vector m_gk_denom; // ||a[k]||^2
@@ -174,7 +176,7 @@ class ReHLineSolver
174176 // =================== Initialization functions =================== //
175177
176178 // Compute the primal variable beta from dual variables
177- // beta = A'xi - U3 * vec(Lambda) - S3 * vec(Gamma)
179+ // beta = A'xi - U3 * vec(Lambda) - S3 * vec(Gamma) + 2 * Mu - rho
178180 // A can be empty, one of U and V may be empty
179181 inline void set_primal ()
180182 {
@@ -193,9 +195,9 @@ class ReHLineSolver
193195 if (m_H > 0 )
194196 LHterm.noalias () += m_S.cwiseProduct (m_Gamma).colwise ().sum ().transpose ();
195197 m_beta.noalias () -= m_X.transpose () * LHterm;
196-
197- if (m_rho > 0 )
198- m_beta.noalias () += Scalar (2.0 ) * m_mu - m_rho * Vector::Ones (m_d) ;
198+ // L1 related
199+ if (m_W > 0 )
200+ m_beta.noalias () += Scalar (2.0 ) * m_mu - m_rho;
199201 }
200202
201203 // =================== Evaluating objection function =================== //
@@ -224,7 +226,7 @@ class ReHLineSolver
224226 // Quadratic term
225227 result += Scalar (0.5 ) * m_beta.squaredNorm ();
226228 // L1 penalty term
227- result += m_rho * m_beta.template lpNorm < 1 > ();
229+ result += m_beta.cwiseAbs (). cwiseProduct (m_rho). sum ();
228230 return result;
229231 }
230232
@@ -251,8 +253,8 @@ class ReHLineSolver
251253 }
252254 // 2 * Mu - rho, [d x 1]
253255 Vector MuR = Vector::Zero (m_d);
254- if (m_rho > 0 )
255- MuR = Scalar (2.0 ) * m_mu - m_rho * Vector::Ones (m_d) ;
256+ if (m_W > 0 )
257+ MuR = Scalar (2.0 ) * m_mu - m_rho;
256258 // Compute dual objective function value
257259 Scalar obj = Scalar (0 );
258260 // If K = 0, all terms that depend on A, xi, or b will be zero
@@ -261,30 +263,31 @@ class ReHLineSolver
261263 // 0.5 * ||Atxi||^2 - Atxi' * U3L - Atxi' * S3G + Atxi' MuR + xi' * b
262264 const Scalar Atxi_U3L = (m_L > 0 ) ? (Atxi.dot (U3L )) : Scalar (0 );
263265 const Scalar Atxi_S3G = (m_H > 0 ) ? (Atxi.dot (S3G )) : Scalar (0 );
264- const Scalar Atxi_MuR = (m_rho > 0 ) ? (Atxi.dot (MuR)) : Scalar (0 );
266+ const Scalar Atxi_MuR = (m_W > 0 ) ? (Atxi.dot (MuR)) : Scalar (0 );
265267 obj += Scalar (0.5 ) * Atxi.squaredNorm () - Atxi_U3L - Atxi_S3G + Atxi_MuR + m_xi.dot (m_b);
266268 }
267269 // If L = 0, all terms that depend on U, V, or Lambda will be zero
268270 if (m_L > 0 )
269271 {
270272 // 0.5 * ||U3L||^2 + U3L' * S3G - U3L' * MuR - tr(Lambda * V')
271273 const Scalar U3L_S3G = (m_H > 0 ) ? (U3L .dot (S3G )) : Scalar (0 );
272- const Scalar U3L_MuR = (m_rho > 0 ) ? (U3L .dot (MuR)) : Scalar (0 );
274+ const Scalar U3L_MuR = (m_W > 0 ) ? (U3L .dot (MuR)) : Scalar (0 );
273275 obj += Scalar (0.5 ) * U3L .squaredNorm () + U3L_S3G - U3L_MuR -
274276 m_Lambda.cwiseProduct (m_V).sum ();
275277 }
276278 // If H = 0, all terms that depend on S, T, or Gamma will be zero
277279 if (m_H > 0 )
278280 {
279281 // 0.5 * ||S3G||^2 - S3G' * MuR + 0.5 * ||Gamma||^2 - tr(Gamma * T')
280- const Scalar S3G_MuR = (m_rho > 0 ) ? (S3G .dot (MuR)) : Scalar (0 );
282+ const Scalar S3G_MuR = (m_W > 0 ) ? (S3G .dot (MuR)) : Scalar (0 );
281283 obj += Scalar (0.5 ) * S3G .squaredNorm () - S3G_MuR + Scalar (0.5 ) * m_Gamma.squaredNorm () -
282284 m_Gamma.cwiseProduct (m_T).sum ();
283285 }
284- // If rho = 0, all terms that depend on rho, or Mu will be zero
285- if (m_rho > 0 )
286- obj += Scalar (2.0 ) * m_mu.squaredNorm () - Scalar (2.0 ) * m_rho * m_mu.sum () +
287- Scalar (0.5 ) * m_d * m_rho * m_rho;
286+ // If W = 0, all terms that depend on rho or Mu will be zero
287+ if (m_W > 0 )
288+ // 2.0 * ||Mu||^2 - 2.0 * rho' * Mu + 0.5 * ||rho||^2
289+ obj += Scalar (2.0 ) * m_mu.squaredNorm () - Scalar (2.0 ) * m_rho.dot (m_mu) +
290+ Scalar (0.5 ) * m_rho.squaredNorm ();
288291 return obj;
289292 }
290293
@@ -368,7 +371,7 @@ class ReHLineSolver
368371 // Update mu and beta
369372 inline void update_mu_beta ()
370373 {
371- if (m_rho <= 0 )
374+ if (m_W <= 0 )
372375 return ;
373376
374377 // Save original Mu
@@ -598,7 +601,7 @@ class ReHLineSolver
598601 // Overloaded version based on free variable set
599602 inline void update_mu_beta (std::vector<Index>& fv_set, Scalar& min_pg, Scalar& max_pg)
600603 {
601- if (m_rho <= 0 )
604+ if (m_W <= 0 )
602605 return ;
603606
604607 // Permutation
@@ -618,12 +621,13 @@ class ReHLineSolver
618621 for (auto j: fv_set)
619622 {
620623 const Scalar mu_j = m_mu[j];
624+ const Scalar rho_j = m_rho[j];
621625
622626 // Compute g_j
623627 const Scalar g_j = m_beta[j];
624628 // PG and shrink
625629 Scalar pg;
626- const bool shrink = pg_mu (mu_j, g_j, m_rho , lb, ub, pg);
630+ const bool shrink = pg_mu (mu_j, g_j, rho_j , lb, ub, pg);
627631 if (shrink)
628632 continue ;
629633
@@ -632,7 +636,7 @@ class ReHLineSolver
632636 min_pg = std::min (min_pg, pg);
633637 // Compute new mu_j
634638 const Scalar candid = mu_j - g_j * Scalar (0.5 );
635- const Scalar newmu = std::max (Scalar (0 ), std::min (m_rho , candid));
639+ const Scalar newmu = std::max (Scalar (0 ), std::min (rho_j , candid));
636640 // Update mu and beta
637641 m_mu[j] = newmu;
638642 m_beta[j] += Scalar (2.0 ) * (newmu - mu_j);
@@ -647,8 +651,9 @@ class ReHLineSolver
647651 ReHLineSolver (ConstRefMat X, ConstRefMat U, ConstRefMat V,
648652 ConstRefMat S, ConstRefMat T, ConstRefMat Tau,
649653 ConstRefMat A, ConstRefVec b,
650- Scalar rho) :
651- m_n (X.rows()), m_d(X.cols()), m_L(U.rows()), m_H(S.rows()), m_K(A.rows()),
654+ ConstRefVec rho) :
655+ m_n (X.rows()), m_d(X.cols()), m_L(U.rows()), m_H(S.rows()), m_K(A.rows()),
656+ m_W (rho.rows()), // check if l1 penalty is implemented
652657 m_X (X), m_U(U), m_V(V), m_S(S), m_T(T), m_Tau(Tau), m_A(A), m_b(b),
653658 m_rho (rho),
654659 m_gk_denom (m_K), m_gli_denom(m_L, m_n), m_ghi_denom(m_H, m_n),
@@ -691,10 +696,10 @@ class ReHLineSolver
691696 // Gamma.fill(std::min(1.0, 0.5 * tau));
692697 }
693698
694- // Each element of Mu satisfies 0 <= mu_j <= rho ,
699+ // Each element of Mu satisfies 0 <= mu_j <= rho_j ,
695700 // and we use min(0.5 * rho, 1) to initialize (rho can be Inf)
696- if (m_rho > 0 )
697- m_mu.setConstant ( std::min ( Scalar (0.5 ) * m_rho, Scalar (1 )) );
701+ if (m_W > 0 )
702+ m_mu.noalias () = (m_rho * Scalar (0.5 )). cwiseMin ( Scalar (1 ));
698703
699704 // Set primal variable based on duals
700705 set_primal ();
@@ -746,15 +751,15 @@ class ReHLineSolver
746751 }
747752
748753
749- if (m_rho > 0 )
754+ if (m_W > 0 )
750755 {
751756 // Check shape of warmstart parameters
752757 if (mu_ws.size () != m_d){
753758 throw std::invalid_argument (" mu_ws must have size d" );
754759 }
755760 // Check values of warmstart parameters
756- if ((mu_ws.array () < Scalar (0 )).any () || (mu_ws.array () > m_rho).any ()){
757- throw std::invalid_argument (" mu_ws must be in [0, rho ]" );
761+ if ((mu_ws.array () < Scalar (0 )).any () || (mu_ws.array () > m_rho. array () ).any ()){
762+ throw std::invalid_argument (" mu_ws_j must be in [0, rho_j ]" );
758763 }
759764 m_mu = mu_ws;
760765 }
@@ -928,10 +933,10 @@ template <typename DerivedMat, typename DerivedVec, typename Index = int>
928933void rehline_solver (
929934 ReHLineResult<typename DerivedMat::PlainObject, Index>& result,
930935 const Eigen::MatrixBase<DerivedMat>& X, const Eigen::MatrixBase<DerivedMat>& A,
931- const Eigen::MatrixBase<DerivedVec>& b,
936+ const Eigen::MatrixBase<DerivedVec>& b, const Eigen::MatrixBase<DerivedVec>& rho,
932937 const Eigen::MatrixBase<DerivedMat>& U, const Eigen::MatrixBase<DerivedMat>& V,
933938 const Eigen::MatrixBase<DerivedMat>& S, const Eigen::MatrixBase<DerivedMat>& T, const Eigen::MatrixBase<DerivedMat>& Tau,
934- Index max_iter, typename DerivedMat::Scalar tol, typename DerivedMat::Scalar rho = 0 ,
939+ Index max_iter, typename DerivedMat::Scalar tol,
935940 Index shrink = 1 , Index verbose = 0 , Index trace_freq = 100 ,
936941 std::ostream& cout = std::cout
937942)
0 commit comments