| 
4 | 4 | #include <future>  | 
5 | 5 | #include <random>  | 
6 | 6 | #include <vector>  | 
7 |  | -#include <omp.h>  | 
 | 7 | +#include <thread>  | 
8 | 8 | #include "../dependencies/eigen-3.4.0/Eigen/Dense"  | 
9 | 9 | #include "functions.h"  | 
10 | 10 | #include "term.h"  | 
@@ -79,6 +79,7 @@ class APLRRegressor  | 
79 | 79 |     bool max_terms_reached;  | 
80 | 80 |     bool round_robin_update_of_existing_terms;  | 
81 | 81 |     size_t term_to_update_in_this_boosting_step;  | 
 | 82 | +    size_t cores_to_use;  | 
82 | 83 | 
 
  | 
83 | 84 |     void validate_input_to_fit(const MatrixXd &X, const VectorXd &y, const VectorXd &sample_weight, const std::vector<std::string> &X_names,  | 
84 | 85 |                                const MatrixXi &cv_observations, const std::vector<size_t> &prioritized_predictors_indexes,  | 
@@ -215,6 +216,7 @@ class APLRRegressor  | 
215 | 216 |     size_t number_of_unique_term_affiliations;  | 
216 | 217 |     std::vector<std::string> unique_term_affiliations;  | 
217 | 218 |     std::map<std::string, size_t> unique_term_affiliation_map;  | 
 | 219 | +    std::vector<std::vector<size_t>> base_predictors_in_each_unique_term_affiliation;  | 
218 | 220 |     VectorXd feature_importance;  | 
219 | 221 |     VectorXd term_importance;  | 
220 | 222 |     double dispersion_parameter;  | 
@@ -276,6 +278,7 @@ class APLRRegressor  | 
276 | 278 |     std::vector<std::string> get_term_names();  | 
277 | 279 |     std::vector<std::string> get_term_affiliations();  | 
278 | 280 |     std::vector<std::string> get_unique_term_affiliations();  | 
 | 281 | +    std::vector<std::vector<size_t>> get_base_predictors_in_each_unique_term_affiliation();  | 
279 | 282 |     VectorXd get_term_coefficients();  | 
280 | 283 |     MatrixXd get_validation_error_steps();  | 
281 | 284 |     VectorXd get_feature_importance();  | 
@@ -351,7 +354,8 @@ APLRRegressor::APLRRegressor(const APLRRegressor &other)  | 
351 | 354 |       penalty_for_non_linearity{other.penalty_for_non_linearity}, penalty_for_interactions{other.penalty_for_interactions},  | 
352 | 355 |       max_terms{other.max_terms}, min_predictor_values_in_training{other.min_predictor_values_in_training},  | 
353 | 356 |       max_predictor_values_in_training{other.max_predictor_values_in_training}, unique_term_affiliations{other.unique_term_affiliations},  | 
354 |  | -      unique_term_affiliation_map{other.unique_term_affiliation_map}  | 
 | 357 | +      unique_term_affiliation_map{other.unique_term_affiliation_map},  | 
 | 358 | +      base_predictors_in_each_unique_term_affiliation{other.base_predictors_in_each_unique_term_affiliation}  | 
355 | 359 | {  | 
356 | 360 | }  | 
357 | 361 | 
 
  | 
@@ -410,12 +414,10 @@ void APLRRegressor::preprocess_prioritized_predictors_and_interaction_constraint  | 
410 | 414 | void APLRRegressor::initialize_multithreading()  | 
411 | 415 | {  | 
412 | 416 |     size_t available_cores{static_cast<size_t>(std::thread::hardware_concurrency())};  | 
413 |  | -    size_t cores_to_use;  | 
414 | 417 |     if (n_jobs == 0)  | 
415 | 418 |         cores_to_use = available_cores;  | 
416 | 419 |     else  | 
417 | 420 |         cores_to_use = std::min(n_jobs, available_cores);  | 
418 |  | -    omp_set_num_threads(cores_to_use);  | 
419 | 421 | }  | 
420 | 422 | 
 
  | 
421 | 423 | void APLRRegressor::preprocess_penalties()  | 
@@ -1299,14 +1301,47 @@ std::vector<size_t> APLRRegressor::find_terms_eligible_current_indexes_for_a_bas  | 
1299 | 1301 | void APLRRegressor::estimate_split_point_for_each_term(std::vector<Term> &terms, std::vector<size_t> &terms_indexes)  | 
1300 | 1302 | {  | 
1301 | 1303 |     bool multithreading{n_jobs != 1 && terms_indexes.size() > 1};  | 
1302 |  | -#pragma omp parallel for schedule(guided) if (multithreading)  | 
1303 |  | -    for (size_t i = 0; i < terms_indexes.size(); ++i)  | 
 | 1304 | + | 
 | 1305 | +    if (multithreading)  | 
1304 | 1306 |     {  | 
1305 |  | -        terms[terms_indexes[i]].estimate_split_point(X_train, neg_gradient_current, sample_weight_train, bins,  | 
1306 |  | -                                                     predictor_learning_rates[terms[terms_indexes[i]].base_term],  | 
1307 |  | -                                                     min_observations_in_split, linear_effects_only_in_this_boosting_step,  | 
1308 |  | -                                                     predictor_penalties_for_non_linearity[terms[terms_indexes[i]].base_term],  | 
1309 |  | -                                                     predictor_penalties_for_interactions[terms[terms_indexes[i]].base_term]);  | 
 | 1307 | +        size_t num_threads{std::min(cores_to_use, terms_indexes.size())};  | 
 | 1308 | +        std::vector<std::thread> threads;  | 
 | 1309 | +        size_t chunk_size{(terms_indexes.size() + num_threads - 1) / num_threads};  | 
 | 1310 | + | 
 | 1311 | +        for (size_t t = 0; t < num_threads; ++t)  | 
 | 1312 | +        {  | 
 | 1313 | +            threads.emplace_back([&, t]()  | 
 | 1314 | +                                 {  | 
 | 1315 | +                size_t start = t * chunk_size;  | 
 | 1316 | +                size_t end = std::min(start + chunk_size, terms_indexes.size());  | 
 | 1317 | +                for (size_t i = start; i < end; ++i)  | 
 | 1318 | +                {  | 
 | 1319 | +                    terms[terms_indexes[i]].estimate_split_point(X_train, neg_gradient_current, sample_weight_train, bins,  | 
 | 1320 | +                                                                 predictor_learning_rates[terms[terms_indexes[i]].base_term],  | 
 | 1321 | +                                                                 min_observations_in_split, linear_effects_only_in_this_boosting_step,  | 
 | 1322 | +                                                                 predictor_penalties_for_non_linearity[terms[terms_indexes[i]].base_term],  | 
 | 1323 | +                                                                 predictor_penalties_for_interactions[terms[terms_indexes[i]].base_term]);  | 
 | 1324 | +                } });  | 
 | 1325 | +        }  | 
 | 1326 | + | 
 | 1327 | +        for (auto &thread : threads)  | 
 | 1328 | +        {  | 
 | 1329 | +            if (thread.joinable())  | 
 | 1330 | +            {  | 
 | 1331 | +                thread.join();  | 
 | 1332 | +            }  | 
 | 1333 | +        }  | 
 | 1334 | +    }  | 
 | 1335 | +    else  | 
 | 1336 | +    {  | 
 | 1337 | +        for (size_t i = 0; i < terms_indexes.size(); ++i)  | 
 | 1338 | +        {  | 
 | 1339 | +            terms[terms_indexes[i]].estimate_split_point(X_train, neg_gradient_current, sample_weight_train, bins,  | 
 | 1340 | +                                                         predictor_learning_rates[terms[terms_indexes[i]].base_term],  | 
 | 1341 | +                                                         min_observations_in_split, linear_effects_only_in_this_boosting_step,  | 
 | 1342 | +                                                         predictor_penalties_for_non_linearity[terms[terms_indexes[i]].base_term],  | 
 | 1343 | +                                                         predictor_penalties_for_interactions[terms[terms_indexes[i]].base_term]);  | 
 | 1344 | +        }  | 
1310 | 1345 |     }  | 
1311 | 1346 | }  | 
1312 | 1347 | 
 
  | 
@@ -2282,6 +2317,17 @@ void APLRRegressor::correct_term_names_coefficients_and_affiliations()  | 
2282 | 2317 |     {  | 
2283 | 2318 |         unique_term_affiliation_map[unique_term_affiliations[i]] = i;  | 
2284 | 2319 |     }  | 
 | 2320 | +    base_predictors_in_each_unique_term_affiliation.resize(unique_term_affiliation_map.size());  | 
 | 2321 | +    std::vector<std::set<size_t>> base_predictors_in_each_unique_term_affiliation_set(unique_term_affiliation_map.size());  | 
 | 2322 | +    for (auto &term : terms)  | 
 | 2323 | +    {  | 
 | 2324 | +        std::vector<size_t> unique_base_terms_for_this_term{term.get_unique_base_terms_used_in_this_term()};  | 
 | 2325 | +        base_predictors_in_each_unique_term_affiliation_set[unique_term_affiliation_map[term.predictor_affiliation]].insert(unique_base_terms_for_this_term.begin(), unique_base_terms_for_this_term.end());  | 
 | 2326 | +    }  | 
 | 2327 | +    for (size_t i = 0; i < base_predictors_in_each_unique_term_affiliation_set.size(); ++i)  | 
 | 2328 | +    {  | 
 | 2329 | +        base_predictors_in_each_unique_term_affiliation[i] = std::vector<size_t>(base_predictors_in_each_unique_term_affiliation_set[i].begin(), base_predictors_in_each_unique_term_affiliation_set[i].end());  | 
 | 2330 | +    }  | 
2285 | 2331 | }  | 
2286 | 2332 | 
 
  | 
2287 | 2333 | void APLRRegressor::additional_cleanup_after_creating_final_model()  | 
@@ -2402,6 +2448,11 @@ std::vector<std::string> APLRRegressor::get_unique_term_affiliations()  | 
2402 | 2448 |     return unique_term_affiliations;  | 
2403 | 2449 | }  | 
2404 | 2450 | 
 
  | 
 | 2451 | +std::vector<std::vector<size_t>> APLRRegressor::get_base_predictors_in_each_unique_term_affiliation()  | 
 | 2452 | +{  | 
 | 2453 | +    return base_predictors_in_each_unique_term_affiliation;  | 
 | 2454 | +}  | 
 | 2455 | + | 
2405 | 2456 | VectorXd APLRRegressor::get_term_coefficients()  | 
2406 | 2457 | {  | 
2407 | 2458 |     return term_coefficients;  | 
 | 
0 commit comments