Problem.cpp
Go to the documentation of this file.
1 // Copyright 2019, University of Maryland and the MANGO development team.
2 //
3 // This file is part of MANGO.
4 //
5 // MANGO is free software: you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License as
7 // published by the Free Software Foundation, either version 3 of the
8 // License, or (at your option) any later version.
9 //
10 // MANGO is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with MANGO. If not, see
17 // <https://www.gnu.org/licenses/>.
18 
19 #include <iostream>
20 #include <string>
21 #include <stdexcept>
22 #include <cassert>
23 #include "mango.hpp"
24 #include "Solver.hpp"
25 
26 // Constructor for non-least-squares problems
27 mango::Problem::Problem(int N_parameters_in, double* state_vector_in, objective_function_type objective_function_in, int argc_in, char* argv_in[]) {
28  solver = new Solver(this,N_parameters_in);
29  solver->argc = argc_in;
30  solver->argv = argv_in;
31  solver->N_parameters = N_parameters_in;
32  solver->objective_function = objective_function_in;
33  solver->state_vector = state_vector_in;
34 }
35 
36 // Destructor
38  if (solver->verbose > 0) std::cout << "Mango problem is being destroyed." << std::endl;
39  delete solver;
40 }
41 
43  return solver->N_parameters;
44 }
45 
47  return solver->best_function_evaluation;
48 }
49 
51  return solver->state_vector;
52 }
53 
55  return solver->function_evaluations;
56 }
57 
58 void mango::Problem::set_bound_constraints(double* lb, double* ub) {
59  solver->lower_bounds = lb;
60  solver->upper_bounds = ub;
61  solver->bound_constraints_set = true;
62 }
63 
65  solver->centered_differences = new_bool;
66 }
67 
69  solver->finite_difference_step_size = delta;
70 }
71 
73  if (n < 1) throw std::runtime_error("Error! max_function_evaluations must be >= 1.");
74  solver->max_function_evaluations = n;
75 }
76 
78  solver->verbose = v;
79 }
80 
81 void mango::Problem::set_output_filename(std::string filename) {
82  solver->output_filename = filename;
83 }
84 
85 void mango::Problem::set_user_data(void* user_data) {
86  solver->user_data = user_data;
87 }
88 
89 #define bold_line "****************************************************************************************"
90 void mango::Problem::mpi_init(MPI_Comm mpi_comm_world) {
91  // This method basically just calls MPI_Partition::init, but first checks to see if the algorithm
92  // chosen can support parallel function evaluations. If not, N_worker_groups is set to 1.
93 
94  if (solver->algorithm < 0) throw std::runtime_error("Error in mango::Problem::mpi_init. Algorithm cannot be negative.");
95  if (solver->algorithm >= NUM_ALGORITHMS) throw std::runtime_error("Error in mango::Problem::mpi_init. Algorithm is too large.");
96 
97  mpi_partition.verbose = solver->verbose;
98 
99  if (algorithms[solver->algorithm].parallel) {
100  int mpi_rank_world, N_procs_world;
101  MPI_Comm_size(mpi_comm_world, &N_procs_world);
102  MPI_Comm_rank(mpi_comm_world, &mpi_rank_world);
103 
104  if ((N_procs_world > 1) && (mpi_partition.get_N_worker_groups() == 1) && (mpi_rank_world==0)) {
105  std::cerr << bold_line << std::endl;
106  std::cerr << "WARNING!!! You have chosen an algorithm that can exploit concurrent function evaluations" << std::endl;
107  std::cerr << "but you have set N_worker_groups=1. You probably want a larger value." << std::endl;
108  std::cerr << bold_line << std::endl;
109  }
110  } else {
111  // There is no point having >1 worker groups with these algorithms.
112  mpi_partition.set_N_worker_groups(1);
113  }
114 
115  mpi_partition.init(mpi_comm_world);
116 }
117 
118 
120  // Delegate this work to Solver so we don't need to put "solver->" in front of all the variables, and so we can replace solver with derived classes.
121  if (solver->N_line_search <= 0) solver->N_line_search = mpi_partition.get_N_worker_groups();
122  return solver->optimize(&mpi_partition);
123 }
124 
125 
126 void mango::Problem::set_relative_bound_constraints(double min_factor, double max_factor, double min_radius, bool preserve_sign) {
127  if (min_factor < 0) throw std::runtime_error("mango::Problem::set_relative_bound_constraints: min_factor must be >= 0.");
128  if (min_factor > 1) throw std::runtime_error("mango::Problem::set_relative_bound_constraints: min_factor must be <= 1.");
129 
130  if (max_factor < 1) throw std::runtime_error("mango::Problem::set_relative_bound_constraints: max_factor must be >= 1.");
131 
132  if (min_radius < 0) throw std::runtime_error("mango::Problem::set_relative_bound_constraints: min_radius must be >= 0.");
133 
134  if (! solver->bound_constraints_set) throw std::runtime_error("mango::Problem::set_relative_bound_constraints can only be called after bound constraints are set.");
135 
136  int j;
137  double temp;
138  if (preserve_sign) {
139  // Approach in which the sign of the variable is preserved.
140  for (j=0; j < solver->N_parameters; j++) {
141  if (solver->state_vector[j] > 0) {
142  // Initial value and both bounds are positive
143  solver->lower_bounds[j] = min_factor * solver->state_vector[j];
144  solver->upper_bounds[j] = max_factor * solver->state_vector[j];
145  if (solver->upper_bounds[j] - solver->state_vector[j] < min_radius) solver->upper_bounds[j] = solver->state_vector[j] + min_radius;
146  if (solver->state_vector[j] - solver->lower_bounds[j] < min_radius) solver->lower_bounds[j] = solver->state_vector[j] - min_radius;
147  if (solver->lower_bounds[j] < 0) solver->lower_bounds[j] = 0;
148  } else if (solver->state_vector[j] < 0) {
149  // Initial value and both bounds are negative
150  solver->lower_bounds[j] = max_factor * solver->state_vector[j];
151  solver->upper_bounds[j] = min_factor * solver->state_vector[j];
152  if (solver->upper_bounds[j] - solver->state_vector[j] < min_radius) solver->upper_bounds[j] = solver->state_vector[j] + min_radius;
153  if (solver->state_vector[j] - solver->lower_bounds[j] < min_radius) solver->lower_bounds[j] = solver->state_vector[j] - min_radius;
154  if (solver->upper_bounds[j] > 0) solver->upper_bounds[j] = 0;
155  } else {
156  // Initial value is 0, so there is a bound of each sign
157  assert(solver->state_vector[j] == 0);
158  solver->lower_bounds[j] = -min_radius;
159  solver->upper_bounds[j] = min_radius;
160  }
161  if (! (solver->upper_bounds[j] >= solver->lower_bounds[j])) std::cout << "ub:" << solver->upper_bounds[j] << " lb:" << solver->lower_bounds[j] << "\n";
162  assert(solver->upper_bounds[j] >= solver->lower_bounds[j]);
163  }
164  } else {
165  // Approach in which the sign of the variable is not preserved.
166  for (j=0; j < solver->N_parameters; j++) {
167  temp = max_factor * abs(solver->state_vector[j]);
168  if (temp < min_radius) temp = min_radius;
169  solver->lower_bounds[j] = -temp;
170  solver->upper_bounds[j] = temp;
171  assert(solver->upper_bounds[j] >= solver->lower_bounds[j]);
172  }
173  }
174 }
175 
176 void mango::Problem::set_N_line_search(int N_line_search) {
177  solver->N_line_search = N_line_search;
178 }
179 
181  return solver;
182 }
mango::Problem::set_N_line_search
void set_N_line_search(int N_line_search)
Sets the number of points considered as a set for parallel line searches.
Definition: Problem.cpp:176
mango::Problem::solver
Solver * solver
Definition: mango.hpp:446
mango::Solver::objective_function
objective_function_type objective_function
Definition: Solver.hpp:44
mango::algorithm_properties::parallel
bool parallel
Whether the algorithm can support concurrent evaluations of the objective function....
Definition: mango.hpp:63
mango::Solver::argc
int argc
Definition: Solver.hpp:46
mango::Problem::get_N_parameters
int get_N_parameters()
Get the number of independent variables for an optimization problem.
Definition: Problem.cpp:42
mango::Problem::set_user_data
void set_user_data(void *user_data)
Pass the prescribed pointer to the objective function whenever it is called.
Definition: Problem.cpp:85
Solver.hpp
mango::Solver::state_vector
double * state_vector
Definition: Solver.hpp:58
mango::algorithms
const algorithm_properties algorithms[NUM_ALGORITHMS]
A database of the algorithms that MANGO is aware of, including various properties of each algorithm.
Definition: mango.hpp:124
mango::Problem::set_max_function_evaluations
void set_max_function_evaluations(int N)
Set the maximum number of evaluations of the objective function that will be allowed before the optim...
Definition: Problem.cpp:72
mango::Problem::set_verbose
void set_verbose(int verbose)
Control how much diagnostic information is printed by MANGO.
Definition: Problem.cpp:77
mango::Problem::get_best_function_evaluation
int get_best_function_evaluation()
For an optimization problem that has already been solved, return the index of the function evaluation...
Definition: Problem.cpp:46
bold_line
#define bold_line
Definition: Problem.cpp:89
mango::Problem::set_output_filename
void set_output_filename(std::string filename)
Sets the name of the output file that will record values of the objective function at each evaluation...
Definition: Problem.cpp:81
mango::Problem::get_state_vector
double * get_state_vector()
Get the vector of independent variables.
Definition: Problem.cpp:50
mango::Problem::set_centered_differences
void set_centered_differences(bool centered_differences)
Control whether 1-sided or centered finite differences will be used to compute derivatives of the obj...
Definition: Problem.cpp:64
mango::Solver::argv
char ** argv
Definition: Solver.hpp:47
mango.hpp
mango::Problem::set_finite_difference_step_size
void set_finite_difference_step_size(double finite_difference_step_size)
Set an absolute step size for finite difference derivatives.
Definition: Problem.cpp:68
mango::Problem::get_solver
Solver * get_solver()
Get the Solver object associated with the optimization problem.
Definition: Problem.cpp:180
mango::objective_function_type
void(* objective_function_type)(int *N_parameters, const double *state_vector, double *objective_value, int *failed, mango::Problem *problem, void *user_data)
Format for the user-supplied subroutine that computes the objective function for a general (non least...
Definition: mango.hpp:424
mango::Solver::N_parameters
int N_parameters
Definition: Solver.hpp:43
mango::Solver
Definition: Solver.hpp:31
mango::Problem::Problem
Problem(int N_parameters, double *state_vector, objective_function_type objective_function, int argc, char **argv)
Constructor for a standard optimization problem.
Definition: Problem.cpp:27
mango::Problem::mpi_init
void mpi_init(MPI_Comm mpi_comm)
Initialize MANGO's internal MPI data that describes the partitioning of the processes into worker gro...
Definition: Problem.cpp:90
mango::Problem::set_relative_bound_constraints
void set_relative_bound_constraints(double min_factor, double max_factor, double min_radius, bool preserve_sign)
Impose bound constraints on an optimization problem, with the bounds chosen as multiples of the initi...
Definition: Problem.cpp:126
mango::Problem::get_function_evaluations
int get_function_evaluations()
For an optimization problem that has already been solved, return the number of times the objective fu...
Definition: Problem.cpp:54
mango::Problem::~Problem
~Problem()
Destructor.
Definition: Problem.cpp:37
mango::Problem::Solver
friend class Solver
Definition: mango.hpp:443
mango::NUM_ALGORITHMS
@ NUM_ALGORITHMS
Not an actual algorithm, just counting.
Definition: mango.hpp:117
mango::Problem::optimize
double optimize()
Solve the optimization problem that has been set up.
Definition: Problem.cpp:119
mango::Problem::set_bound_constraints
void set_bound_constraints(double *lower, double *upper)
Sets bound constraints for the optimization problem.
Definition: Problem.cpp:58