Unfit  3.1.1
Data fitting and optimization software
GenerateInitialGuess.hpp
1 // Unfit: Data fitting and optimization software
2 //
3 // Copyright (C) 2012- Dr Martin Buist & Dr Alberto Corrias
4 // Contacts: martin.buist _at_ nus.edu.sg; alberto _at_ nus.edu.sg
5 //
6 // See the 'Contributors' file for a list of those who have contributed
7 // to this work.
8 //
9 // This program is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 3 of the License, or
12 // (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 //
22 #ifndef UNFIT_NOTFORRELEASE_GENERATEINITIALGUESS_HPP_
23 #define UNFIT_NOTFORRELEASE_GENERATEINITIALGUESS_HPP_
24 
25 #include <algorithm>
26 #include <future>
27 #include <numeric>
28 #include <random>
29 #include <vector>
30 
31 #include <iostream>
32 
33 namespace // file scope
34 {
35 template <class T>
36 std::vector<double> RunOneTrial(Unfit::GenericCostFunction &cost_func,
37  const std::vector<double> &lb, const std::vector<double> &ub,
38  int number_of_unknowns, int trial, int population_per_trial,
39  double cost_tol = 1e-4, double geom_tol = 1e-2)
40 {
41  T opt;
42  for (auto i = 0; i < number_of_unknowns; ++i) {
43  opt.bounds.SetBounds(i, lb[i], ub[i]);
44  }
45  opt.options.SetPopulationSize(population_per_trial);
46  // Reduced tolerances as we don't need an exact solution here
47  opt.options.SetCostTolerance(cost_tol);
48  opt.options.SetGeometricTolerance(geom_tol);
49  opt.options.SetRandomSeed(10*trial);
50  // Initial guess
51  std::vector<double> coordinates(number_of_unknowns, 0.0);
52  if (!opt.GetIsPopulationBased()) {
53  // If the algorithm does not generate a population internally, we will have
54  // to generate a random guess here or we will always be starting our
55  // optimization from the origin
56  std::mt19937 random_engine(opt.options.GetRandomSeed());
57  for (auto i = 0; i < number_of_unknowns; ++i) {
58  auto dist = std::uniform_real_distribution<double>(lb[i], ub[i]);
59  coordinates[i] = dist(random_engine);
60  }
61  }
62  // Minimise
63  opt.FindMin(cost_func, coordinates);
64  // Append the cost to the coordinates as needed by SetPopulation
65  auto residuals = cost_func(coordinates);
66  auto cost = std::inner_product(begin(residuals), end(residuals),
67  begin(residuals), 0.0);
68  coordinates.push_back(cost);
69  return coordinates;
70 }
71 } // namespace
72 
73 namespace Unfit
74 {
75 template <class T>
76 std::vector<std::vector<double>> GenerateInitialPopulation(
77  GenericCostFunction &cost_func, const std::vector<double> &lb,
78  const std::vector<double> &ub, int number_of_unknowns, int number_of_trials,
79  int population_per_trial, double cost_tol = 1e-4,
80  double geom_tol = 1e-2)
81 {
82  std::vector<std::vector<double>> population(number_of_trials);
83  // Serial implementation
84 // for (auto trial = 0; trial < number_of_trials; ++trial) {
85 // population[trial] = RunOneTrial<T>(cost_func, lb, ub, number_of_unknowns,
86 // trial, population_per_trial, cost_tol, geom_tol);
87 // }
88  // Threaded (parallel) implementation
89  std::vector<std::future<std::vector<double>>>population_futures;
90  for (auto trial = 0; trial < number_of_trials; ++trial) {
91  population_futures.push_back(std::async(std::launch::async,
92  &RunOneTrial<T>, std::ref(cost_func), lb, ub, number_of_unknowns, trial,
93  population_per_trial, cost_tol, geom_tol));
94  }
95  for (auto trial = 0; trial < number_of_trials; ++trial) {
96  population[trial] = population_futures[trial].get();
97  }
98  return population;
99 }
100 
101 template <class T>
102 std::vector<std::vector<double>> GenerateInitialPopulation(
103  GenericCostFunction &cost_func, const std::vector<double> &lb,
104  const std::vector<double> &ub, int number_of_unknowns)
105 {
106  const int number_of_trials {16};
107  const int population_per_trial {16};
108  const double cost_tol {1e-4};
109  const double geom_tol {1e-2};
110 
111  return GenerateInitialPopulation<T>(cost_func, lb, ub, number_of_unknowns,
112  number_of_trials, population_per_trial, cost_tol, geom_tol);
113 }
114 
115 template <class T>
116 std::vector<double> GenerateInitialGuess(GenericCostFunction &cost_func,
117  const std::vector<double> &lb, const std::vector<double> &ub,
118  int number_of_unknowns, int number_of_trials, int population_per_trial,
119  double cost_tol = 1e-4, double geom_tol = 1e-2)
120 {
121  std::vector<std::vector<double>> population = GenerateInitialPopulation<T>(
122  cost_func, lb, ub, number_of_unknowns, number_of_trials,
123  population_per_trial, cost_tol, geom_tol);
124  // Sort the population by cost low -> high
125  std::sort(begin(population), end(population),
126  [](const std::vector<double> &x, const std::vector<double> &y) {
127  return y.back() > x.back();
128  });
129  // Return the best member, with the cost removed
130  population[0].pop_back();
131  return population[0];
132 }
133 
134 template <class T>
135 std::vector<double> GenerateInitialGuess(GenericCostFunction &cost_func,
136  const std::vector<double> &lb, const std::vector<double> &ub,
137  int number_of_unknowns)
138 {
139  const int number_of_trials {16};
140  const int population_per_trial {10*number_of_unknowns};
141  const double cost_tol {1e-4};
142  const double geom_tol {1e-2};
143 
144  return GenerateInitialGuess<T>(cost_func, lb, ub, number_of_unknowns,
145  number_of_trials, population_per_trial, cost_tol, geom_tol);
146 }
147 } // namespace Unfit
148 
149 #endif
Definition: Bounds.hpp:27
Definition: GenericCostFunction.hpp:36