diff --git a/src/classification/SVMWrapper.cpp b/src/classification/SVMWrapper.cpp index 369fcf99338958c79cb4b97bee97bdc9f0cea7a5..097caf2a7d949abef144787c6aa8a694349de8d6 100644 --- a/src/classification/SVMWrapper.cpp +++ b/src/classification/SVMWrapper.cpp @@ -178,7 +178,7 @@ void SVMWrapper::copy_data(std::vector<double*> val_ptrs) } } -void SVMWrapper::train() +void SVMWrapper::train(bool remap_coefs) { _model = svm_train(&_prob, &_param); std::copy_n(_model->rho, _intercept.size(), _intercept.data()); @@ -201,8 +201,11 @@ void SVMWrapper::train() for(int sv = start_c2; sv < start_c2 + n_sv_c2; ++sv) _coefs[class_combo][dd] -= _model->sv_coef[c1][sv] * _model->SV[sv][dd].value; - _coefs[class_combo][dd] *= _w_remap[dd]; - _intercept[class_combo] -= _coefs[class_combo][dd] * _b_remap[dd]; + if(remap_coefs) + { + _coefs[class_combo][dd] *= _w_remap[dd]; + _intercept[class_combo] -= _coefs[class_combo][dd] * _b_remap[dd]; + } } ++class_combo; } @@ -214,16 +217,16 @@ void SVMWrapper::train() _n_misclassified += _y[ss] != _y_est[ss]; } -void SVMWrapper::train(std::vector<int> inds, int task) +void SVMWrapper::train(std::vector<int> inds, int task, bool remap_coefs) { copy_data(inds, task); - train(); + train(remap_coefs); } -void SVMWrapper::train(std::vector<double*> val_ptrs) +void SVMWrapper::train(std::vector<double*> val_ptrs, bool remap_coefs) { copy_data(val_ptrs); - train(); + train(remap_coefs); } std::vector<double> SVMWrapper::predict(int n_test_samp, std::vector<double*> val_ptrs) diff --git a/src/classification/SVMWrapper.hpp b/src/classification/SVMWrapper.hpp index 3c2e34770ecc7dad072dd4cda5ecbcf24fb6099f..96ec8bd1f108d503733f48d87088f27ef6e2f288 100644 --- a/src/classification/SVMWrapper.hpp +++ b/src/classification/SVMWrapper.hpp @@ -132,23 +132,27 @@ public: /** * @brief Train the SVM model + * + * @param remap_coefs If true remap the final coefficients back to the unscaled feature space */ - void train(); + void train(bool remap_coefs=true); /** * @brief Copy the data from a set of feature indexes (sorted_dmatrix) into the x_space and train the SVM model * * @param inds list of indexes to pull data for * @param task the task number for the calculation + * @param remap_coefs If true remap the final coefficients back to the unscaled feature space */ - void train(std::vector<int> inds, int task); + void train(std::vector<int> inds, int task, bool remap_coefs=true); /** * @brief Copy tthe data from a set data pointers and train the SVM model * * @param val_ptrs The pointers to the feature's data + * @param remap_coefs If true remap the final coefficients back to the unscaled feature space */ - void train(std::vector<double*> val_ptrs); + void train(std::vector<double*> val_ptrs, bool remap_coefs=true); /** * @brief Predict the class of a set of data from the SVM model diff --git a/src/descriptor_identifier/SISSO_DI/SISSOClassifier.cpp b/src/descriptor_identifier/SISSO_DI/SISSOClassifier.cpp index 1b916648831a7efd5d89ef540da474f2e191236a..df62b7d88628160efe7031b0b92ee18747fcc61d 100644 --- a/src/descriptor_identifier/SISSO_DI/SISSOClassifier.cpp +++ b/src/descriptor_identifier/SISSO_DI/SISSOClassifier.cpp @@ -125,6 +125,29 @@ void SISSOClassifier::setup_lp() prop_sorted_d_mat::initialize_sroted_d_matrix_arr(0, _n_task, _n_class, n_samp_per_class); } +std::array<double, 2> SISSOClassifier::svm_error(std::vector<int>& feat_inds) +{ + double error = 0.0; + double dist_error = 0.0; + for(int tt = 0; tt < _n_task; ++tt) + { + _svm[tt].train(feat_inds, tt, false); + error += _svm[tt].n_misclassified(); + for(auto& coefs : _svm[tt].coefs()) + dist_error += 1.0 / util_funcs::norm(coefs.data(), feat_inds.size()); + } + dist_error /= static_cast<double>(_n_task * _svm[0].n_class()); + return {error, dist_error}; +} + +int SISSOClassifier::get_max_error_ind(int n_models, int* n_convex_overlap, double* svm_score, double* svm_margin, double* scores) +{ + std::transform(n_convex_overlap, n_convex_overlap, svm_score, scores, [this](int n_overlap, double score){return static_cast<double>(n_overlap * _n_samp) + score;}); + double max_dist = *std::max_element(svm_margin, svm_margin) + 0.01; + std::transform(svm_margin, svm_margin, scores, scores, [&max_dist](double margin, double score){return score + (1.0 - margin / max_dist);}); + return std::max_element(scores, scores) - scores; +} + std::vector<std::vector<int>> SISSOClassifier::find_min_svm(std::vector<std::vector<int>>& test_inds, int n_keep) { int n_dim = test_inds[0].size(); @@ -183,22 +206,22 @@ void SISSOClassifier::transfer_d_mat_to_sorted() } } -void SISSOClassifier::set_lp_data(int task, int cls) +void SISSOClassifier::set_lp_data(int task, int cls, std::vector<int>& feat_inds) { - int n_dim = _cur_inds.size(); + int n_dim = feat_inds.size(); for(int ii = 0; ii < n_dim; ++ii) - dcopy_(_lp_n_col, prop_sorted_d_mat::access_sorted_d_matrix(_cur_inds[ii], task, cls), 1, &_lp_elements[ii], _lp_n_row); + dcopy_(_lp_n_col, prop_sorted_d_mat::access_sorted_d_matrix(feat_inds[ii], task, cls), 1, &_lp_elements[ii], _lp_n_row); int n_copied = 0; for(auto& cls_task_ind : _class_task_check[task * _n_class + cls]) { - for(int ii = 0; ii < _cur_inds.size(); ++ii) + for(int ii = 0; ii < feat_inds.size(); ++ii) { - dcopy_(prop_sorted_d_mat::N_SAMPLES_PER_CLASS[cls_task_ind], prop_sorted_d_mat::access_sorted_d_matrix(_cur_inds[ii], task, cls_task_ind % _n_class), 1, &_lp_row_lower[n_copied + ii], _lp_n_row); - dcopy_(prop_sorted_d_mat::N_SAMPLES_PER_CLASS[cls_task_ind], prop_sorted_d_mat::access_sorted_d_matrix(_cur_inds[ii], task, cls_task_ind % _n_class), 1, &_lp_row_upper[n_copied + ii], _lp_n_row); + dcopy_(prop_sorted_d_mat::N_SAMPLES_PER_CLASS[cls_task_ind], prop_sorted_d_mat::access_sorted_d_matrix(feat_inds[ii], task, cls_task_ind % _n_class), 1, &_lp_row_lower[n_copied + ii], _lp_n_row); + dcopy_(prop_sorted_d_mat::N_SAMPLES_PER_CLASS[cls_task_ind], prop_sorted_d_mat::access_sorted_d_matrix(feat_inds[ii], task, cls_task_ind % _n_class), 1, &_lp_row_upper[n_copied + ii], _lp_n_row); } - n_copied += prop_sorted_d_mat::N_SAMPLES_PER_CLASS[cls_task_ind] * _cur_inds.size(); + n_copied += prop_sorted_d_mat::N_SAMPLES_PER_CLASS[cls_task_ind] * feat_inds.size(); } - _sz_cls_task_check = n_copied / _cur_inds.size(); + _sz_cls_task_check = n_copied / feat_inds.size(); _lp_simplex.loadProblem( _lp_n_col, @@ -229,7 +252,7 @@ int SISSOClassifier::pt_in_convex_hull_lp(int cls_task_ind) return n_overlap; } -int SISSOClassifier::get_n_overlap_lp() +int SISSOClassifier::get_n_overlap_lp(std::vector<int>& feat_inds) { int n_overlap = 0; for(int tt = 0; tt < _n_task; ++tt) @@ -237,7 +260,7 @@ int SISSOClassifier::get_n_overlap_lp() for(int cc = 0; cc < _n_class; ++cc) { _lp_n_col = prop_sorted_d_mat::get_class_size(tt, cc); - set_lp_data(tt, cc); + set_lp_data(tt, cc, feat_inds); for(auto& cls_task_ind : _class_task_check[tt * _n_class + cc]) n_overlap += pt_in_convex_hull_lp(cls_task_ind); } @@ -263,10 +286,11 @@ void SISSOClassifier::l0_norm(std::vector<double>& prop, int n_dim) std::vector<double> coefs(n_dim + 1, 0.0); _cur_inds = std::vector<int>(n_dim, 0); - std::vector<std::vector<std::vector<int>>> min_inds(n_get_models); - + std::vector<int> min_inds(n_get_models * n_dim, -1); std::vector<int> min_n_convex_overlap(n_get_models, ((n_dim > 1) ? models().back().back().n_convex_overlap_train() : _n_samp)); + std::vector<double> min_svm_score(n_get_models, ((n_dim > 1) ? models().back().back().n_convex_overlap_train() : _n_samp)); + std::vector<double> min_svm_margin(n_get_models, -1.0); for(int rr = 0; rr < n_dim; ++rr) _cur_inds[rr] = _feat_space->phi_selected().size() - 1 - rr; @@ -274,69 +298,80 @@ void SISSOClassifier::l0_norm(std::vector<double>& prop, int n_dim) util_funcs::iterate(_cur_inds, _cur_inds.size(), _mpi_comm->rank()); int max_error_ind = 0; - std::vector<double> gamma(_prop.size(), 0.0); - std::vector<double> gamma_feat(_prop.size(), 0.0); + #pragma omp parallel firstprivate(_svm, max_error_ind) + { + std::vector<int> min_inds_private(min_inds); + std::vector<int> min_n_convex_overlap_private(min_n_convex_overlap); + std::vector<double> min_svm_score_private(min_svm_score); + std::vector<double> min_svm_margin_private(min_svm_margin); + std::array<double, 2> temp_svm_error; - do { - int n_convex_overlap = get_n_overlap_lp(); - int el_num = std::find(min_n_convex_overlap.begin(), min_n_convex_overlap.end(), n_convex_overlap) - min_n_convex_overlap.begin(); + std::vector<double> scores(n_get_models); - if(el_num < n_get_models) - { - min_inds[el_num].push_back(_cur_inds); - } - else if(n_convex_overlap < min_n_convex_overlap[max_error_ind]) + #pragma omp single { - min_n_convex_overlap[max_error_ind] = n_convex_overlap; - min_inds[max_error_ind] = {_cur_inds}; - max_error_ind = std::max_element(min_n_convex_overlap.begin(), min_n_convex_overlap.end()) - min_n_convex_overlap.begin(); + do { + #pragma omp task firstprivate(_cur_inds, _svm) + { + int n_convex_overlap = get_n_overlap_lp(_cur_inds); + if(n_convex_overlap <= min_n_convex_overlap_private[max_error_ind]) + { + temp_svm_error = svm_error(_cur_inds); + + if((n_convex_overlap < min_n_convex_overlap_private[max_error_ind]) || (temp_svm_error[0] < min_svm_score_private[max_error_ind]) || ((temp_svm_error[0] == min_svm_score_private[max_error_ind]) && (temp_svm_error[1] > min_svm_margin_private[max_error_ind]))) + { + min_n_convex_overlap_private[max_error_ind] = n_convex_overlap; + min_svm_score_private[max_error_ind] = temp_svm_error[0]; + min_svm_margin_private[max_error_ind] = temp_svm_error[1]; + std::copy_n(_cur_inds.begin(), n_dim, min_inds_private.begin() + max_error_ind * n_dim); + + max_error_ind = get_max_error_ind(n_get_models, min_n_convex_overlap_private.data(), min_svm_score_private.data(), min_svm_margin_private.data(), scores.data()); + } + } + } + } while(util_funcs::iterate(_cur_inds, _cur_inds.size(), _mpi_comm->size())); } - } while(util_funcs::iterate(_cur_inds, _cur_inds.size(), _mpi_comm->size())); - - std::vector<int> inds_min(n_get_models * n_dim, -1); - std::vector<int> sorted_overlap_inds = util_funcs::argsort(min_n_convex_overlap); - std::vector<int> min_n_convex_overlap_copy(min_n_convex_overlap); - - int ii = 0; - int nn = 0; - while((ii < n_get_models) && (nn < min_n_convex_overlap.size())) - { - if(((ii + min_inds[sorted_overlap_inds[nn]].size()) * n_dim <= inds_min.size())) + #pragma omp barrier + std::cout << min_n_convex_overlap_private[0] << std::endl; + std::cout << min_svm_score_private[0] << std::endl; + std::cout << min_svm_margin_private[0] << std::endl; + std::cout << "check inds" << std::endl; + #pragma omp critical { - for(auto& mi : min_inds[sorted_overlap_inds[nn]]) + max_error_ind = get_max_error_ind(n_get_models, min_n_convex_overlap.data(), min_svm_score.data(), min_svm_margin.data(), scores.data()); + for(int ee = 0; ee < min_n_convex_overlap.size(); ++ee) { - std::copy_n(mi.begin(), mi.size(), &inds_min[ii * n_dim]); - min_n_convex_overlap[ii] = min_n_convex_overlap_copy[sorted_overlap_inds[nn]]; - ++ii; + std::cout << min_n_convex_overlap_private[ee] << '\t' << min_n_convex_overlap[max_error_ind] << std::endl; + if((min_n_convex_overlap_private[ee] < min_n_convex_overlap[max_error_ind]) || (min_svm_score_private[ee] < min_svm_score[max_error_ind]) || ((min_svm_score_private[ee] == min_svm_score[max_error_ind]) && (min_svm_margin_private[ee] > min_svm_margin[max_error_ind]))) + { + min_n_convex_overlap[max_error_ind] = min_n_convex_overlap_private[ee]; + min_svm_score[max_error_ind] = min_svm_score_private[ee]; + min_svm_margin[max_error_ind] = min_svm_margin_private[ee]; + std::copy_n(min_inds_private.begin() + ee * n_dim, n_dim, min_inds.begin() + max_error_ind * n_dim); + + max_error_ind = get_max_error_ind(n_get_models, min_n_convex_overlap.data(), min_svm_score.data(), min_svm_margin.data(), scores.data()); + } } } - else - { - std::vector<std::vector<int>> test_inds = find_min_svm(min_inds[sorted_overlap_inds[nn]], n_get_models - ii); - int kk = 0; - while((ii < inds_min.size()) && (kk < test_inds.size())) - { - std::copy_n(test_inds[kk].begin(), test_inds[kk].size(), &inds_min[ii * n_dim]); - min_n_convex_overlap[ii] = min_n_convex_overlap_copy[sorted_overlap_inds[nn]]; - ++ii; - ++kk; - } - } - ++nn; } - + std::cout << "mpi" << std::endl; std::vector<int> all_min_n_convex_overlap(_mpi_comm->size() * n_get_models); - std::vector<int> all_inds_min(_mpi_comm->size() * n_get_models * n_dim); + std::vector<double> all_min_svm_score(_mpi_comm->size() * n_get_models); + std::vector<double> all_min_svm_margin(_mpi_comm->size() * n_get_models); + std::vector<int> all_min_inds(_mpi_comm->size() * n_get_models * n_dim); mpi::all_gather(*_mpi_comm, min_n_convex_overlap.data(), n_get_models, all_min_n_convex_overlap); - mpi::all_gather(*_mpi_comm, inds_min.data(), n_get_models * n_dim, all_inds_min); + mpi::all_gather(*_mpi_comm, min_svm_score.data(), n_get_models, all_min_svm_score); + mpi::all_gather(*_mpi_comm, min_svm_margin.data(), n_get_models, all_min_svm_margin); + mpi::all_gather(*_mpi_comm, min_inds.data(), n_get_models * n_dim, all_min_inds); std::vector<int> inds = util_funcs::argsort(all_min_n_convex_overlap); - std::vector<int> all_inds_min_original(all_inds_min); + std::vector<int> all_min_inds_original(all_min_inds); - ii = 1; - nn = 0; + int ii = 1; + int nn = 0; + std::cout << "find" << std::endl; while(nn < n_get_models) { while((ii < all_min_n_convex_overlap.size()) && (all_min_n_convex_overlap[inds[ii]] == all_min_n_convex_overlap[inds[nn]])) @@ -349,26 +384,32 @@ void SISSOClassifier::l0_norm(std::vector<double>& prop, int n_dim) } std::vector<std::vector<int>> test_inds(ii - nn, std::vector<int>(n_dim, 0)); for(int cc = nn; cc < ii; ++cc) - std::copy_n(&all_inds_min_original[inds[cc] * n_dim], n_dim, test_inds[cc - nn].begin()); + std::copy_n(&all_min_inds_original[inds[cc] * n_dim], n_dim, test_inds[cc - nn].begin()); test_inds = find_min_svm(test_inds, std::min(ii - nn, n_get_models - nn)); for(int cc = 0; cc < test_inds.size(); ++cc) - std::copy_n(test_inds[cc].begin(), n_dim, &all_inds_min[(cc + nn) * n_dim]); + std::copy_n(test_inds[cc].begin(), n_dim, &all_min_inds[(cc + nn) * n_dim]); nn = ii; ++ii; } std::vector<model_node_ptr> min_nodes(n_dim); std::vector<ModelClassifier> models; + + std::cout << "models" << std::endl; + #pragma omp parallel for for(int rr = 0; rr < n_get_models; ++rr) { node_value_arrs::clear_temp_test_reg(); for(int ii = 0; ii < n_dim; ++ii) { - int index = all_inds_min[rr * n_dim + ii]; + int index = all_min_inds[rr * n_dim + ii]; + std::cout << index << std::endl; min_nodes[ii] = std::make_shared<ModelNode>(_feat_space->phi_selected()[index]->arr_ind(), _feat_space->phi_selected()[index]->rung(), _feat_space->phi_selected()[index]->expr(), _feat_space->phi_selected()[index]->postfix_expr(), _feat_space->phi_selected()[index]->value(), _feat_space->phi_selected()[index]->test_value(), _feat_space->phi_selected()[index]->unit()); } + + #pragma omp critical models.push_back(ModelClassifier(_prop_unit, _prop, _prop_test, min_nodes, _task_sizes_train, _task_sizes_test, _fix_intercept)); } diff --git a/src/descriptor_identifier/SISSO_DI/SISSOClassifier.hpp b/src/descriptor_identifier/SISSO_DI/SISSOClassifier.hpp index 9ce400a5e4e4dc9d6cdf4450edb99d91134d3d71..cccc8fa9ddd587e55d2cc9fb79d9e7f307dd0f48 100644 --- a/src/descriptor_identifier/SISSO_DI/SISSOClassifier.hpp +++ b/src/descriptor_identifier/SISSO_DI/SISSOClassifier.hpp @@ -119,8 +119,9 @@ public: * * @param task The task number to set up the data objects for * @param cls The class number to set up the data objects for + * @param feat_inds The indexes of the features to create the model for */ - void set_lp_data(int task, int cls); + void set_lp_data(int task, int cls, std::vector<int>& feat_inds); /** * @brief Check how many points in a given set are inside the convex hull @@ -134,9 +135,31 @@ public: /** * @brief Get the number of points in overlapping convex hull regions * @details Loop over all task/class combinations and finds the total number of points in overlapping + * + * @param feat_inds The indexes to develop the SVM model for * @return The total number of overlapping points in all convex hull regions. */ - int get_n_overlap_lp(); + int get_n_overlap_lp(std::vector<int>& feat_inds); + + /** + * @brief Find the SVM error and margin for a given set of indexes + * + * @param feat_inds The indexes to develop the SVM model for + * @return {The number of misclassified points, the SVM margin} + */ + std::array<double, 2> svm_error(std::vector<int>& feat_inds); + + /** + * @brief Gets the max error index for the classification problem + * @details [long description] + * + * @param n_models number of models to be stored + * @param n_convex_overlap number of points in the overlapping convex hull regions (in all models) + * @param svm_score the number of points misclassified by SVM (in all models) + * @param svm_margin The margin of the SVM model (in all models) + * @return [description] + */ + int get_max_error_ind(int n_models, int* n_convex_overlap, double* svm_score, double* svm_margin, double* scores); /** * @brief Preform the l0 normalization for a property or the residual diff --git a/src/descriptor_identifier/SISSO_DI/SISSORegressor.cpp b/src/descriptor_identifier/SISSO_DI/SISSORegressor.cpp index 92d1c9500f129a1872898bcd2b6f21406e909011..d0eb107f495fe31b25b5fb394455ed5b4997aa02 100644 --- a/src/descriptor_identifier/SISSO_DI/SISSORegressor.cpp +++ b/src/descriptor_identifier/SISSO_DI/SISSORegressor.cpp @@ -27,27 +27,28 @@ SISSORegressor::SISSORegressor( _work = std::vector<double>(_lwork, 0.0); } -void SISSORegressor::set_a(std::vector<int>& inds, int start, int n_samp) +void SISSORegressor::set_a(std::vector<int>& inds, int start, int n_samp, double* a) { for(int ii = 0; ii < inds.size(); ++ii) - std::copy_n(node_value_arrs::get_d_matrix_ptr(inds[ii]) + start, n_samp, _a.data() + ii * n_samp); + std::copy_n(node_value_arrs::get_d_matrix_ptr(inds[ii]) + start, n_samp, a + ii * n_samp); + if(!_fix_intercept) - std::fill_n(_a.data() + inds.size() * n_samp, n_samp, 1.0); + std::fill_n(a + inds.size() * n_samp, n_samp, 1.0); } -void SISSORegressor::least_squares(std::vector<int>& inds, double* coeffs, int start, int n_samp) +void SISSORegressor::least_squares(std::vector<int>& inds, double* coeffs, int start, int n_samp, double* a, double*b, double* work) { int info; int n_dim = inds.size() + (1 - _fix_intercept); - set_a(inds, start, n_samp); - std::copy_n(_prop.data() + start, n_samp, _b.data()); + set_a(inds, start, n_samp, a); + std::copy_n(_prop.data() + start, n_samp, b); - dgels_('N', n_samp, n_dim, 1, _a.data(), n_samp, _b.data(), n_samp, _work.data(), _lwork, &info); + dgels_('N', n_samp, n_dim, 1, a, n_samp, b, n_samp, work, _lwork, &info); if(info == 0) { - std::copy_n(_b.data(), n_dim, coeffs); + std::copy_n(b, n_dim, coeffs); } else { @@ -71,13 +72,13 @@ int SISSORegressor::get_opt_lwork(int n_dim) throw std::logic_error("Failed to get lwork."); } -void SISSORegressor::set_error(std::vector<int>& inds, double* coeffs, int start, int n_samp) +void SISSORegressor::set_error(std::vector<int>& inds, double* coefs, int start, int n_samp, double* error) { - std::fill_n(_error.data() + start, n_samp, -1 * (!_fix_intercept) * coeffs[inds.size()]); - daxpy_(n_samp, 1.0, _prop.data() + start, 1, _error.data() + start, 1); - + std::fill_n(error + start, n_samp, -1 * (!_fix_intercept) * coefs[inds.size()]); for(int ii = 0; ii < inds.size(); ++ii) - daxpy_(n_samp, -1.0 * coeffs[ii], node_value_arrs::get_d_matrix_ptr(inds[ii]) + start, 1, _error.data() + start, 1); + daxpy_(n_samp, -1.0 * coefs[ii], node_value_arrs::get_d_matrix_ptr(inds[ii]) + start, 1, error + start, 1); + daxpy_(n_samp, 1.0, _prop.data() + start, 1, error + start, 1); + } void SISSORegressor::l0_norm(std::vector<double>& prop, int n_dim) @@ -90,36 +91,67 @@ void SISSORegressor::l0_norm(std::vector<double>& prop, int n_dim) std::vector<double> min_errors(n_get_models, util_funcs::norm(_prop.data(), _n_samp)); + int n_interactions = 1; + int n_dim_fact = 1; for(int rr = 0; rr < n_dim; ++rr) + { inds[rr] = _feat_space->phi_selected().size() - 1 - rr; + n_interactions *= inds[rr]; + n_dim_fact *= (rr + 1); + } + n_interactions /= n_dim_fact; util_funcs::iterate(inds, inds.size(), _mpi_comm->rank()); - int max_error_ind = 0; if(inds.back() >= 0) { - do { - int start = 0; - double error = 0.0; - for(auto& sz : _task_sizes_train) + #pragma omp parallel shared(inds_min, min_errors, n_interactions, n_get_models, n_dim) firstprivate(inds, coefs, _error, _a, _b, _work) + { + int max_error_ind = 0; + std::vector<int> inds_min_private(inds_min); + std::vector<double> min_errors_private(min_errors); + + int ii_prev = 0; + #pragma omp for schedule(dynamic) + for(int ii = 0; ii < n_interactions; ii += _mpi_comm->size()) { - least_squares(inds, coefs.data(), start, sz); - set_error(inds, coefs.data(), start, sz); - error += ddot_(sz, _error.data() + start, 1, _error.data() + start, 1) / sz; - // error += std::pow(util_funcs::norm(_error.data() + start, sz), 2.0) / sz; - start += sz; + util_funcs::iterate(inds, inds.size(), _mpi_comm->size() * (ii - ii_prev)); + + int start = 0; + for(auto& sz : _task_sizes_train) + { + least_squares(inds, coefs.data(), start, sz, _a.data(), _b.data(), _work.data()); + set_error(inds, coefs.data(), start, sz, _error.data()); + start += sz; + } + double error = std::sqrt(ddot_(_n_samp, _error.data(), 1, _error.data(), 1) / _n_samp); + #pragma omp critical + { + if(error < min_errors_private[max_error_ind]) + { + min_errors_private[max_error_ind] = error; + std::copy_n(inds.begin(), inds.size(), inds_min_private.begin() + max_error_ind * n_dim); + max_error_ind = std::max_element(min_errors_private.begin(), min_errors_private.end()) - min_errors_private.begin(); + } + } + ii_prev = ii; } - error = std::sqrt(error / _n_task); - if(error < min_errors[max_error_ind]) - { - min_errors[max_error_ind] = error; - std::copy_n(inds.begin(), inds.size(), inds_min.begin() + max_error_ind * n_dim); + #pragma omp critical + { max_error_ind = std::max_element(min_errors.begin(), min_errors.end()) - min_errors.begin(); + for(int ee = 0; ee < n_get_models; ++ee) + { + if(min_errors_private[ee] < min_errors[max_error_ind]) + { + min_errors[max_error_ind] = min_errors_private[ee]; + std::copy_n(inds_min_private.begin() + ee * n_dim, n_dim, inds_min.begin() + max_error_ind * n_dim); + max_error_ind = std::max_element(min_errors.begin(), min_errors.end()) - min_errors.begin(); + } + } } - } while(util_funcs::iterate(inds, inds.size(), _mpi_comm->size())); + } } - std::vector<double> all_min_error(_mpi_comm->size() * n_get_models); std::vector<int> all_inds_min(_mpi_comm->size() * n_get_models * n_dim); @@ -131,6 +163,7 @@ void SISSORegressor::l0_norm(std::vector<double>& prop, int n_dim) std::vector<model_node_ptr> min_nodes(n_dim); std::vector<ModelRegressor> models; + // #pragma omp parallel for firstprivate(min_nodes) for(int rr = 0; rr < n_get_models; ++rr) { node_value_arrs::clear_temp_test_reg(); @@ -139,6 +172,8 @@ void SISSORegressor::l0_norm(std::vector<double>& prop, int n_dim) int index = all_inds_min[inds[rr] * n_dim + ii]; min_nodes[ii] = std::make_shared<ModelNode>(_feat_space->phi_selected()[index]->arr_ind(), _feat_space->phi_selected()[index]->rung(), _feat_space->phi_selected()[index]->expr(), _feat_space->phi_selected()[index]->postfix_expr(), _feat_space->phi_selected()[index]->value(), _feat_space->phi_selected()[index]->test_value(), _feat_space->phi_selected()[index]->unit()); } + + // #pragma omp critical models.push_back(ModelRegressor(_prop_unit, _prop, _prop_test, min_nodes, _task_sizes_train, _task_sizes_test, _fix_intercept)); } diff --git a/src/descriptor_identifier/SISSO_DI/SISSORegressor.hpp b/src/descriptor_identifier/SISSO_DI/SISSORegressor.hpp index 939994dfb8e3cbb9163268b4986974086b57f506..83b5d191561af4fd79ce65f7a83a66d20e82a2b1 100644 --- a/src/descriptor_identifier/SISSO_DI/SISSORegressor.hpp +++ b/src/descriptor_identifier/SISSO_DI/SISSORegressor.hpp @@ -59,7 +59,7 @@ public: * @param start The index in the property and feature vectors start copying into _b and _a * @param n_samp number of samples to perform least squares optimization on */ - void set_error(std::vector<int>& inds, double* coeffs, int start, int n_samp); + void set_error(std::vector<int>& inds, double* coefs, int start, int n_samp, double* error); /** * @brief Get the optimal size of the working array @@ -77,7 +77,7 @@ public: * @param start The index in the property and feature vectors start copying into _b and _a * @param n_samp number of samples to perform least squares optimization on */ - void least_squares(std::vector<int>& inds, double* coeffs, int start, int n_samp); + void least_squares(std::vector<int>& inds, double* coefs, int start, int n_samp, double* a, double*b, double* work); /** * @brief Set the A matrix for the least squares problem @@ -86,7 +86,7 @@ public: * @param start The index in the property and feature vectors start copying into _b and _a * @param n_samp number of samples to perform least squares optimization on */ - void set_a(std::vector<int>& inds, int start, int n_samp); + void set_a(std::vector<int>& inds, int start, int n_samp, double* a); /** * @brief Preform the l0 normalization for a property or the residual diff --git a/src/feature_creation/feature_space/FeatureSpace.cpp b/src/feature_creation/feature_space/FeatureSpace.cpp index 7b33ce2c5bc8fc198690ffb0876ca6405f6a3678..f0ab6be199d924df17693cab1165313a70a6db39 100644 --- a/src/feature_creation/feature_space/FeatureSpace.cpp +++ b/src/feature_creation/feature_space/FeatureSpace.cpp @@ -471,51 +471,53 @@ void FeatureSpace::project_generated(double* prop, int size, std::vector<node_pt std::vector<node_ptr> generated_phi; generate_new_feats(feat, generated_phi, feat_ind, _l_bound, _u_bound); - std::vector<double> scores(generated_phi.size(), 0.0); - _project(prop, scores.data(), generated_phi, _task_sizes, size / _n_samp); - - std::vector<int> inds = util_funcs::argsort(scores); + #pragma omp critical + { + std::vector<double> scores(generated_phi.size(), 0.0); + _project(prop, scores.data(), generated_phi, _task_sizes, size / _n_samp); - int ii = 0; + std::vector<int> inds = util_funcs::argsort(scores); - while(_scores[inds[ii]] < -1.0) - ++ii; + int ii = 0; - while((ii < inds.size()) && (scores[inds[ii]] < worst_score)) - { - double cur_score = scores[inds[ii]]; + while(scores[inds[ii]] < -1.0) + ++ii; - if(valid_feature_against_selected(generated_phi[inds[ii]]->value_ptr(), node_value_arrs::N_SELECTED - _n_sis_select + scores_sel_private.size())) + while((ii < inds.size()) && (scores[inds[ii]] < worst_score)) { - if(scores_sel_private.size() == _n_sis_select) + double cur_score = scores[inds[ii]]; + + if(valid_feature_against_selected(generated_phi[inds[ii]]->value_ptr(), node_value_arrs::N_SELECTED - _n_sis_select + scores_sel_private.size())) { - phi_sel_private[worst_score_ind]->set_selected(false); - phi_sel_private[worst_score_ind]->set_d_mat_ind(-1); + if(scores_sel_private.size() == _n_sis_select) + { + phi_sel_private[worst_score_ind]->set_selected(false); + phi_sel_private[worst_score_ind]->set_d_mat_ind(-1); - phi_sel_private[worst_score_ind] = generated_phi[inds[ii]]; - scores_sel_private[worst_score_ind] = cur_score; + phi_sel_private[worst_score_ind] = generated_phi[inds[ii]]; + scores_sel_private[worst_score_ind] = cur_score; - phi_sel_private[worst_score_ind]->set_selected(true); - phi_sel_private[worst_score_ind]->set_d_mat_ind(node_value_arrs::N_SELECTED - _n_sis_select + worst_score_ind); - phi_sel_private[worst_score_ind]->set_value(); - } - else - { + phi_sel_private[worst_score_ind]->set_selected(true); + phi_sel_private[worst_score_ind]->set_d_mat_ind(node_value_arrs::N_SELECTED - _n_sis_select + worst_score_ind); + phi_sel_private[worst_score_ind]->set_value(); + } + else + { - phi_sel_private.push_back(generated_phi[inds[ii]]); - scores_sel_private.push_back(cur_score); + phi_sel_private.push_back(generated_phi[inds[ii]]); + scores_sel_private.push_back(cur_score); - phi_sel_private.back()->set_selected(true); - phi_sel_private.back()->set_d_mat_ind(node_value_arrs::N_SELECTED - _n_sis_select + scores_sel_private.size()); - phi_sel_private.back()->set_value(); + phi_sel_private.back()->set_selected(true); + phi_sel_private.back()->set_d_mat_ind(node_value_arrs::N_SELECTED - _n_sis_select + scores_sel_private.size()); + phi_sel_private.back()->set_value(); + } + worst_score_ind = std::max_element(scores_sel_private.begin(), scores_sel_private.end()) - scores_sel_private.begin(); + worst_score = scores_sel_private[worst_score_ind]; } - worst_score_ind = std::max_element(scores_sel_private.begin(), scores_sel_private.end()) - scores_sel_private.begin(); - worst_score = scores_sel_private[worst_score_ind]; + ++ii; } - ++ii; } } - #pragma omp critical { worst_score_ind = std::max_element(scores_sel.begin(), scores_sel.end()) - scores_sel.begin(); diff --git a/src/utils/project.cpp b/src/utils/project.cpp index 52e96203fe24fa6e352b8e165549ced849f9e1ca..1fd04c6071c0ef9697e3e23e7f24a36e74e83214 100644 --- a/src/utils/project.cpp +++ b/src/utils/project.cpp @@ -18,7 +18,7 @@ void project_funcs::project_r2(double* prop, double* scores, std::vector<node_pt { int n_samp = std::accumulate(sizes.begin(), sizes.end(), 0); - #pragma omp parallel + #pragma omp parallel firstprivate(prop) { int start = omp_get_thread_num() * (phi.size() / omp_get_num_threads()) + std::min(omp_get_thread_num(), static_cast<int>(phi.size()) % omp_get_num_threads()); int end = (omp_get_thread_num() + 1) * (phi.size() / omp_get_num_threads()) + std::min(omp_get_thread_num() + 1, static_cast<int>(phi.size()) % omp_get_num_threads()); @@ -31,6 +31,8 @@ void project_funcs::project_r2(double* prop, double* scores, std::vector<node_pt std::transform(phi.begin() + start, phi.begin() + end, scores + start, scores + start, [&prop, &sizes](node_ptr feat, double sc){return std::min(-1 * util_funcs::r2(prop, feat->value_ptr(), sizes.data(), sizes.size()), sc);}); } std::transform(scores + start, scores + end, scores + start, [](double score){return std::isnan(score) ? 0.0 : score;}); + + #pragma omp barrier } } @@ -40,7 +42,7 @@ void project_funcs::project_classify(double* prop, double* scores, std::vector<n convex_hull::initialize_projection(sizes, prop); - #pragma omp parallel + #pragma omp parallel firstprivate(prop) { int start = omp_get_thread_num() * (phi.size() / omp_get_num_threads()) + std::min(omp_get_thread_num(), static_cast<int>(phi.size()) % omp_get_num_threads()); int end = (omp_get_thread_num() + 1) * (phi.size() / omp_get_num_threads()) + std::min(omp_get_thread_num() + 1, static_cast<int>(phi.size()) % omp_get_num_threads()); @@ -54,5 +56,6 @@ void project_funcs::project_classify(double* prop, double* scores, std::vector<n std::transform(phi.begin() + start, phi.begin() + end, scores + start, scores + start, [](node_ptr feat, double score){return std::min(convex_hull::overlap_1d(feat->value_ptr()), score);}); } std::transform(scores + start, scores + end, scores + start, [](double score){return std::isnan(score) ? std::numeric_limits<double>::infinity() : score;}); + #pragma omp barrier } }