1 /* Copyright 2017-2021 PaGMO development team
2 
3 This file is part of the PaGMO library.
4 
5 The PaGMO library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8   * the GNU Lesser General Public License as published by the Free
9     Software Foundation; either version 3 of the License, or (at your
10     option) any later version.
11 
12 or
13 
14   * the GNU General Public License as published by the Free Software
15     Foundation; either version 3 of the License, or (at your option) any
16     later version.
17 
18 or both in parallel, as here.
19 
20 The PaGMO library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the PaGMO library.  If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #include <cassert>
30 #include <stdexcept>
31 #include <string>
32 
33 #if defined(_MSC_VER)
34 
35 // Disable a warning from MSVC in the TBB code.
36 #pragma warning(push)
37 #pragma warning(disable : 4324)
38 
39 #endif
40 
41 #include <tbb/blocked_range.h>
42 #include <tbb/parallel_for.h>
43 
44 #if defined(_MSC_VER)
45 
46 #pragma warning(pop)
47 
48 #endif
49 
50 #include <pagmo/detail/bfe_impl.hpp>
51 #include <pagmo/exceptions.hpp>
52 #include <pagmo/problem.hpp>
53 #include <pagmo/types.hpp>
54 
55 namespace pagmo
56 {
57 
58 namespace detail
59 {
60 
61 // Check the input decision vectors for a batch fitness evaluation
62 // for problem p.
bfe_check_input_dvs(const problem & p,const vector_double & dvs)63 void bfe_check_input_dvs(const problem &p, const vector_double &dvs)
64 {
65     // Fetch the number of dimensions from the problem.
66     const auto n_dim = p.get_nx();
67     // Get the total number of decision vectors packed in dvs.
68     const auto n_dvs = dvs.size() / n_dim;
69     // dvs represent a sequence of decision vectors laid out next to each other.
70     // Hence, its size must be divided by the problem's dimension exactly.
71     if (dvs.size() % n_dim) {
72         pagmo_throw(std::invalid_argument, "Invalid argument for a batch fitness evaluation: the length of the vector "
73                                            "representing the decision vectors, "
74                                                + std::to_string(dvs.size())
75                                                + ", is not an exact multiple of the dimension of the problem, "
76                                                + std::to_string(n_dim));
77     }
78     // Check all the decision vectors, using the same function employed
79     // in pagmo::problem for dv checking.
80     using range_t = tbb::blocked_range<decltype(dvs.size())>;
81     tbb::parallel_for(range_t(0, n_dvs), [&p, &dvs, n_dim](const range_t &range) {
82         for (auto i = range.begin(); i != range.end(); ++i) {
83             // NOTE: prob_check_dv only fetches cached data from p,
84             // and it is thus thread-safe.
85             prob_check_dv(p, dvs.data() + i * n_dim, n_dim);
86         }
87     });
88 }
89 
90 // Check the fitness vectors fvs produced by a bfe for problem p with input
91 // decision vectors dvs.
bfe_check_output_fvs(const problem & p,const vector_double & dvs,const vector_double & fvs)92 void bfe_check_output_fvs(const problem &p, const vector_double &dvs, const vector_double &fvs)
93 {
94     const auto n_dim = p.get_nx();
95     const auto n_dvs = dvs.size() / n_dim;
96     const auto f_dim = p.get_nf();
97     const auto n_fvs = fvs.size() / f_dim;
98     // NOTE: assume dvs has been checked already.
99     assert(dvs.size() % n_dim == 0u);
100     if (fvs.size() % f_dim) {
101         // The size of the vector of fitnesses must be divided exactly
102         // by the fitness dimension of the problem.
103         pagmo_throw(std::invalid_argument,
104                     "An invalid result was produced by a batch fitness evaluation: the length of "
105                     "the vector representing the fitness vectors, "
106                         + std::to_string(fvs.size())
107                         + ", is not an exact multiple of the fitness dimension of the problem, "
108                         + std::to_string(f_dim));
109     }
110     if (n_fvs != n_dvs) {
111         // The number of fitness vectors produced must be equal to the number of input
112         // decision vectors.
113         pagmo_throw(
114             std::invalid_argument,
115             "An invalid result was produced by a batch fitness evaluation: the number of produced fitness vectors, "
116                 + std::to_string(n_fvs) + ", differs from the number of input decision vectors, "
117                 + std::to_string(n_dvs));
118     }
119     // Check all the fitness vectors, using the same function employed
120     // in pagmo::problem for fv checking.
121     using range_t = tbb::blocked_range<decltype(fvs.size())>;
122     tbb::parallel_for(range_t(0, n_fvs), [&p, &fvs, f_dim](const range_t &range) {
123         for (auto i = range.begin(); i != range.end(); ++i) {
124             // NOTE: prob_check_fv only fetches cached data from p,
125             // and it is thus thread-safe.
126             prob_check_fv(p, fvs.data() + i * f_dim, f_dim);
127         }
128     });
129 }
130 
131 } // namespace detail
132 
133 } // namespace pagmo
134