Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
14b2184
interface draft
cnpetra Mar 3, 2025
14a243c
wrapper for WeiInProd wrapper in NlpFormulation
cnpetra Mar 5, 2025
89bc337
draft of InnerProd class
cnpetra Mar 5, 2025
a1ae282
cleaning up
cnpetra Mar 6, 2025
826c5d2
temp code + notes
cnpetra Mar 6, 2025
46c055f
added additional functionality for residual norm (weighted)
cnpetra Mar 6, 2025
1caeb33
IPM alg nlp errors
cnpetra Mar 7, 2025
e4edea2
clean up, fixed warnings
cnpetra Mar 7, 2025
cab209f
addressed MPI issues
cnpetra Mar 7, 2025
bf79f0d
exposing mass matrix in the example
cnpetra Mar 14, 2025
5887c75
added volume and lumped matrix
cnpetra Mar 14, 2025
f0de791
adding weights through the code (linear system and resids)
cnpetra Mar 14, 2025
67f98d9
weighted log barrier reduce/sum
cnpetra Mar 16, 2025
df028e9
log bar weighting functionality in Iterate
cnpetra Mar 17, 2025
a44d355
fixing ci runtime errors
cnpetra Mar 17, 2025
82c02d6
cuda and raja impl; also added tests
cnpetra Mar 17, 2025
758ee13
fixed bug in test and syntax for thrust::transform
cnpetra Mar 17, 2025
ecb7554
fixed typo in Raja Vec Impl
cnpetra Mar 17, 2025
fc2b25d
fixing logBarWeighted in RAJA vector
cnpetra Mar 18, 2025
86c437e
stregthen test for logBarrierWeighted
cnpetra Mar 18, 2025
038229f
HIP implementation logBarrierWeight
cnpetra Mar 18, 2025
01495bf
draft of weighted B0 in the LowRank quasi Newton solves
cnpetra Mar 19, 2025
b283b07
fixed bug in new B0 code
cnpetra Mar 19, 2025
1d54e3f
duals lsq computation
cnpetra Mar 21, 2025
63d8f88
draft of Hessian approx - code works mesh independently
cnpetra Mar 21, 2025
3295382
added test for Ex1 with L2
cnpetra Mar 21, 2025
57a3067
M lumped applies in residuals
cnpetra Mar 23, 2025
8e71f46
SOC
cnpetra Mar 28, 2025
9f5b92a
fixed hardcoded SOC cond bypasses
cnpetra Mar 28, 2025
9663829
rename to VectorSpace
cnpetra Mar 30, 2025
018e956
finished renaming to VectorSpace
cnpetra Mar 31, 2025
7e20b4e
cleaning up VectorSpace
cnpetra Mar 31, 2025
5b75a70
added api for lumped weight; some methods renaming
cnpetra Apr 2, 2025
1bfc6a1
distinguish between lump and full weight cases
cnpetra Apr 2, 2025
d60b257
fixed return type
cnpetra Apr 2, 2025
a80ec21
misc devs
cnpetra Jul 14, 2025
10b023b
added dual regularization for quasi-Newton
cnpetra Jul 14, 2025
3a656de
fixed a bug - Nmat was not copied correctly
cnpetra Jul 16, 2025
c133980
Merge branch 'develop' into infdim-ipm-dev
cnpetra Jul 16, 2025
56afc29
output clean up; ramped up tol for singularity in KktLowRankLinsys
cnpetra Jul 16, 2025
b43e0b3
large bound duals warning is displayed only once
cnpetra Aug 26, 2025
db89c6b
updated user manual: derivative check and elastic-relaxfixed-perturbbnds
cnpetra Aug 26, 2025
fa89b53
updated user manual pdf
cnpetra Aug 26, 2025
a9cc882
addressing review comments
cnpetra Sep 3, 2025
7d2184a
finished reviewer comments
cnpetra Sep 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified doc/hiop_usermanual.pdf
Binary file not shown.
24 changes: 20 additions & 4 deletions doc/src/sections/solver_options.tex
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,14 @@ \subsubsection{Feasibility restoration}

\subsubsection{Elastic mode}

\noindent \textbf{elastic\_mode}: type of elastic mode used within \Hi:
\noindent \textbf{elastic\_mode}: this is an advanced option that is not supported by all solvers. It dynamically perturbs bounds and inequalities (similar to \textit{bound\_relax\_perturb}): the initial bound perturbation is controlled by \textit{elastic\_mode\_bound\_relax\_initial} and reduced throughout the optimization iterations to be \textit{elastic\_mode\_bound\_relax\_final} at the final solution. Possible values are
\begin{itemize}
\item ``none'' (default): does not apply elastic mode;
\item ``tighten\_bound '': tightens the bounds when $\mu$ changes.
\item ``correct\_it'': tightens the bounds, and corrects the slacks and slack duals when $\mu$ changes.
\item ``correct\_it\_adjust\_bound'': tightens the bounds, corrects the slacks and slack duals, and adjusts the bounds again from the modified iterate when $\mu$ changes.
\end{itemize}
Options \textit{fixed\_var\_perturb} and \textit{bound\_relax\_perturb} are ignored when this option set to a value other than ``none''.
\medskip

\noindent \textbf{elastic\_bound\_strategy}: Strategy used to tighen the bounds, when $\mu$ changes:
Expand Down Expand Up @@ -374,6 +375,7 @@ \subsubsection{Problem preprocessing}
\item ``relax'': relax the fixed variables accordingly to ``fixed\_var\_perturb'' option below;
\item ``'remove'': remove variables from the (internal) NLP formulation.
\end{itemize}
When treatment of fixed variables is relaxed, the relaxation is controlled by one of the options \textit{fixed\_var\_perturb}, \textit{bound\_relax\_perturb}, or \textit{elastic\_mode}.
\medskip

\noindent \textbf{fixed\_var\_tolerance}: a variable (say the $i$th) is considered fixed if
Expand All @@ -388,15 +390,15 @@ \subsubsection{Problem preprocessing}
(x_l)_i & = (x_l)_i - \max(|(x_u)_i|,1) \times \textnormal{fixed\_var\_perturb}, \\
(x_u)_i & = (x_u)_i + \max(|(x_u)_i|,1) \times \textnormal{fixed\_var\_perturb}.
\end{align*}
This option takes double values in $[10^{-14}, 0.1]$ and has a default value $10^{-8}$.
This option takes double values in $[10^{-14}, 0.1]$ and has a default value $10^{-8}$. This option is ignored when option \textit{bound\_relax\_perturb} has a nonzero value or option \textit{elastic\_mode} is not ``none''.
\medskip

\noindent \textbf{bound\_relax\_perturb}: perturbation of the lower and upper bounds for all variables and all constraints relative to their magnitude. A variable or constraint (say the $i$th) with lower and upper bounds $(x_l)_i$ and $(x_u)_i$, respectively, is ``relaxed'' accordingly to
\noindent \textbf{bound\_relax\_perturb}: perturbation of the lower and upper bounds for all variables and all inequality constraints relative to their magnitude. A variable or constraint (say the $i$th) with lower and upper bounds $(x_l)_i$ and $(x_u)_i$, respectively, is ``relaxed'' accordingly to
\begin{align*}
(x_l)_i & = (x_l)_i - \max(|(x_l)_i|,1) \times \textnormal{bound\_relax\_perturb}, \\
(x_u)_i & = (x_u)_i + \max(|(x_u)_i|,1) \times \textnormal{bound\_relax\_perturb}.
\end{align*}
This option takes double values in $[0, 10^{20}]$ and has a default value $10^{-8}$.
This option takes double values in $[0, 10^{20}]$ and has a default value $10^{-8}$. A nonzero value for this option will cause \textit{fixed\_var\_perturb} to be ignored and all fixed variables will be relaxed accordingly to the value of this option. This option is ignored when option \textit{elastic\_mode} is set to a value other than ``none''.
\medskip

%%%% scaling
Expand Down Expand Up @@ -449,6 +451,20 @@ \subsubsection{Miscellaneous options}
\noindent \textbf{time\_kkt}: string option with ``on'' or ``off'' values deciding whether \Hi turns on/off performance timers and reporting of the computational constituents of the KKT solve process. Default value: ``off''.
\medskip

\noindent \textbf{derivative\_check}: string option with ``no'' or ``first-order'' values that can be used to check user-provided derivatives using finite differences and to report comparison. Default value: ``no''. Remark that only first-order derivatives are supported (objective gradient and constraints Jacobian).
\medskip

\noindent \textbf{derivative\_check\_perturbation}: Numeric option (range $[10^{-20}, 10^{3}]$, default $10^{-8}$) that controls the finite difference perturbation of each variables, relative to variable's value.
\medskip

\noindent \textbf{derivative\_check\_tolerance}: Numeric option (range $[10^{-20}, 10^{3}]$, default $10^{-4}$) controlling tolerance for marking a mismatch between user-provided derivative and finite difference, relative to magnitude of derivative value provided by the user.
\medskip

\noindent \textbf{derivative\_check\_print\_all}: String option with values ``no'' (default) and ``yes'' indicating that whether to print the comparison of provided derivatives and finite difference approximation for mismatching or for all derivative entries only, respectively.


\medskip




Expand Down
1 change: 1 addition & 0 deletions src/Drivers/Dense/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ install(
##########################################################
add_test(NAME NlpDenseCons1_5H COMMAND ${RUNCMD} "$<TARGET_FILE:NlpDenseConsEx1.exe>" "500" "1.0" "-selfcheck")
add_test(NAME NlpDenseCons1_5K COMMAND ${RUNCMD} "$<TARGET_FILE:NlpDenseConsEx1.exe>" "5000" "1.0" "-selfcheck")
add_test(NAME NlpDenseCons1_25K_InfDim COMMAND ${RUNCMD} "$<TARGET_FILE:NlpDenseConsEx1.exe>" "25000" "1.0" "-selfcheck" "-use_L2")
add_test(NAME NlpDenseCons1_50K COMMAND ${RUNCMD} "$<TARGET_FILE:NlpDenseConsEx1.exe>" "50000" "1.0" "-selfcheck")
if(HIOP_USE_MPI)
add_test(NAME NlpDenseCons1_50K_mpi COMMAND ${MPICMD} -n 2 "$<TARGET_FILE:NlpDenseConsEx1.exe>" "50000" "1.0" "-selfcheck")
Expand Down
10 changes: 9 additions & 1 deletion src/Drivers/Dense/NlpDenseConsEx1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,15 @@ bool Ex1Meshing1D::get_vecdistrib_info(size_type global_n, index_type* cols)
for(int i = 0; i <= comm_size; i++) cols[i] = col_partition[i];
return true;
}
void Ex1Meshing1D::applyM(DiscretizedFunction& f) { f.componentMult(*this->_mass); }
void Ex1Meshing1D::applyM(DiscretizedFunction& f)
{
f.componentMult(*this->_mass);
}

void Ex1Meshing1D::applyMinv(DiscretizedFunction& f)
{
f.componentDiv(*this->_mass);
}

// converts the local indexes to global indexes
index_type Ex1Meshing1D::getGlobalIndex(index_type i_local) const
Expand Down
49 changes: 46 additions & 3 deletions src/Drivers/Dense/NlpDenseConsEx1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ class Ex1Meshing1D
index_type* get_col_partition() const { return col_partition; }
MPI_Comm get_comm() const { return comm; }

virtual void applyM(DiscretizedFunction& f);

void applyM(DiscretizedFunction& f);
void applyMinv(DiscretizedFunction& f);
protected:
hiop::hiopVector* _mass; // the length or the mass of the elements
double _a, _b; // end points
Expand Down Expand Up @@ -112,9 +112,10 @@ class DiscretizedFunction : public hiop::hiopVectorPar
class DenseConsEx1 : public hiop::hiopInterfaceDenseConstraints
{
public:
DenseConsEx1(int n_mesh_elem = 100, double mesh_ratio = 1.0)
DenseConsEx1(int n_mesh_elem, double mesh_ratio=1.0, int type_weighted_vars=0)
: n_vars(n_mesh_elem),
comm(MPI_COMM_WORLD),
type_weighted_space_((hiopInterfaceBase::WeightedSpaceType)type_weighted_vars),
solver_(nullptr)
{
// create the members
Expand Down Expand Up @@ -257,10 +258,52 @@ class DenseConsEx1 : public hiop::hiopInterfaceDenseConstraints
double alpha_du,
double alpha_pr,
int ls_trials);

bool apply_M(const size_type& n, const double* x_in, double* y_out)
{
x->copyFrom(x_in);
_mesh->applyM(*x);
x->copyTo(y_out);
return true;
}

/**
* Computes action y of the inner product weight matrix H on a vector x, namely y=H*x
*/
virtual bool apply_H(const size_type& n, const double* x_in, double* y_out)
{
x->copyFrom(x_in);
_mesh->applyM(*x);
x->copyTo(y_out);
return true;
}

/**
* Computes action y of the inverse of H on a vector x, namely y=H^{-1}*x
*/
virtual bool apply_Hinv(const size_type& n, const double* x_in, double* y_out)
{
x->copyFrom(x_in);
_mesh->applyMinv(*x);
x->copyTo(y_out);
return true;
}

/**
* Enables the use of weighted inner products via @apply_M, @apply_H, and @apply_Hinv
*/
virtual hiopInterfaceBase::WeightedSpaceType get_weighted_space_type()
{
// return
// - hiopInterfaceBase::Euclidean for no weighted space
// - hiopInterfaceBase::HilbertLumped for space weighted by lumped mass matrix
return type_weighted_space_;
}

private:
int n_vars;
MPI_Comm comm;
hiopInterfaceBase::WeightedSpaceType type_weighted_space_;
Ex1Meshing1D* _mesh;

int n_local;
Expand Down
27 changes: 20 additions & 7 deletions src/Drivers/Dense/NlpDenseConsEx1Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,26 @@ static bool self_check(size_type n, double obj_value);
#ifdef HIOP_USE_AXOM
static bool do_load_checkpoint_test(const size_type& mesh_size, const double& ratio, const double& obj_val_expected);
#endif
static bool parse_arguments(int argc, char** argv, size_type& n, double& distortion_ratio, bool& self_check)
static bool parse_arguments(int argc, char** argv, size_type& n, double& distortion_ratio, bool& wei_vars, bool& self_check)
{
n = 20000;
distortion_ratio = 1.;
wei_vars = false;
self_check = false; // default options

switch(argc) {
case 1:
// no arguments
return true;
break;
case 5: // 4 arguments - -use_L2 expected
{
if(std::string(argv[4]) == "-use_L2") {
wei_vars = true;
} else {
return false;
}
}
case 4: // 3 arguments - -selfcheck expected
{
if(std::string(argv[3]) == "-selfcheck") {
Expand Down Expand Up @@ -91,15 +100,17 @@ int main(int argc, char** argv)
}
#endif
bool selfCheck;
//flags the use of Ex1 with the mass weighted variables (L2 inner product) or without (Euclidean inner product)
bool wei_vars;
size_type mesh_size;
double ratio;
double objective = 0.;
if(!parse_arguments(argc, argv, mesh_size, ratio, selfCheck)) {
if(!parse_arguments(argc, argv, mesh_size, ratio, wei_vars, selfCheck)) {
usage(argv[0]);
return 1;
}

DenseConsEx1 problem(mesh_size, ratio);
DenseConsEx1 problem(mesh_size, ratio, wei_vars);
hiop::hiopNlpDenseConstraints nlp(problem);

hiop::hiopAlgFilterIPM solver(&nlp);
Expand All @@ -110,7 +121,9 @@ int main(int argc, char** argv)

// this is used for testing when the driver is called with -selfcheck
if(selfCheck) {
if(!self_check(mesh_size, objective)) return -1;
if(!self_check(mesh_size, objective)) {
return -1;
}
} else {
if(rank == 0) {
printf("Optimal objective: %22.14e. Solver status: %d. Number of iterations: %d\n",
Expand Down Expand Up @@ -142,9 +155,9 @@ int main(int argc, char** argv)

static bool self_check(size_type n, double objval)
{
#define num_n_saved 3 // keep this is sync with n_saved and objval_saved
const size_type n_saved[] = {500, 5000, 50000};
const double objval_saved[] = {8.6156700e-2, 8.6156106e-02, 8.6161001e-02};
#define num_n_saved 4 // keep this is sync with n_saved and objval_saved
const size_type n_saved[] = {500, 5000, 50000, 25000};
const double objval_saved[] = {8.6156700e-2, 8.6156106e-02, 8.6161001e-02, 8.6155777e-02};

#define relerr 1e-6
bool found = false;
Expand Down
113 changes: 112 additions & 1 deletion src/Interface/hiopInterface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@

namespace hiop
{
/** Solver status codes. */
// Solver status codes
enum hiopSolveStatus
{
//(partial) success
Expand Down Expand Up @@ -142,6 +142,24 @@ class hiopInterfaceBase
hiopQuadratic,
hiopNonlinear
};
/**
* Type of weighting to be used internally for computing norm and inner products, for determining
* representations of dual bound variables, and initial quasi-Newton Hessian approximations.
*/
enum WeightedSpaceType
Comment thread
cnpetra marked this conversation as resolved.
{
// no weighted space.
Euclidean = 0,

// lumps mass matrix and uses lumped matrix everywhere
HilbertLumped,

/**
* Experimental: lumps mass matrix and uses for dual bound representers and initial Hessian
* approximations, however, uses H and H-inverse norms in termination criteria
*/
Hilbert
};

public:
hiopInterfaceBase() {};
Expand Down Expand Up @@ -282,6 +300,99 @@ class hiopInterfaceBase
return false; // defaults to serial
}

/**
* Computes action y of the mass matrix on a vector x, namely y=M*x
*
* The mass matrix is generally the weight matrix associated with L^2 finite element
* discretizations. This matrix is used internally to build and maintain Riesz-like
* representations of the dual variables (associated with bound constraints) to ensure
* mesh independent performance of the algorithm. Currently M is lumped into a diagonal
* and used internally for the abovementioned dual variables.
*
* @note If the variables are not coming from discretizations (specified by
* a hiopInterfaceBase::Euclidean return value from @get_weighted_space_type), the method is
* not called and HiOp will use internally M=I. Otherwise, should true or false depending
* on whether the user code succesfully applied M.
*
* @param[in] n the (global) number of variables
* @param[in] x the array to which mass action is applied
* @param[out] y the result of apply
* @return see note above.
*/
virtual bool apply_M(const size_type& n, const double* x, double* y)
{
return true;
}

/**
* Computes action y of the inner product weight matrix H on a vector x, namely y=H*x
*
* The weight matrix H is generally associated with L^2 or H^1 finite element
* discretizations and corresponding weighted inner products: <u_h,v_h> = u^T H v. For L^2,
* H is the mass matrix, while for H^1 is the mass plus stiffness. This matrix is applied
* internally to obtain termination criteria and derive Hessian representations that are
* mesh independent and consistent with the function space nature of the problem.
*
* Additional info: C. G. Petra et. al., On the implementation of a quasi-Newton
* interior-point method for PDE-constrained optimization using finite element
* discretizations, Optimiz. Meth. and Software, Vol. 38, 2023.
*
* @note The method is called only when hiopInterfaceBase::Hilbert is returned by
* @get_weighted_space_type. In this case, it should return true or false depending on
* whether the user code succesfully applied H.
*
* @note Currently HiOp only uses H for computing the inner products and norms (including
* for vector representations of duals discretizations). The lumped mass matrix M is used
* in the quasi-Newton Hessian approximations. This can be revisited, but will require
* the user to provide a method for solve with H plus a diagonal positive definite matrix.
*
* @param[in] n the (global) number of variables
* @param[in] x the array to which the H matrix is applied
* @param[out] y the result of apply
* @return see note above
*/
virtual bool apply_H(const size_type& n, const double* x, double* y)
{
return true;
}

/**
* Computes action y of the inverse of H on a vector x, namely y=H^{-1}*x
*
* See @apply_H for a discussion of H and additional notes. The inverse of H plays an
* important role in computing the "dual" norms and, in turn, to ensure mesh
* independent behavior of the IPM solver(s). Also see notes from @apply_H.
*
* @param[in] n the (global) number of variables
* @param[in] x the array to which the inverse is applied
* @param[out] y the result of apply
* @return see return of @apply_H
*/
virtual bool apply_Hinv(const size_type& n, const double* x, double* y)
{
return true;
}

/**
* Enables the use of weighted inner products via @apply_M, @apply_H, and @apply_Hinv
*
* See @WeightedSpaceType for the return values of this function and their meaning. If the
* return value is
* - hiopInterfaceBase::Euclidean: @apply_M, @apply_H, and @apply_Hinv need not be overriden by user.
* If provided, they are not called.
* - hiopInterfaceBase::HilbertLumped: only @apply_M is called. @apply_H and @apply_Hinv are not.
* - hiopInterfaceBase::Hilbert: @apply_M, @apply_H, and @apply_Hinv are called.
*
* See also notes for @apply_M, @apply_H, and @apply_Hinv.
*
* @return WeightedSpaceType (see @WeightedSpaceType and notes above
*/
virtual WeightedSpaceType get_weighted_space_type()
{
//the default impl. instructs HiOp to use Euclidean/l^2 variables (H=I) internally
return Euclidean;
}

/**
* Method provides a primal or starting point. This point is subject to internal adjustments.
*
Expand Down
Loading
Loading