@@ -592,9 +592,48 @@ auto Optimize::run_manual_cv(const std::string &job_prefix, const int maxorder,
592592 A_merged << A, A_validation;
593593 b_merged << b, b_validation;
594594
595- Eigen::VectorXd x_ols = A_merged.colPivHouseholderQr ().solve (b_merged);
595+ // Use QR decomposition with pivoting to check if system is well-determined
596+ Eigen::ColPivHouseholderQR<Eigen::MatrixXd> qr_solver (A_merged);
597+
598+ // Check if the system is underdetermined or rank-deficient
599+ const auto rank = qr_solver.rank ();
600+
601+ if (rank < N_new) {
602+ std::string error_msg =
603+ " Adaptive lasso failed: The least squares problem is rank-deficient.\n "
604+ " Matrix rank = " + std::to_string (rank) +
605+ " , Number of parameters = " + std::to_string (N_new) + " \n "
606+ " This typically occurs when there are too few training data\n "
607+ " or when some parameters cannot be uniquely determined.\n "
608+ " Please try one of the following:\n "
609+ " - Increase the amount of training data (DFSET)\n "
610+ " - Use LMODEL = 1 (least-squares) or 2 (elastic-net) instead\n "
611+ " - Reduce the interaction cutoff distance\n " ;
612+ ALM_NS::exit (" optimize_main" , error_msg.c_str ());
613+ }
614+
615+ Eigen::VectorXd x_ols = qr_solver.solve (b_merged);
596616 Eigen::VectorXd weight_adalasso = x_ols.cwiseAbs ();
597617
618+ // Check if any weights are too small (could cause numerical issues)
619+ const double min_weight_threshold = 1.0e-10 ;
620+ int n_zero_weights = 0 ;
621+ for (int i = 0 ; i < weight_adalasso.size (); ++i) {
622+ if (weight_adalasso[i] < min_weight_threshold) {
623+ n_zero_weights++;
624+ }
625+ }
626+
627+ if (n_zero_weights > 0 ) {
628+ if (verbosity > 0 ) {
629+ std::cout << " WARNING: Adaptive lasso detected " << n_zero_weights
630+ << " near-zero weights (< " << min_weight_threshold << " ).\n " ;
631+ std::cout << " This may indicate an underdetermined or ill-conditioned problem.\n " ;
632+ std::cout << " The optimization will continue but results may be unreliable.\n " ;
633+ std::cout << " Consider using LMODEL = 2 (elastic-net) instead.\n\n " ;
634+ }
635+ }
636+
598637 A = A * weight_adalasso.asDiagonal ();
599638 A_validation = A_validation * weight_adalasso.asDiagonal ();
600639 }
@@ -716,8 +755,44 @@ auto Optimize::run_auto_cv(const std::string &job_prefix, const int maxorder, co
716755 matrix_train->amat_dense .size () / N_new,
717756 N_new);
718757 Eigen::VectorXd b_full = Eigen::Map<Eigen::VectorXd>(matrix_train->bvec .data (), matrix_train->bvec .size ());
719- Eigen::VectorXd x_ols = A_full.colPivHouseholderQr ().solve (b_full);
758+
759+ // Use QR decomposition with pivoting to check if system is well-determined
760+ Eigen::ColPivHouseholderQR<Eigen::MatrixXd> qr_solver (A_full);
761+
762+ // Check if the system is underdetermined or rank-deficient
763+ const auto rank = qr_solver.rank ();
764+
765+ if (rank < N_new) {
766+ std::string error_msg =
767+ " Adaptive lasso failed in CV: The least squares problem is rank-deficient.\n "
768+ " Matrix rank = " + std::to_string (rank) +
769+ " , Number of parameters = " + std::to_string (N_new) + " \n "
770+ " This typically occurs when there are too few training data\n "
771+ " or when some parameters cannot be uniquely determined.\n "
772+ " Please try one of the following:\n "
773+ " - Increase the amount of training data (DFSET)\n "
774+ " - Use LMODEL = 1 (least-squares) or 2 (elastic-net) instead\n "
775+ " - Reduce the interaction cutoff distance\n " ;
776+ ALM_NS::exit (" optimize_main" , error_msg.c_str ());
777+ }
778+
779+ Eigen::VectorXd x_ols = qr_solver.solve (b_full);
720780 weight_adalasso = x_ols.cwiseAbs ();
781+
782+ // Check if any weights are too small (could cause numerical issues)
783+ const double min_weight_threshold = 1.0e-10 ;
784+ int n_zero_weights = 0 ;
785+ for (int i = 0 ; i < weight_adalasso.size (); ++i) {
786+ if (weight_adalasso[i] < min_weight_threshold) {
787+ n_zero_weights++;
788+ }
789+ }
790+
791+ if (n_zero_weights > 0 && verbosity > 0 ) {
792+ std::cout << " WARNING: Adaptive lasso detected " << n_zero_weights
793+ << " near-zero weights (< " << min_weight_threshold << " ).\n " ;
794+ std::cout << " This may indicate an underdetermined or ill-conditioned problem.\n\n " ;
795+ }
721796 }
722797
723798 if (optcontrol.l1_alpha_max <= 0 ) {
@@ -1273,8 +1348,52 @@ auto Optimize::optimize_with_given_l1alpha(const int maxorder, const size_t M, c
12731348 b = Eigen::Map<Eigen::VectorXd>(matrix_train->bvec .data (), M);
12741349
12751350 if (optcontrol.linear_model == 3 ) {
1276- Eigen::VectorXd x_ols = A.colPivHouseholderQr ().solve (b);
1351+ // Use QR decomposition with pivoting to check if system is well-determined
1352+ Eigen::ColPivHouseholderQR<Eigen::MatrixXd> qr_solver (A);
1353+
1354+ // Check if the system is underdetermined or rank-deficient
1355+ const auto rank = qr_solver.rank ();
1356+
1357+ if (rank < N_new) {
1358+ std::string error_msg =
1359+ " Adaptive lasso failed: The least squares problem is rank-deficient.\n "
1360+ " Matrix rank = " + std::to_string (rank) +
1361+ " , Number of parameters = " + std::to_string (N_new) + " \n "
1362+ " Number of data points = " + std::to_string (M) + " \n "
1363+ " This typically occurs when there are too few training data\n "
1364+ " or when some parameters cannot be uniquely determined.\n "
1365+ " Please try one of the following:\n "
1366+ " - Increase the amount of training data (DFSET)\n "
1367+ " - Use LMODEL = 1 (least-squares) or 2 (elastic-net) instead\n "
1368+ " - Reduce the interaction cutoff distance\n " ;
1369+ ALM_NS::exit (" optimize_elasticnet" , error_msg.c_str ());
1370+ }
1371+
1372+ Eigen::VectorXd x_ols = qr_solver.solve (b);
12771373 weight_adalasso = x_ols.cwiseAbs ();
1374+
1375+ // Check if any weights are too small (could cause numerical issues)
1376+ const double min_weight_threshold = 1.0e-10 ;
1377+ int n_zero_weights = 0 ;
1378+ double max_weight = weight_adalasso.maxCoeff ();
1379+
1380+ for (int i = 0 ; i < weight_adalasso.size (); ++i) {
1381+ if (weight_adalasso[i] < min_weight_threshold) {
1382+ n_zero_weights++;
1383+ }
1384+ }
1385+
1386+ if (n_zero_weights > 0 ) {
1387+ if (verbosity > 0 ) {
1388+ std::cout << " WARNING: Adaptive lasso detected " << n_zero_weights
1389+ << " near-zero weights (< " << min_weight_threshold << " ).\n " ;
1390+ std::cout << " Maximum weight = " << max_weight << " \n " ;
1391+ std::cout << " This may indicate an underdetermined or ill-conditioned problem.\n " ;
1392+ std::cout << " The optimization will continue but results may be unreliable.\n " ;
1393+ std::cout << " Consider using LMODEL = 2 (elastic-net) instead.\n\n " ;
1394+ }
1395+ }
1396+
12781397 A = A * weight_adalasso.asDiagonal ();
12791398 }
12801399
0 commit comments