optimize_least_squares.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 <cstring>
21 #include <stdexcept>
22 #include <limits>
23 #include "mango.hpp"
24 #include "Least_squares_solver.hpp"
25 
27 
28  mpi_partition = mpi_partition_in;
30 
31  int j;
32  bool proc0_world = mpi_partition->get_proc0_world();
33 
34  if (verbose > 0) std::cout << "Hello world from Least_squares_solver::optimize()" << std::endl;
35 
36  // I need to think about this next bit. Do all group leaders need a copy of sigmas and targets?
37  // For hopspack, they do, because the residuals are combined into the total objective function on each group leader.
38  // But for finite difference Jacobians, only proc0 needs sigmas and targets.
39  // If they do, then they must all agree on N_terms; otherwise probably the size of targets and sigmas
40  // will be incorrect on non-master procs.
41  // Make sure that all procs agree on sigmas and targets.
42  MPI_Bcast(targets, N_terms, MPI_DOUBLE, 0, mpi_partition->get_comm_group_leaders());
43  MPI_Bcast(sigmas, N_terms, MPI_DOUBLE, 0, mpi_partition->get_comm_group_leaders());
44 
45  if (algorithms[algorithm].uses_derivatives && !proc0_world && algorithms[algorithm].package != PACKAGE_MANGO) {
46  // In line above, we include algorithms[algorithm].package != PACKAGE_MANGO
47  // because MANGO's own algorithms may need a parallel line search in addition to parallel gradients.
48  // Therefore MANGO's own algorithms are responsible for launching their own group_leaders_loop.
49  // For a more general solution, I might want to consider adding an algorithm property like "parallel_only_in_gradient".
51  return std::numeric_limits<double>::quiet_NaN();
52  }
53 
54  // proc0_world always continues past this point.
55  // For finite-difference-derivative algorithms, the other procs do not go past this point.
56  // For parallel algorithms that do not use finite-difference derivatives, such as HOPSPACK, the other group leader procs DO continue past this point.
57 
59 
60  // Verify that the sigmas array is all nonzero.
61  for (j=0; j<N_terms; j++) {
62  if (sigmas[j] == 0.0) {
63  std::cerr << "Error! The (0-based) entry " << j << " in the sigmas array is 0. sigmas must all be nonzero." << std::endl;
64  throw std::runtime_error("Error in mango::problem::optimize_least_squares. sigmas is not all nonzero.");
65  }
66  }
67 
68  if (proc0_world) {
69 
70  /*
71  // Open output file
72  output_file.open(output_filename.c_str());
73  if (!output_file.is_open()) {
74  std::cout << "output file: " << output_filename << std::endl;
75  throw std::runtime_error("Error in mango::problem::optimize_least_squares(). Unable to open output file.");
76  }
77  // Write header line of output file
78  output_file << "Least squares?" << std::endl << "yes" << std::endl << "N_parameters:" << std::endl << N_parameters << std::endl << "function_evaluation,seconds";
79  for (j=0; j<N_parameters; j++) {
80  output_file << ",x(" << j+1 << ")";
81  }
82  output_file << ",objective_function";
83  if (print_residuals_in_output_file) {
84  for (j=0; j<N_terms; j++) {
85  output_file << ",F(" << j+1 << ")";
86  }
87  }
88  output_file << std::endl << std::flush;
89  */
90 
91  /* Sanity test */
92  /* if (!least_squares_algorithm) {
93  std::cout << "Error in optimize_least_squares(). Should not get here!\n";
94  exit(1);
95  }*/
96 
97  /* objective_function = (mango::objective_function_type) &mango::problem::least_squares_to_single_objective; */
98  } // if (proc0_world)
99 
100  // 20200129 This next line was moved to the constructor
101  //objective_function = &mango::Least_squares_solver::least_squares_to_single_objective;
102 
103  // This next bit is useful for hopspack.
104  memset(best_residual_function, 0, N_terms*sizeof(double));
106 
107  // Perform the main optimization.
108  if (algorithms[algorithm].least_squares) {
110  } else {
111  // Non-least-squares algorithms
112  package->optimize(this);
113  }
114 
115  if (!proc0_world) return std::numeric_limits<double>::quiet_NaN();
116  // Only proc0_world continues past this point.
117 
118  // Tell the other group leaders to exit.
119  int data = -1;
120  MPI_Bcast(&data,1,MPI_INT,0,mpi_partition->get_comm_group_leaders());
121 
122  memcpy(state_vector, best_state_vector, N_parameters * sizeof(double)); // Make sure we leave state_vector equal to the best state vector seen.
123 
124  recorder->finalize();
125  /*
126  // Copy the line corresponding to the optimum to the bottom of the output file.
127  int function_evaluations_temp= function_evaluations;
128  function_evaluations = best_function_evaluation;
129  write_least_squares_file_line(best_time, state_vector, best_objective_function, best_residual_function);
130  function_evaluations = function_evaluations_temp;
131 
132  output_file.close();
133  */
134 
135  if (verbose > 0) {
136  std::cout << "Here comes the optimal state_vector from optimize_least_squares.cpp: " << state_vector[0];
137  for (int j=1; j<N_parameters; j++) {
138  std::cout << ", " << state_vector[j];
139  }
140  std::cout << std::endl;
141  }
142 
144 }
145 
146 /////////////////////////////////////////////////////////////
147 /////////////////////////////////////////////////////////////
148 
149 void mango::Least_squares_solver::least_squares_to_single_objective(int* N, const double* x, double* f, int* failed_int, mango::Problem* this_problem, void* user_data) {
150  // Note that this function is static, so "this" does not exist.
151  // We therefore need a pointer to the Least_squares_solver.
152  // Since this function is being called, this_problem->solver must be a Least_squares_solver, so we can cast the pointer:
153  Least_squares_solver* least_squares_solver = (Least_squares_solver*)(this_problem->get_solver());
154 
155  // Note that this subroutine sets the 'residuals' array of the mango::Least_squares_solver class.
156 
157  if (least_squares_solver->verbose > 0) std::cout << "Hello from least_squares_to_single_objective" << std::endl;
158  //double* residuals = new double[N_terms];
159 
160  bool failed_bool;
161  least_squares_solver->residual_function_wrapper(x, least_squares_solver->residuals, &failed_bool);
162  if (failed_bool) {
163  *failed_int = 1;
164  } else {
165  *failed_int = 0;
166  }
167 
168  int N_terms = least_squares_solver->N_terms;
169  double term;
170  *f = 0;
171  for (int j=0; j<N_terms; j++) {
172  term = (least_squares_solver->residuals[j] - least_squares_solver->targets[j]) / least_squares_solver->sigmas[j];
173  *f += term*term;
174  }
175 
176  least_squares_solver->current_residuals = least_squares_solver->residuals;
177  //delete[] residuals;
178 }
179 
180 /////////////////////////////////////////////////////////////
181 /////////////////////////////////////////////////////////////
182 
184  // Combine the residuals into the total objective function.
185  double total_objective_function, temp;
186  int j;
187 
188  total_objective_function = 0;
189  for (j=0; j<N_terms; j++) {
190  temp = (residuals_in[j] - targets[j]) / sigmas[j];
191  total_objective_function += temp*temp;
192  }
193  return(total_objective_function);
194 }
195 
196 
mango::Least_squares_solver::current_residuals
double * current_residuals
Definition: Least_squares_solver.hpp:45
Least_squares_solver.hpp
mango::Solver::package
Package * package
Definition: Solver.hpp:57
mango::Least_squares_solver::N_terms
int N_terms
Definition: Least_squares_solver.hpp:38
mango::Least_squares_solver::sigmas
double * sigmas
Definition: Least_squares_solver.hpp:40
mango::Least_squares_solver::least_squares_to_single_objective
static void least_squares_to_single_objective(int *, const double *, double *, int *, mango::Problem *, void *)
Definition: optimize_least_squares.cpp:149
mango::Solver::verbose
int verbose
Definition: Solver.hpp:63
mango::MPI_Partition::get_comm_group_leaders
MPI_Comm get_comm_group_leaders()
Get the MPI communicator for MANGO's "group leaders" communicator.
Definition: mpi_partition.cpp:51
mango::Least_squares_solver::optimize
double optimize(MPI_Partition *)
Definition: optimize_least_squares.cpp:26
mango::Least_squares_solver
Definition: Least_squares_solver.hpp:28
mango::Package::optimize
virtual void optimize(Solver *)=0
mango::Solver::state_vector
double * state_vector
Definition: Solver.hpp:58
mango::Solver::best_state_vector
double * best_state_vector
Definition: Solver.hpp:50
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::Least_squares_solver::residuals
double * residuals
Definition: Least_squares_solver.hpp:43
mango::Solver::init_optimization
virtual void init_optimization()
Definition: init_optimization.cpp:28
mango::Solver::recorder
Recorder * recorder
Definition: Solver.hpp:67
mango::Solver::best_objective_function
double best_objective_function
Definition: Solver.hpp:51
mango::Solver::mpi_partition
MPI_Partition * mpi_partition
Definition: Solver.hpp:65
mango::PACKAGE_MANGO
@ PACKAGE_MANGO
Definition: mango.hpp:40
mango.hpp
mango::Problem::get_solver
Solver * get_solver()
Get the Solver object associated with the optimization problem.
Definition: Problem.cpp:180
mango::Least_squares_solver::group_leaders_loop
void group_leaders_loop()
Definition: group_leaders_loop_least_squares.cpp:23
mango::Solver::N_parameters
int N_parameters
Definition: Solver.hpp:43
mango::Solver::algorithm
algorithm_type algorithm
Definition: Solver.hpp:42
mango::MPI_Partition::get_proc0_world
bool get_proc0_world()
Determine whether this MPI processor has rank 0 in MANGO's world communicator.
Definition: mpi_partition.cpp:56
mango::Solver::function_evaluations
int function_evaluations
Definition: Solver.hpp:45
mango::MPI_Partition
A class for dividing the set of MPI processes into worker groups.
Definition: mango.hpp:195
mango::Least_squares_solver::residuals_to_single_objective
double residuals_to_single_objective(double *)
Definition: optimize_least_squares.cpp:183
mango::Package::optimize_least_squares
virtual void optimize_least_squares(Least_squares_solver *)=0
mango::Least_squares_solver::residual_function_wrapper
void residual_function_wrapper(const double *, double *, bool *)
Definition: residual_function_wrapper.cpp:26
mango::Recorder::finalize
virtual void finalize()
Definition: Recorder.hpp:31
mango::Least_squares_solver::best_residual_function
double * best_residual_function
Definition: Least_squares_solver.hpp:42
mango::Problem
Definition: mango.hpp:442
mango::Least_squares_solver::targets
double * targets
Definition: Least_squares_solver.hpp:39