MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
hiop.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#include "../config/config.hpp"
13#include "hiop.hpp"
14
15#ifdef MFEM_USE_HIOP
16#include <iostream>
17
18#include "hiopAlgFilterIPM.hpp"
19
20using namespace hiop;
21
22namespace mfem
23{
24
25bool HiopOptimizationProblem::get_prob_sizes(size_type &n, size_type &m)
26{
27 n = ntdofs_glob;
28 m = problem.GetNumConstraints();
29
30 return true;
31}
32
33bool HiopOptimizationProblem::get_starting_point(const size_type &n, double *x0)
34{
35 MFEM_ASSERT(x_start != NULL && ntdofs_loc == x_start->Size(),
36 "Starting point is not set properly.");
37
38 memcpy(x0, x_start->GetData(), ntdofs_loc * sizeof(double));
39
40 return true;
41}
42
44 double *xlow, double *xupp,
45 NonlinearityType *type)
46{
47 MFEM_ASSERT(n == ntdofs_glob, "Global input mismatch.");
48 MFEM_ASSERT(problem.GetBoundsVec_Lo() && problem.GetBoundsVec_Hi(),
49 "Solution bounds are not set!");
50
51 const int s = ntdofs_loc * sizeof(double);
52 std::memcpy(xlow, problem.GetBoundsVec_Lo()->GetData(), s);
53 std::memcpy(xupp, problem.GetBoundsVec_Hi()->GetData(), s);
54
55 return true;
56}
57
59 double *clow, double *cupp,
60 NonlinearityType *type)
61{
62 MFEM_ASSERT(m == m_total, "Global constraint size mismatch.");
63
64 int csize = 0;
65 if (problem.GetC())
66 {
67 csize = problem.GetEqualityVec()->Size();
68 const int s = csize * sizeof(double);
69 std::memcpy(clow, problem.GetEqualityVec()->GetData(), s);
70 std::memcpy(cupp, problem.GetEqualityVec()->GetData(), s);
71 }
72 if (problem.GetD())
73 {
74 const int s = problem.GetInequalityVec_Lo()->Size() * sizeof(double);
75 std::memcpy(clow + csize, problem.GetInequalityVec_Lo()->GetData(), s);
76 std::memcpy(cupp + csize, problem.GetInequalityVec_Hi()->GetData(), s);
77 }
78
79 return true;
80}
81
82bool HiopOptimizationProblem::eval_f(const size_type &n, const double *x,
83 bool new_x, double &obj_value)
84{
85 MFEM_ASSERT(n == ntdofs_glob, "Global input mismatch.");
86
87 if (new_x) { constr_info_is_current = false; }
88
89 Vector x_vec(ntdofs_loc);
90 x_vec = x;
91 problem.new_x = new_x;
92 obj_value = problem.CalcObjective(x_vec);
93
94 return true;
95}
96
97bool HiopOptimizationProblem::eval_grad_f(const size_type &n, const double *x,
98 bool new_x, double *gradf)
99{
100 MFEM_ASSERT(n == ntdofs_glob, "Global input mismatch.");
101
102 if (new_x) { constr_info_is_current = false; }
103
104 Vector x_vec(ntdofs_loc), gradf_vec(ntdofs_loc);
105 x_vec = x;
106 problem.new_x = new_x;
107 problem.CalcObjectiveGrad(x_vec, gradf_vec);
108 std::memcpy(gradf, gradf_vec.GetData(), ntdofs_loc * sizeof(double));
109
110 return true;
111}
112
113bool HiopOptimizationProblem::eval_cons(const size_type &n, const size_type &m,
114 const size_type &num_cons,
115 const index_type *idx_cons,
116 const double *x, bool new_x,
117 double *cons)
118{
119 MFEM_ASSERT(n == ntdofs_glob, "Global input mismatch.");
120 MFEM_ASSERT(m == m_total, "Constraint size mismatch.");
121 MFEM_ASSERT(num_cons <= m, "num_cons should be at most m = " << m);
122
123 if (num_cons == 0) { return true; }
124
125 if (new_x) { constr_info_is_current = false; }
126 Vector x_vec(ntdofs_loc);
127 x_vec = x;
128 problem.new_x = new_x;
129 UpdateConstrValsGrads(x_vec);
130
131 for (int c = 0; c < num_cons; c++)
132 {
133 MFEM_ASSERT(idx_cons[c] < m_total, "Constraint index is out of bounds.");
134 cons[c] = constr_vals(idx_cons[c]);
135 }
136
137 return true;
138}
139
141 const size_type &m,
142 const size_type &num_cons,
143 const index_type *idx_cons,
144 const double *x, bool new_x,
145 double *Jac)
146{
147 MFEM_ASSERT(n == ntdofs_glob, "Global input mismatch.");
148 MFEM_ASSERT(m == m_total, "Constraint size mismatch.");
149 MFEM_ASSERT(num_cons <= m, "num_cons should be at most m = " << m);
150
151 if (num_cons == 0) { return true; }
152
153 if (new_x) { constr_info_is_current = false; }
154 Vector x_vec(ntdofs_loc);
155 x_vec = x;
156 problem.new_x = new_x;
157 UpdateConstrValsGrads(x_vec);
158
159 for (int c = 0; c < num_cons; c++)
160 {
161 MFEM_ASSERT(idx_cons[c] < m_total, "Constraint index is out of bounds.");
162 for (int j = 0; j < ntdofs_loc; j++)
163 {
164 // The matrix is stored by rows.
165 Jac[c * ntdofs_loc + j] = constr_grads(idx_cons[c], j);
166 }
167 }
168
169 return true;
170}
171
173 index_type *cols)
174{
175#ifdef MFEM_USE_MPI
176 int nranks;
177 MPI_Comm_size(comm, &nranks);
178
179 size_type *sizes = new size_type[nranks];
180 MPI_Allgather(&ntdofs_loc, 1, MPI_HIOP_SIZE_TYPE, sizes, 1,
181 MPI_HIOP_SIZE_TYPE, comm);
182 cols[0] = 0;
183 for (int r = 1; r <= nranks; r++)
184 {
185 cols[r] = sizes[r-1] + cols[r-1];
186 }
187
188 delete [] sizes;
189 return true;
190#else
191 // Returning false means that Hiop runs in non-distributed mode.
192 return false;
193#endif
194}
195
196void HiopOptimizationProblem::solution_callback(hiop::hiopSolveStatus status,
197 hiop::size_type n,
198 const double *x,
199 const double *z_L,
200 const double *z_U,
201 hiop::size_type m,
202 const double *g,
203 const double *lambda,
204 double obj_value)
205{
206 auto hp = dynamic_cast<const HiOpProblem *>(&problem);
207 if (!hp) { return; }
208 hp->SolutionCallback(status, n, x, z_L, z_U, m, g, lambda, obj_value);
209}
210
212 double obj_value,
213 double logbar_obj_value,
214 int n,
215 const double *x,
216 const double *z_L,
217 const double *z_U,
218 int m_ineq,
219 const double *s,
220 int m,
221 const double *g,
222 const double *lambda,
223 double inf_pr,
224 double inf_du,
225 double onenorm_pr_,
226 double mu,
227 double alpha_du,
228 double alpha_pr,
229 int ls_trials)
230{
231 auto hp = dynamic_cast<const HiOpProblem *>(&problem);
232 if (!hp) { return true; }
233 return hp->IterateCallback(iter, obj_value, logbar_obj_value, n, x, z_L, z_U,
234 m_ineq, s, m, g, lambda, inf_pr, inf_du,
235 onenorm_pr_, mu, alpha_du, alpha_pr, ls_trials);
236}
237
238void HiopOptimizationProblem::UpdateConstrValsGrads(const Vector x)
239{
240 if (constr_info_is_current) { return; }
241
242 // If needed (e.g. for CG spaces), communication should be handled by the
243 // operators' Mult() and GetGradient() methods.
244
245 int cheight = 0;
246 if (problem.GetC())
247 {
248 cheight = problem.GetC()->Height();
249
250 // Values of C.
251 Vector vals_C(constr_vals.GetData(), cheight);
252 problem.GetC()->Mult(x, vals_C);
253
254 // Gradients C.
255 const Operator &oper_C = problem.GetC()->GetGradient(x);
256 const DenseMatrix *grad_C = dynamic_cast<const DenseMatrix *>(&oper_C);
257 MFEM_VERIFY(grad_C, "Hiop expects DenseMatrices as operator gradients.");
258 MFEM_ASSERT(grad_C->Height() == cheight && grad_C->Width() == ntdofs_loc,
259 "Incorrect dimensions of the C constraint gradient.");
260 for (int i = 0; i < cheight; i++)
261 {
262 for (int j = 0; j < ntdofs_loc; j++)
263 {
264 constr_grads(i, j) = (*grad_C)(i, j);
265 }
266 }
267 }
268
269 if (problem.GetD())
270 {
271 const int dheight = problem.GetD()->Height();
272
273 // Values of D.
274 Vector vals_D(constr_vals.GetData() + cheight, dheight);
275 problem.GetD()->Mult(x, vals_D);
276
277 // Gradients of D.
278 const Operator &oper_D = problem.GetD()->GetGradient(x);
279 const DenseMatrix *grad_D = dynamic_cast<const DenseMatrix *>(&oper_D);
280 MFEM_VERIFY(grad_D, "Hiop expects DenseMatrices as operator gradients.");
281 MFEM_ASSERT(grad_D->Height() == dheight && grad_D->Width() == ntdofs_loc,
282 "Incorrect dimensions of the D constraint gradient.");
283 for (int i = 0; i < dheight; i++)
284 {
285 for (int j = 0; j < ntdofs_loc; j++)
286 {
287 constr_grads(i + cheight, j) = (*grad_D)(i, j);
288 }
289 }
290 }
291
292 constr_info_is_current = true;
293}
294
296{
297#ifdef MFEM_USE_MPI
298 // Set in case a serial driver uses a parallel MFEM build.
299 comm = MPI_COMM_WORLD;
300 int initialized, nret = MPI_Initialized(&initialized);
301 MFEM_ASSERT(MPI_SUCCESS == nret, "Failure in calling MPI_Initialized!");
302 if (!initialized)
303 {
304 nret = MPI_Init(NULL, NULL);
305 MFEM_ASSERT(MPI_SUCCESS == nret, "Failure in calling MPI_Init!");
306 }
307#endif
308}
309
310#ifdef MFEM_USE_MPI
312 : OptimizationSolver(comm_), hiop_problem(NULL), comm(comm_) { }
313#endif
314
319
321{
322 problem = &prob;
324
325 if (hiop_problem) { delete hiop_problem; }
326
327#ifdef MFEM_USE_MPI
329#else
331#endif
332}
333
334void HiopNlpOptimizer::Mult(const Vector &xt, Vector &x) const
335{
336 MFEM_ASSERT(hiop_problem != NULL,
337 "Unspecified OptimizationProblem that must be solved.");
338
340
341 hiop::hiopNlpDenseConstraints hiopInstance(*hiop_problem);
342
343 hiopInstance.options->SetNumericValue("rel_tolerance", rel_tol);
344 hiopInstance.options->SetNumericValue("tolerance", abs_tol);
345 hiopInstance.options->SetIntegerValue("max_iter", max_iter);
346
347 hiopInstance.options->SetStringValue("fixed_var", "relax");
348 hiopInstance.options->SetNumericValue("fixed_var_tolerance", 1e-20);
349 hiopInstance.options->SetNumericValue("fixed_var_perturb", 1e-9);
350
351 hiopInstance.options->SetNumericValue("mu0", 1e-1);
352
353 // 0: no output; 3: not too much
354 hiopInstance.options->SetIntegerValue("verbosity_level", print_level);
355
356 // Use the IPM solver.
357 hiop::hiopAlgFilterIPM solver(&hiopInstance);
358 const hiop::hiopSolveStatus status = solver.run();
359 final_norm = solver.getObjective();
360 final_iter = solver.getNumIterations();
361
362 if (status != hiop::Solve_Success && status != hiop::Solve_Success_RelTol)
363 {
364 converged = false;
365 MFEM_WARNING("HIOP returned with a non-success status: " << status);
366 }
367 else { converged = true; }
368
369 // Copy the final solution in x.
370 solver.getSolution(x.GetData());
371}
372
373} // mfem namespace
374#endif // MFEM_USE_HIOP
Users can inherit this class to access to HiOp-specific functionality.
Definition hiop.hpp:211
virtual bool IterateCallback(int iter, double obj_value, double logbar_obj_value, int n, const double *x, const double *z_L, const double *z_U, int m_ineq, const double *s, int m, const double *g, const double *lambda, double inf_pr, double inf_du, double onenorm_pr_, double mu, double alpha_du, double alpha_pr, int ls_trials) const
See hiopInterfaceBase::iterate_callback(...).
Definition hiop.hpp:229
virtual void SolutionCallback(hiop::hiopSolveStatus status, hiop::size_type n, const double *x, const double *z_L, const double *z_U, hiop::size_type m, const double *g, const double *lambda, double obj_value) const
See hiopInterfaceBase::solution_callback(...).
Definition hiop.hpp:217
virtual void Mult(const Vector &xt, Vector &x) const
Solves the optimization problem with xt as initial guess.
Definition hiop.cpp:334
virtual ~HiopNlpOptimizer()
Definition hiop.cpp:315
virtual void SetOptimizationProblem(const OptimizationProblem &prob)
Definition hiop.cpp:320
HiopOptimizationProblem * hiop_problem
Definition hiop.hpp:255
Internal class - adapts the OptimizationProblem class to HiOp's interface.
Definition hiop.hpp:33
virtual bool get_cons_info(const hiop::size_type &m, double *clow, double *cupp, NonlinearityType *type)
Definition hiop.cpp:58
virtual bool eval_grad_f(const hiop::size_type &n, const double *x, bool new_x, double *gradf)
Definition hiop.cpp:97
void setStartingPoint(const Vector &x0)
Definition hiop.hpp:85
virtual bool iterate_callback(int iter, double obj_value, double logbar_obj_value, int n, const double *x, const double *z_L, const double *z_U, int m_ineq, const double *s, int m, const double *g, const double *lambda, double inf_pr, double inf_du, double onenorm_pr_, double mu, double alpha_du, double alpha_pr, int ls_trials)
Definition hiop.cpp:211
virtual bool get_prob_sizes(hiop::size_type &n, hiop::size_type &m)
Definition hiop.cpp:25
virtual bool eval_f(const hiop::size_type &n, const double *x, bool new_x, double &obj_value)
Definition hiop.cpp:82
virtual bool get_vecdistrib_info(hiop::size_type global_n, hiop::index_type *cols)
Definition hiop.cpp:172
virtual bool get_starting_point(const hiop::size_type &n, double *x0)
Definition hiop.cpp:33
virtual void solution_callback(hiop::hiopSolveStatus status, hiop::size_type n, const double *x, const double *z_L, const double *z_U, hiop::size_type m, const double *g, const double *lambda, double obj_value)
Definition hiop.cpp:196
virtual bool eval_cons(const hiop::size_type &n, const hiop::size_type &m, const hiop::size_type &num_cons, const hiop::index_type *idx_cons, const double *x, bool new_x, double *cons)
Definition hiop.cpp:113
virtual bool eval_Jac_cons(const hiop::size_type &n, const hiop::size_type &m, const hiop::size_type &num_cons, const hiop::index_type *idx_cons, const double *x, bool new_x, double *Jac)
Definition hiop.cpp:140
virtual bool get_vars_info(const hiop::size_type &n, double *xlow, double *xupp, NonlinearityType *type)
Definition hiop.cpp:43
real_t abs_tol
Absolute tolerance.
Definition solvers.hpp:158
real_t rel_tol
Relative tolerance.
Definition solvers.hpp:155
int print_level
(DEPRECATED) Legacy print level definition, which is left for compatibility with custom iterative sol...
Definition solvers.hpp:131
int max_iter
Limit for the number of iterations the solver is allowed to do.
Definition solvers.hpp:152
int width
Dimension of the input / number of columns in the matrix.
Definition operator.hpp:28
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:27
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
virtual Operator & GetGradient(const Vector &x) const
Evaluate the gradient operator at the point x. The default behavior in class Operator is to generate ...
Definition operator.hpp:122
virtual void CalcObjectiveGrad(const Vector &x, Vector &grad) const
The result grad is expected to enter with the correct size.
Definition solvers.hpp:871
const Vector * GetEqualityVec() const
Definition solvers.hpp:880
int GetNumConstraints() const
Definition solvers.cpp:2342
virtual real_t CalcObjective(const Vector &x) const =0
Objective F(x). In parallel, the result should be reduced over tasks.
const Vector * GetInequalityVec_Hi() const
Definition solvers.hpp:882
const Operator * GetC() const
Definition solvers.hpp:878
const Vector * GetBoundsVec_Hi() const
Definition solvers.hpp:884
const Operator * GetD() const
Definition solvers.hpp:879
const Vector * GetInequalityVec_Lo() const
Definition solvers.hpp:881
const Vector * GetBoundsVec_Lo() const
Definition solvers.hpp:883
Abstract solver for OptimizationProblems.
Definition solvers.hpp:891
const OptimizationProblem * problem
Definition solvers.hpp:893
Vector data type.
Definition vector.hpp:80
int Size() const
Returns the size of the vector.
Definition vector.hpp:218
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:227
real_t mu
Definition ex25.cpp:140
prob_type prob
Definition ex25.cpp:156
RefCoord s[3]