bool NnlsBlockpivot(const DenseMatrix<T>& LHS, const DenseMatrix<T>& RHS, DenseMatrix<T>& X, // input as xinit DenseMatrix<T>& Y) // gradX { // Solve (LHS)*X = RHS for X by block principal pivoting. Matrix LHS // is assumed to be symmetric positive definite. const int PBAR = 3; const unsigned int WIDTH = RHS.Width(); const unsigned int HEIGHT = RHS.Height(); const unsigned int MAX_ITER = HEIGHT*5; BitMatrix passive_set = (X > T(0)); std::vector<unsigned int> tmp_indices(WIDTH); for (unsigned int i=0; i<WIDTH; ++i) tmp_indices[i] = i; MakeZeros(X); if (!BppSolveNormalEqNoGroup(tmp_indices, passive_set, LHS, RHS, X)) return false; // Y = LHS * X - RHS Gemm(NORMAL, NORMAL, T(1), LHS, X, T(0), Y); Axpy( T(-1), RHS, Y); std::vector<int> P(WIDTH, PBAR), Ninf(WIDTH, HEIGHT+1); BitMatrix nonopt_set = (Y < T(0)) & ~passive_set; BitMatrix infeas_set = (X < T(0)) & passive_set; std::vector<int> col_sums(WIDTH); std::vector<int> not_good(WIDTH); nonopt_set.SumColumns(not_good); infeas_set.SumColumns(col_sums); not_good += col_sums; BitMatrix not_opt_cols = (not_good > 0); BitMatrix not_opt_mask; std::vector<unsigned int> non_opt_col_indices(WIDTH); not_opt_cols.Find(non_opt_col_indices); DenseMatrix<double> RHSsub(HEIGHT, WIDTH); DenseMatrix<double> Xsub(HEIGHT, WIDTH); DenseMatrix<double> Ysub(HEIGHT, WIDTH); unsigned int iter = 0; while (!non_opt_col_indices.empty()) { // exit if not getting anywhere if (iter >= MAX_ITER) return false; UpdatePassiveSet(passive_set, PBAR, HEIGHT, not_opt_cols, nonopt_set, infeas_set, not_good, P, Ninf); // equivalent of repmat(NotOptCols, HEIGHT, 1) not_opt_mask = MatrixFromColumnMask(not_opt_cols, HEIGHT); // Setup for the normal equation solver by extracting submatrices // from RHS and X. The normal equation solver will extract further // subproblems from RHSsub and Xsub and write all updated values // back into RHSsub and Xsub. RHS.SubmatrixFromCols(RHSsub, non_opt_col_indices); X.SubmatrixFromCols(Xsub, non_opt_col_indices); if (!BppSolveNormalEqNoGroup(non_opt_col_indices, passive_set, LHS, RHSsub, Xsub)) return false; ZeroizeSmallValues(Xsub, 1.0e-12); // compute Ysub = LHS * Xsub - RHSsub Ysub.Resize(RHSsub.Height(), RHSsub.Width()); Gemm(NORMAL, NORMAL, T(1), LHS, Xsub, T(0), Ysub); Axpy( T(-1), RHSsub, Ysub); // update Y and X using the new values in Ysub and Xsub OverwriteCols(Y, Ysub, non_opt_col_indices, non_opt_col_indices.size()); OverwriteCols(X, Xsub, non_opt_col_indices, non_opt_col_indices.size()); ZeroizeSmallValues(X, 1.0e-12); ZeroizeSmallValues(Y, 1.0e-12); // Check optimality - BppUpdateSets does the equivalent of the next two lines. // nonopt_set = not_opt_mask & (Y < T(0)) & ~passive_set; // infeas_set = not_opt_mask & (X < T(0)) & passive_set; BppUpdateSets(nonopt_set, infeas_set, not_opt_mask, X, Y, passive_set); nonopt_set.SumColumns(not_good); infeas_set.SumColumns(col_sums); not_good += col_sums; not_opt_cols = (not_good > 0); not_opt_cols.Find(non_opt_col_indices); ++iter; } return true; }