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 // In this tutorial, we will learn how to code a
30 // stochastic problem. We will focus on the trivial minimization
31 // problem where the objective is (as in the previous tutorials)
32 // f = x1^2 + x2^2 + x3^2 + x4^2 + s
33 // in the bounds: -10 <= xi <= 10. Note that s is our stochastic
34 // variable which we consider normally distributed around 0 with standard
35 // deviation equal to 1.
36 
37 // All we need to do is to implement a class having the
38 // following mandatory methods:
39 //
40 // fitness_vector fitness(const decision_vector &) const
41 // std::pair<decision_vector, decision_vector> get_bounds() const
42 //
43 // and add the method
44 //
45 // void set_seed(unsigned)
46 //
47 // which will be used to change the seed of the random engine
48 
49 #include <string>
50 
51 #include <pagmo/io.hpp>
52 #include <pagmo/problem.hpp>
53 #include <pagmo/rng.hpp>
54 #include <pagmo/s11n.hpp>
55 #include <pagmo/types.hpp>
56 
57 using namespace pagmo;
58 class problem_basic_s
59 {
60 public:
61     // Since the problem is stochastic we introduce as data members a random engine
62     // and a seed
problem_basic_s(unsigned seed=pagmo::random_device::next ())63     problem_basic_s(unsigned seed = pagmo::random_device::next()) : m_e(seed), m_seed(seed) {}
64 
65     // Mandatory, computes ... well ... the fitness.
66     // In a stochastic problem the fitness depends on the
67     // chromosome (decision vector) but also on a number
68     // of stochastic variables which are instantiated from a
69     // common seed s
fitness(const vector_double & x) const70     vector_double fitness(const vector_double &x) const
71     {
72         // We seed the random engine
73         m_e.seed(m_seed);
74         // We define a normal distribution
75         auto s = std::normal_distribution<double>(0., 1.);
76         // We return the fitness
77         return {x[0] * x[0] + x[1] * x[1] + x[2] * x[2] + x[3] * x[3] + s(m_e)};
78     }
79 
80     // Mandatory, returns the box-bounds
get_bounds() const81     std::pair<vector_double, vector_double> get_bounds() const
82     {
83         return {{-10, -10, -10, -10}, {10, 10, 10, 10}};
84     }
85 
86     // Mandatory for the problem to be stochastic
set_seed(unsigned seed)87     void set_seed(unsigned seed)
88     {
89         m_seed = seed;
90     }
91 
92     // Optional, provides a name for the problem overrding the default name
get_name() const93     std::string get_name() const
94     {
95         return "My Problem";
96     }
97 
98     // Optional, provides extra information that will be appended after
99     // the default stream operator
get_extra_info() const100     std::string get_extra_info() const
101     {
102         return "This is just a simple toy problem with one objective,\n no constraints and a fixed dimension of 4.\n";
103     }
104 
105     // Optional methods-data can also be accessed later via
106     // the problem::extract() method
best_known() const107     vector_double best_known() const
108     {
109         return {0., 0., 0., 0.};
110     }
111 
112 private:
113     // Random engine
114     mutable detail::random_engine_type m_e;
115     // Seed
116     unsigned m_seed;
117 };
118 
main()119 int main()
120 {
121     // Constructing a problem
122     problem p0{problem_basic_s{}};
123     // Streaming to screen the problem
124     std::cout << p0 << '\n';
125     // Getting its dimensions
126     std::cout << "Calling the dimension getter: " << p0.get_nx() << '\n';
127     std::cout << "Calling the fitness dimension getter: " << p0.get_nobj() << '\n';
128 
129     // Getting the bounds via the pagmo::print eating also std containers
130     pagmo::print("Calling the bounds getter: ", p0.get_bounds(), "\n");
131 
132     // As soon as a problem its created its function evaluation counter
133     // is set to zero. Checking its value is easy
134     pagmo::print("fevals: ", p0.get_fevals(), "\n");
135     // Computing one fitness
136     pagmo::print("calling fitness in x=[2,2,2,2]: ", p0.fitness({2, 2, 2, 2}), "\n");
137     // The evaluation counter is now ... well ... 1
138     pagmo::print("fevals: ", p0.get_fevals(), "\n");
139     // Changing the seed
140     p0.set_seed(3245323u);
141     pagmo::print("seed changed to: " + std::to_string(3245323u), '\n');
142     // Recomputing the fitness which will be ... well ... different
143     pagmo::print("calling fitness in x=[2,2,2,2]: ", p0.fitness({2, 2, 2, 2}), "\n");
144 
145     // While our problem_basic_s struct is now hidden inside the pagmo::problem
146     // we can still access its methods / data via the extract interface
147     pagmo::print("Accessing best_known: ", p0.extract<problem_basic_s>()->best_known(), "\n");
148 }
149