ROL
ROL_ProgressiveHedging.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ************************************************************************
3 //
4 // Rapid Optimization Library (ROL) Package
5 // Copyright (2014) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact lead developers:
38 // Drew Kouri (dpkouri@sandia.gov) and
39 // Denis Ridzal (dridzal@sandia.gov)
40 //
41 // ************************************************************************
42 // @HEADER
43 
44 #ifndef ROL_PROGRESSIVEHEDGING_H
45 #define ROL_PROGRESSIVEHEDGING_H
46 
48 #include "ROL_PH_Objective.hpp"
49 #include "ROL_PH_StatusTest.hpp"
50 #include "ROL_RiskVector.hpp"
53 
84 namespace ROL {
85 
86 template <class Real>
88 private:
89  const Ptr<OptimizationProblem<Real>> input_;
90  const Ptr<SampleGenerator<Real>> sampler_;
91  ParameterList parlist_;
95  Real maxPen_;
96  Real update_;
97  int freq_;
98  Real ztol_;
99  int maxit_;
100  bool print_;
101 
102  bool hasStat_;
103  Ptr<PH_Objective<Real>> ph_objective_;
104  Ptr<Vector<Real>> ph_vector_;
105  Ptr<BoundConstraint<Real>> ph_bound_;
106  Ptr<Constraint<Real>> ph_constraint_;
107  Ptr<OptimizationProblem<Real>> ph_problem_;
108  Ptr<OptimizationSolver<Real>> ph_solver_;
109  Ptr<PH_StatusTest<Real>> ph_status_;
110  Ptr<Vector<Real>> z_psum_, z_gsum_;
111  std::vector<Ptr<Vector<Real>>> wvec_;
112 
113  void presolve(void) {
115  for (int j = 0; j < sampler_->numMySamples(); ++j) {
116  input_->getObjective()->setParameter(sampler_->getMyPoint(j));
117  if (input_->getConstraint() != nullPtr) {
118  input_->getConstraint()->setParameter(sampler_->getMyPoint(j));
119  }
120  solver.solve();
121  z_psum_->axpy(sampler_->getMyWeight(j),*input_->getSolutionVector());
122  solver.reset();
123  }
124  // Aggregation
125  z_gsum_->zero();
126  sampler_->sumAll(*z_psum_,*z_gsum_);
127  }
128 
129 public:
131  const Ptr<SampleGenerator<Real>> &sampler,
132  ParameterList &parlist)
133  : input_(input), sampler_(sampler), parlist_(parlist), hasStat_(false) {
134  // Get algorithmic parameters
135  usePresolve_ = parlist.sublist("SOL").sublist("Progressive Hedging").get("Use Presolve",true);
136  useInexact_ = parlist.sublist("SOL").sublist("Progressive Hedging").get("Use Inexact Solve",true);
137  penaltyParam_ = parlist.sublist("SOL").sublist("Progressive Hedging").get("Initial Penalty Parameter",10.0);
138  maxPen_ = parlist.sublist("SOL").sublist("Progressive Hedging").get("Maximum Penalty Parameter",-1.0);
139  update_ = parlist.sublist("SOL").sublist("Progressive Hedging").get("Penalty Update Scale",10.0);
140  freq_ = parlist.sublist("SOL").sublist("Progressive Hedging").get("Penalty Update Frequency",0);
141  ztol_ = parlist.sublist("SOL").sublist("Progressive Hedging").get("Nonanticipativity Constraint Tolerance",1e-4);
142  maxit_ = parlist.sublist("SOL").sublist("Progressive Hedging").get("Iteration Limit",100);
143  print_ = parlist.sublist("SOL").sublist("Progressive Hedging").get("Print Subproblem Solve History",false);
144  maxPen_ = (maxPen_ <= static_cast<Real>(0) ? ROL_INF<Real>() : maxPen_);
145  penaltyParam_ = std::min(penaltyParam_,maxPen_);
146  // Create progressive hedging vector
147  std::string type = parlist.sublist("SOL").get("Stochastic Component Type","Risk Neutral");
148  std::string prob = parlist.sublist("SOL").sublist("Probability").get("Name","bPOE");
149  hasStat_ = ((type=="Risk Averse") ||
150  (type=="Deviation") ||
151  (type=="Probability" && prob=="bPOE"));
152  Ptr<ParameterList> parlistptr = makePtrFromRef<ParameterList>(parlist);
153  if (hasStat_) {
154  ph_vector_ = makePtr<RiskVector<Real>>(parlistptr,
155  input_->getSolutionVector());
156  }
157  else {
158  ph_vector_ = input_->getSolutionVector();
159  }
160  // Create progressive hedging objective function
161  ph_objective_ = makePtr<PH_Objective<Real>>(input_->getObjective(),
162  ph_vector_,
164  parlist);
165  // Create progressive hedging bound constraint
166  if (hasStat_) {
167  ph_bound_ = makePtr<RiskBoundConstraint<Real>>(parlistptr,
168  input_->getBoundConstraint());
169  }
170  else {
171  ph_bound_ = input_->getBoundConstraint();
172  }
173  // Create progressive hedging constraint
174  ph_constraint_ = nullPtr;
175  if (input_->getConstraint() != nullPtr) {
176  if (hasStat_) {
177  ph_constraint_ = makePtr<RiskLessConstraint<Real>>(input_->getConstraint());
178  }
179  else {
180  ph_constraint_ = input_->getConstraint();
181  }
182  }
183  // Build progressive hedging subproblems
184  ph_problem_ = makePtr<OptimizationProblem<Real>>(ph_objective_,
185  ph_vector_,
186  ph_bound_,
188  input_->getMultiplierVector());
189  // Build progressive hedging subproblem solver
190  ph_solver_ = makePtr<OptimizationSolver<Real>>(*ph_problem_, parlist);
191  // Build progressive hedging status test for inexact solves
192  if (useInexact_) {
193  ph_status_ = makePtr<PH_StatusTest<Real>>(parlist,
194  *ph_vector_);
195 //*input_->getSolutionVector());
196  }
197  else {
198  ph_status_ = nullPtr;
199  }
200  // Initialize vector storage
201  z_psum_ = ph_problem_->getSolutionVector()->clone();
202  z_gsum_ = ph_problem_->getSolutionVector()->clone();
203  z_gsum_->set(*ph_problem_->getSolutionVector());
204  wvec_.resize(sampler_->numMySamples());
205  for (int i = 0; i < sampler_->numMySamples(); ++i) {
206  wvec_[i] = z_psum_->clone(); wvec_[i]->zero();
207  }
208  if (usePresolve_) {
209  presolve();
210  }
211  }
212 
213  void check(std::ostream &outStream = std::cout, const int numSamples = 1) {
214  int nsamp = std::min(sampler_->numMySamples(),numSamples);
215  for (int i = 0; i < nsamp; ++i) {
216  ph_objective_->setParameter(sampler_->getMyPoint(i));
218  if (ph_constraint_ != nullPtr) {
219  ph_constraint_->setParameter(sampler_->getMyPoint(i));
220  }
221  ph_problem_->check(outStream);
222  }
223  }
224 
225  void run(std::ostream &outStream = std::cout) {
226  const Real zero(0);
227  std::vector<Real> vec_p(2), vec_g(2);
228  Real znorm(ROL_INF<Real>()), zdotz(0);
229  int iter(0), tspiter(0), flag = 1;
230  bool converged = true;
231  // Output
232  outStream << std::scientific << std::setprecision(6);
233  outStream << std::endl << "Progressive Hedging"
234  << std::endl << " "
235  << std::setw(8) << std::left << "iter"
236  << std::setw(15) << std::left << "||z-Ez||"
237  << std::setw(15) << std::left << "penalty"
238  << std::setw(10) << std::left << "subiter"
239  << std::setw(8) << std::left << "success"
240  << std::endl;
241  for (iter = 0; iter < maxit_; ++iter) {
242  z_psum_->zero(); vec_p[0] = zero; vec_p[1] = zero;
243  ph_problem_->getSolutionVector()->set(*z_gsum_);
244  // Solve concurrent optimization problems
245  for (int j = 0; j < sampler_->numMySamples(); ++j) {
247  ph_problem_->getObjective()->setParameter(sampler_->getMyPoint(j));
248  if (useInexact_) {
249  ph_status_->setData(iter,z_gsum_);
250  }
251  if (ph_problem_->getConstraint() != nullPtr) {
252  ph_problem_->getConstraint()->setParameter(sampler_->getMyPoint(j));
253  }
254  if (print_) {
255  ph_solver_->solve(outStream,ph_status_,true);
256  }
257  else {
258  ph_solver_->solve(ph_status_,true);
259  }
260  wvec_[j]->axpy(penaltyParam_,*ph_problem_->getSolutionVector());
261  vec_p[0] += sampler_->getMyWeight(j)
262  * ph_problem_->getSolutionVector()->dot(
263  *ph_problem_->getSolutionVector());
264  vec_p[1] += static_cast<Real>(ph_solver_->getAlgorithmState()->iter);
265  z_psum_->axpy(sampler_->getMyWeight(j),*ph_problem_->getSolutionVector());
266  converged = (ph_solver_->getAlgorithmState()->statusFlag == EXITSTATUS_CONVERGED
267  ||ph_solver_->getAlgorithmState()->statusFlag == EXITSTATUS_USERDEFINED
268  ? converged : false);
269  ph_solver_->reset();
270  }
271  // Aggregation
272  z_gsum_->zero(); vec_g[0] = zero; vec_g[1] = zero;
273  sampler_->sumAll(*z_psum_,*z_gsum_);
274  sampler_->sumAll(&vec_p[0],&vec_g[0],2);
275  // Multiplier Update
276  for (int j = 0; j < sampler_->numMySamples(); ++j) {
277  wvec_[j]->axpy(-penaltyParam_,*z_gsum_);
278  }
279  zdotz = z_gsum_->dot(*z_gsum_);
280  znorm = std::sqrt(std::abs(vec_g[0] - zdotz));
281  tspiter += static_cast<int>(vec_g[1]);
282  // Output
283  outStream << " "
284  << std::setw(8) << std::left << iter
285  << std::setw(15) << std::left << znorm
286  << std::setw(15) << std::left << penaltyParam_
287  << std::setw(10) << std::left << static_cast<int>(vec_g[1])
288  << std::setw(8) << std::left << converged
289  << std::endl;
290  // Check termination criterion
291  if (znorm <= ztol_ && converged) {
292  flag = 0;
293  outStream << "Converged: Nonanticipativity constraint tolerance satisfied!" << std::endl;
294  break;
295  }
296  converged = true;
297  // Update penalty parameter
298  if (freq_ > 0 && iter%freq_ == 0) {
300  }
301  penaltyParam_ = std::min(penaltyParam_,maxPen_);
302  }
303  if (hasStat_) {
304  input_->getSolutionVector()->set(*dynamicPtrCast<RiskVector<Real>>(z_gsum_)->getVector());
305  }
306  else {
307  input_->getSolutionVector()->set(*z_gsum_);
308  }
309  // Output reason for termination
310  if (iter >= maxit_ && flag != 0) {
311  outStream << "Maximum number of iterations exceeded" << std::endl;
312  }
313  outStream << "Total number of subproblem iterations per sample: "
314  << tspiter << " / " << sampler_->numGlobalSamples()
315  << " ~ " << static_cast<int>(std::ceil(static_cast<Real>(tspiter)/static_cast<Real>(sampler_->numGlobalSamples())))
316  << std::endl;
317  }
318 
319 }; // class ProgressiveHedging
320 
321 } // namespace ROL
322 
323 #endif
ProgressiveHedging(const Ptr< OptimizationProblem< Real >> &input, const Ptr< SampleGenerator< Real >> &sampler, ParameterList &parlist)
Ptr< BoundConstraint< Real > > ph_bound_
Ptr< Vector< Real > > ph_vector_
Provides the interface to solve a stochastic program using progressive hedging.
void check(std::ostream &outStream=std::cout, const int numSamples=1)
Ptr< OptimizationProblem< Real > > ph_problem_
Ptr< Constraint< Real > > ph_constraint_
Objective_SerialSimOpt(const Ptr< Obj > &obj, const V &ui) z0_ zero()
Ptr< PH_StatusTest< Real > > ph_status_
const Ptr< SampleGenerator< Real > > sampler_
Ptr< OptimizationSolver< Real > > ph_solver_
void reset(const bool resetAlgo=true)
Reset both Algorithm and Step.
std::vector< Ptr< Vector< Real > > > wvec_
Provides a simplified interface for solving a wide range of optimization problems.
int solve(const ROL::Ptr< StatusTest< Real > > &status=ROL::nullPtr, const bool combineStatus=true)
Solve optimization problem with no iteration output.
const Ptr< OptimizationProblem< Real > > input_
void run(std::ostream &outStream=std::cout)
Ptr< PH_Objective< Real > > ph_objective_