75 "Expecting equal numbers of equality and inequality constraints");
138 Mult(x0block, xfblock);
157 for (
int i = 0; i <
dimM; i++)
162 Xk.GetBlock(0).Set(1.0, xk.GetBlock(0));
163 Xk.GetBlock(1).Set(1.0, xk.GetBlock(1));
164 Xk.GetBlock(2).Set(1.0,
lk);
165 Xk.GetBlock(3).Set(1.0,
zlk);
179 real_t theta0 = GetTheta(xk);
180 thetaMin = 1.e-4 * std::max(1.0, theta0);
183 real_t OptErrSubproblem, OptErr;
185 int maxBarrierSolves = 10;
190 mfem::out <<
"\n" << std::string(50,
'-') << std::endl;
191 mfem::out <<
"interior-point solve step # " << j << std::endl;
194 OptErr = OptimalityError(xk,
lk,
zlk);
200 mfem::out <<
"solved optimization problem\n";
205 if (j > 0) { maxBarrierSolves = 1; }
206 for (
int i = 0; i < maxBarrierSolves; i++)
209 OptErrSubproblem = OptimalityError(xk,
lk,
zlk,
mu_k);
214 mfem::out <<
"solved mu = " <<
mu_k <<
" barrier subproblem\n";
216 UpdateBarrierSubProblem();
226 zlhat = 0.0; Xhatuml = 0.0;
228 bool passedCurvatureTest =
false;
229 IPNewtonSolve(xk,
lk,
zlk, zlhat, Xhatuml, passedCurvatureTest,
mu_k);
230 if (!passedCurvatureTest)
237 int maxCurvatureTests = 30;
250 zlhat = 0.0; Xhatuml = 0.0;
251 IPNewtonSolve(xk,
lk,
zlk, zlhat, Xhatuml, passedCurvatureTest,
mu_k, deltaReg);
253 for (
int numCurvatureTests = 0; numCurvatureTests < maxCurvatureTests;
258 mfem::out <<
"deltaReg = " << deltaReg << std::endl;
260 if (passedCurvatureTest)
281 zlhat = 0.0; Xhatuml = 0.0;
282 IPNewtonSolve(xk,
lk,
zlk, zlhat, Xhatuml, passedCurvatureTest,
mu_k, deltaReg);
287 Xk.GetBlock(0).Set(1.0, xk.GetBlock(0));
288 Xk.GetBlock(1).Set(1.0, xk.GetBlock(1));
289 Xk.GetBlock(2).Set(1.0,
lk);
290 Xk.GetBlock(3).Set(1.0,
zlk);
293 for (
int i = 0; i < 3; i++)
303 LineSearch(Xk, Xhat,
mu_k);
327 mfem::out <<
"lineSearch not successful\n";
334 mfem::out <<
"maximum optimization iterations\n";
355 for (
int i = 0; i <
dimM; i++)
363 SparseMatrix * Ds =
new SparseMatrix(DiagLogBar);
364 HypreParMatrix * D =
new HypreParMatrix(
comm,
373 SparseMatrix * Ds =
new SparseMatrix(DiagLogBar);
380 Vector deltaDiagVec(
dimU);
381 deltaDiagVec =
delta;
387 SparseMatrix * Duus =
new SparseMatrix(deltaDiagVec);
397 SparseMatrix * DuuS =
new SparseMatrix(deltaDiagVec);
419void IPSolver::IPNewtonSolve(BlockVector &x, Vector &l,
420 Vector &zl, Vector &zlhat, BlockVector &Xhat,
bool & passedCurvatureTest,
428 FormIPNewtonMat(x, l, zl, A,
delta);
434 GetDxphi(x,
mu, gradphi);
436 for (
int i = 0; i < 2; i++)
438 b.GetBlock(i).Set(1.0, gradphi.GetBlock(i));
439 A.GetBlock(i, 2).AddMult(l,
b.GetBlock(i));
446 HypreParMatrix *JuTDJu =
RAP(
Wmm,
Ju);
447 HypreParMatrix *Areduced =
ParAdd(
Huu, JuTDJu);
451 Vector breduced(
dimU); breduced = 0.0;
452 Vector tempVec(
dimM); tempVec = 0.0;
454 tempVec.Add(1.0,
b.GetBlock(1));
456 breduced.Add(1.0,
b.GetBlock(0));
461 auto itsolver =
dynamic_cast<IterativeSolver *
>(
solver);
462 int numit = (itsolver) ? itsolver->GetNumIterations() : -1;
467 Ju->
Mult(Xhat.GetBlock(0), Xhat.GetBlock(1));
468 Xhat.GetBlock(1).Add(-1.0,
b.GetBlock(2));
471 Wmm->
Mult(Xhat.GetBlock(1), Xhat.GetBlock(2));
472 Xhat.GetBlock(2).Add(-1.0,
b.GetBlock(1));
477 passedCurvatureTest = CurvatureTest(A, Xhat, l,
b,
delta);
480 for (
int i = 0; i <
dimM; i++)
482 zlhat(i) = zl(i) + (zl(i) * Xhat(i +
dimU) -
mu) / x(i +
dimU);
487real_t IPSolver::GetMaxStepSize(Vector &x, Vector &xhat,
492 for (
int i = 0; i < x.Size(); i++)
496 alphaTmp = -1. * tau * x(i) / xhat(i);
497 alphaMaxloc = std::min(alphaMaxloc, alphaTmp);
502 MPI_Allreduce(&alphaMaxloc, &alphaMaxglb, 1, MPITypeMap<real_t>::mpi_type,
510void IPSolver::LineSearch(BlockVector& X0, BlockVector& Xhat,
515 Vector u0 = X0.GetBlock(0);
516 Vector m0 = X0.GetBlock(1);
517 Vector l0 = X0.GetBlock(2);
518 Vector z0 = X0.GetBlock(3);
519 Vector uhat = Xhat.GetBlock(0);
520 Vector mhat = Xhat.GetBlock(1);
521 Vector lhat = Xhat.GetBlock(2);
522 Vector zhat = Xhat.GetBlock(3);
523 real_t alphaMax = GetMaxStepSize(m0, mhat, tau);
524 real_t alphaMaxz = GetMaxStepSize(z0, zhat, tau);
528 x0.GetBlock(0).Set(1.0, u0);
529 x0.GetBlock(1).Set(1.0, m0);
532 xhat.GetBlock(0).Set(1.0, uhat);
533 xhat.GetBlock(1).Set(1.0, mhat);
537 int maxBacktrack = 20;
540 GetDxphi(x0,
mu, Dxphi0);
543 bool descentDirection = (Dxphi0_xhat < 0.);
549 if (!descentDirection)
553 mfem::out <<
" a descent direction for the log-barrier objective\n";
560 for (
int i = 0; i < maxBacktrack; i++)
568 xtrial.Add(
alpha, xhat);
570 real_t thxtrial = GetTheta(xtrial);
571 real_t phxtrial = GetPhi(xtrial,
mu, eval_err);
576 mfem::out <<
"bad log-barrier objective eval, reducing step length\n";
582 auto inFilterRegion = FilterCheck(thxtrial, phxtrial);
589 if (!descentDirection)
603 mfem::out <<
"theta(xtrial) = " << thxtrial <<
", (1-gTheta) *theta(x0) = "
606 mfem::out <<
"phi(xtrial) = " << phxtrial <<
", phi(x0) - gPhi *theta(x0) = "
619 "Line search successful: sufficient decrease in log-barrier objective.\n";
633 "Line search successful: infeasibility or log-barrier objective decreased.\n";
654 bool inFilterRegion =
false;
657 inFilterRegion =
true;
661 for (
int i = 0; i <
F1.
Size(); i++)
663 if (thetax >=
F1[i] && phix >=
F2[i])
665 inFilterRegion =
true;
670 return inFilterRegion;
673void IPSolver::ProjectZ(
const Vector &x, Vector &z,
real_t mu)
677 for (
int i = 0; i <
dimM; i++)
680 zprimal_i =
mu / x(i +
dimU);
681 z(i) = std::max(std::min(zdual_i,
kSig * zprimal_i), zprimal_i /
kSig);
685real_t IPSolver::GetTheta(
const BlockVector &x)
700 real_t logBarrierLoc = 0.0;
701 for (
int i = 0; i <
dimM; i++)
706 MPI_Allreduce(&logBarrierLoc, &logBarrierGlb, 1, MPITypeMap<real_t>::mpi_type,
708 return fx -
mu * logBarrierGlb;
712void IPSolver::GetDxphi(
const BlockVector &x,
real_t mu,
716 Vector ytemp(
dimM); ytemp = 1.0;
717 ytemp /= x.GetBlock(1);
719 y.GetBlock(1).
Add(-
mu, ytemp);
724real_t IPSolver::EvalLangrangian(
const BlockVector &x,
const Vector &l,
730 Vector temp(
dimM); temp = 0.0;
731 temp.Set(1.0, x.GetBlock(1));
739void IPSolver::EvalLagrangianGradient(
const BlockVector &x,
const Vector &l,
740 const Vector &zl, BlockVector &y)
743 y.GetBlock(1).
Set(-1.0, zl);
744 y.GetBlock(1) *=
Mlump;
760bool IPSolver::CurvatureTest(
const BlockOperator & A,
761 const BlockVector & Xhat,
const Vector & l,
const BlockVector &
b,
764 Vector lplus(l.Size());
766 lplus.Add(1.0, Xhat.GetBlock(2));
771 for (
int i = 0; i < 2; i++)
773 for (
int j = 0; j < 2; j++)
775 if (!A.IsZeroBlock(i, j))
777 Vector temp(A.GetBlock(i, j).Height()); temp = 0.0;
778 A.GetBlock(i, j).Mult(Xhat.GetBlock(j), temp);
786 bool passed = (dWd + fmax(-lplusTck,
792real_t IPSolver::OptimalityError(
const BlockVector &x,
const Vector &l,
796 real_t stationarityError, feasibilityError, complementarityError;
802 EvalLagrangianGradient(x, l, zl, gradL);
805 Vector cx(
dimC); cx = 0.0;
810 Vector comp(
dimM); comp = 0.0;
811 for (
int i = 0; i <
dimM; i++)
817 MxinvgradL.Set(1.0, gradL);
818 MxinvgradL.GetBlock(0) /=
Mvlump;
819 MxinvgradL.GetBlock(1) /=
Mlump;
825 optimalityError = std::max(std::max(stationarityError, feasibilityError),
826 complementarityError);
830 mfem::out <<
"evaluating optimality error for mu = " <<
mu << std::endl;
831 mfem::out <<
"stationarity error = " << stationarityError << std::endl;
832 mfem::out <<
"feasibility error = " << feasibilityError << std::endl;
833 mfem::out <<
"complimentarity error = " << complementarityError << std::endl;
834 mfem::out <<
"optimality error = " << optimalityError << std::endl;
836 return optimalityError;
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
void PartialSum()
Fill the entries of the array with the cumulative sum of the entries.
int Append(const T &el)
Append element 'el' to array, resize if necessary.
A class to handle Block systems in a matrix-free implementation.
void SetBlock(int iRow, int iCol, Operator *op, real_t c=1.0)
Add a block op in the block-entry (iblock, jblock).
A class to handle Vectors in a block fashion.
Vector & GetBlock(int i)
Get the i-th vector in the block.
HYPRE_Int MultTranspose(HypreParVector &x, HypreParVector &y, real_t alpha=1.0, real_t beta=0.0) const
Computes y = alpha * A^t * x + beta * y.
HYPRE_Int Mult(HypreParVector &x, HypreParVector &y, real_t alpha=1.0, real_t beta=0.0) const
Computes y = alpha * A * x + beta * y.
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
Operator transpose application: y+=A^t(x) (default) or y+=a*A^t(x).
HypreParMatrix * Transpose() const
Returns the transpose of *this.
int print_level
print level, 0: no printing, > 0 various solver progress output is shown
OptContactProblem * problem
OptContactProblem (not owned).
Array< int > lin_solver_iterations
real_t kRegMinus
inertia-regularization rate parameters
real_t alphaCurvatureTest
inertia-regularization parameters
Vector Mcslump
Lumped masses.
IPSolver(OptContactProblem *)
Construct interior-point solver.
Array< int > constraint_offsets
Array< int > block_offsetsx
void Mult(const Vector &, Vector &)
Apply the interior-point solver.
Array< int > block_offsetsumlz
HypreParMatrix * Huu
Operators (not owned)
Array< int > block_offsetsuml
real_t kSig
interior-point algorithm parameters
Solver * solver
Linear solver (not owned)
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
virtual void SetOperator(const Operator &op)=0
Set/update the solver for the given operator.
Vector & Set(const real_t a, const Vector &x)
(*this) = a * x
void SetSize(int s)
Resize the vector to size s.
Vector & Add(const real_t a, const Vector &Va)
(*this) += a * Va
MFEM_HOST_DEVICE dual< value_type, gradient_type > log(dual< value_type, gradient_type > a)
implementation of the natural logarithm function for dual numbers
MFEM_HOST_DEVICE dual< value_type, gradient_type > sqrt(dual< value_type, gradient_type > x)
implementation of square root for dual numbers
MFEM_HOST_DEVICE dual< value_type, gradient_type > pow(dual< value_type, gradient_type > a, dual< value_type, gradient_type > b)
implementation of a (dual) raised to the b (dual) power
real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
real_t GlobalLpNorm(const real_t p, real_t loc_norm, MPI_Comm comm)
Compute a global Lp norm from the local Lp norms computed by each processor.
real_t InnerProduct(HypreParVector *x, HypreParVector *y)
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)
HypreParMatrix * ParAdd(const HypreParMatrix *A, const HypreParMatrix *B)
Returns the matrix A + B.
void HypreStealOwnership(HypreParMatrix &A_hyp, SparseMatrix &A_diag)
Make A_hyp steal ownership of its diagonal part A_diag.
MFEM_HOST_DEVICE real_t abs(const Complex &z)