#include "IpoptConfig.h"
#include "IpWsmpSolverInterface.hpp"
#include <cmath>
#include <cstdio>
extern "C"
{
void IPOPT_WSMP_FUNC(wsetmaxthrds, WSETMAXTHRDS)(
const ipindex* NTHREADS
);
void IPOPT_WSMP_FUNC(wssmp, WSSMP)(
const ipindex* N,
const ipindex* IA,
const ipindex* JA,
const double* AVALS,
double* DIAG,
ipindex* PERM,
ipindex* INVP,
double* B,
const ipindex* LDB,
const ipindex* NRHS,
double* AUX,
const ipindex* NAUX,
ipindex* MRP,
ipindex* IPARM,
double* DPARM
);
void IPOPT_WSMP_FUNC_(wsmp_clear, WSMP_CLEAR)(void);
void IPOPT_WSMP_FUNC_(wsmp_version, WSMP_VERSION)(
int* V,
int* R,
int* M
);
}
namespace Ipopt
{
#if IPOPT_VERBOSITY > 0
static const Index dbg_verbosity = 3;
#endif
WsmpSolverInterface::WsmpSolverInterface(
#ifdef PARDISO_MATCHING_PREPROCESS
SmartPtr<LibraryLoader> pardisoloader_
#endif
) : a_(NULL),
#ifdef PARDISO_MATCHING_PREPROCESS
ia2(NULL),
ja2(NULL),
a2_(NULL),
perm2(NULL),
scale2(NULL),
pardisoloader(pardisoloader_),
smat_reordering_pardiso_wsmp(NULL),
#endif
negevals_(-1),
initialized_(false),
PERM_(NULL),
INVP_(NULL),
MRP_(NULL)
{
DBG_START_METH("WsmpSolverInterface::WsmpSolverInterface()", dbg_verbosity);
IPARM_ = new Index[64];
DPARM_ = new double[64];
}
WsmpSolverInterface::~WsmpSolverInterface()
{
DBG_START_METH("WsmpSolverInterface::~WsmpSolverInterface()",
dbg_verbosity);
IPOPT_WSMP_FUNC_(wsmp_clear, WSMP_CLEAR)();
#ifdef PARDISO_MATCHING_PREPROCESS
delete[] ia2;
delete[] ja2;
delete[] a2_;
delete[] perm2;
delete[] scale2;
#endif
delete[] PERM_;
delete[] INVP_;
delete[] MRP_;
delete[] IPARM_;
delete[] DPARM_;
delete[] a_;
}
void WsmpSolverInterface::RegisterOptions(
SmartPtr<RegisteredOptions> roptions
)
{
roptions->AddIntegerOption(
"wsmp_num_threads",
"Number of threads to be used in WSMP",
1);
roptions->AddBoundedIntegerOption(
"wsmp_ordering_option",
"Determines how ordering is done in WSMP",
-2, 3,
1,
"This corresponds to the value of WSSMP's IPARM(16).");
roptions->AddBoundedIntegerOption(
"wsmp_ordering_option2",
"Determines how ordering is done in WSMP",
0, 3,
1,
"This corresponds to the value of WSSMP's IPARM(20).",
true);
roptions->AddBoundedNumberOption(
"wsmp_pivtol",
"Pivot tolerance for the linear solver WSMP.",
0.0, true,
1.0, true,
1e-4,
"A smaller number pivots for sparsity, a larger number pivots for stability.");
roptions->AddBoundedNumberOption(
"wsmp_pivtolmax",
"Maximum pivot tolerance for the linear solver WSMP.",
0.0, true,
1.0, true,
1e-1,
"Ipopt may increase pivtol as high as pivtolmax to get a more accurate solution to the linear system.");
roptions->AddBoundedIntegerOption(
"wsmp_scaling",
"Determines how the matrix is scaled by WSMP.",
0, 3,
0,
"This corresponds to the value of WSSMP's IPARM(10).");
roptions->AddBoundedNumberOption(
"wsmp_singularity_threshold",
"WSMP's singularity threshold.",
0.0, true,
1.0, true,
1e-18,
"WSMP's DPARM(10) parameter. "
"The smaller this value the less likely a matrix is declared singular.");
roptions->AddLowerBoundedIntegerOption(
"wsmp_write_matrix_iteration",
"Iteration in which the matrices are written to files.",
-1,
-1,
"If non-negative, this option determines the iteration in which all matrices given to WSMP are written to files.",
true);
roptions->AddBoolOption(
"wsmp_skip_inertia_check",
"Whether to always pretend that inertia is correct.",
false,
"Setting this option to \"yes\" essentially disables inertia check. "
"This option makes the algorithm non-robust and easily fail, but it might give some insight into the necessity of inertia control.",
true);
roptions->AddStringOption2(
"wsmp_no_pivoting",
"Whether to use the static pivoting option of WSMP.",
"no",
"no", "use the regular version",
"yes", "use static pivoting",
"Setting this option to \"yes\" means that WSMP is instructed not to do pivoting. "
"This works only in certain situations (when the Hessian block is known to be positive definite or when we are using L-BFGS). "
"It can also lead to a lot of fill-in.",
true);
}
void WsmpSolverInterface::GetVersion(
int& V,
int& R,
int& M
)
{
IPOPT_WSMP_FUNC_(wsmp_version, WSMP_VERSION)(&V, &R, &M);
}
bool WsmpSolverInterface::InitializeImpl(
const OptionsList& options,
const std::string& prefix
)
{
#ifdef PARDISO_MATCHING_PREPROCESS
DBG_ASSERT(IsValid(pardisoloader));
smat_reordering_pardiso_wsmp = (IPOPT_DECL_SMAT_REORDERING_PARDISO_WSMP(*))pardisoloader->loadSymbol("smat_reordering_pardiso_wsmp");
DBG_ASSERT(smat_reordering_pardiso_wsmp);
#endif
options.GetIntegerValue("wsmp_num_threads", wsmp_num_threads_, prefix);
Index wsmp_ordering_option;
options.GetIntegerValue("wsmp_ordering_option", wsmp_ordering_option, prefix);
Index wsmp_ordering_option2;
options.GetIntegerValue("wsmp_ordering_option2", wsmp_ordering_option2, prefix);
options.GetNumericValue("wsmp_pivtol", wsmp_pivtol_, prefix);
if( options.GetNumericValue("wsmp_pivtolmax", wsmp_pivtolmax_, prefix) )
{
ASSERT_EXCEPTION(wsmp_pivtolmax_ >= wsmp_pivtol_, OPTION_INVALID,
"Option \"wsmp_pivtolmax\": This value must be between "
"wsmp_pivtol and 1.");
}
else
{
wsmp_pivtolmax_ = Max(wsmp_pivtolmax_, wsmp_pivtol_);
}
options.GetNumericValue("wsmp_singularity_threshold", wsmp_singularity_threshold_, prefix);
options.GetIntegerValue("wsmp_scaling", wsmp_scaling_, prefix);
options.GetIntegerValue("wsmp_write_matrix_iteration", wsmp_write_matrix_iteration_, prefix);
options.GetBoolValue("wsmp_skip_inertia_check", skip_inertia_check_, prefix);
options.GetBoolValue("wsmp_no_pivoting", wsmp_no_pivoting_, prefix);
dim_ = 0;
initialized_ = false;
printed_num_threads_ = false;
pivtol_changed_ = false;
have_symbolic_factorization_ = false;
factorizations_since_recomputed_ordering_ = -1;
delete[] a_;
a_ = NULL;
delete[] PERM_;
PERM_ = NULL;
delete[] INVP_;
INVP_ = NULL;
delete[] MRP_;
MRP_ = NULL;
#ifdef PARDISO_MATCHING_PREPROCESS
delete[] ia2;
ia2 = NULL;
delete[] ja2;
ja2 = NULL;
delete[] a2_;
a2_ = NULL;
delete[] perm2;
perm2 = NULL;
delete[] scale2;
scale2 = NULL;
#endif
Index NTHREADS = wsmp_num_threads_;
IPOPT_WSMP_FUNC(wsetmaxthrds, WSETMAXTHRDS)(&NTHREADS);
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"WSMP will use %" IPOPT_INDEX_FORMAT " threads.\n", wsmp_num_threads_);
IPARM_[0] = 0;
IPARM_[1] = 0;
IPARM_[2] = 0;
Index idmy = 0;
double ddmy = 0.;
IPOPT_WSMP_FUNC(wssmp, WSSMP)(&idmy, &idmy, &idmy, &ddmy, &ddmy, &idmy, &idmy, &ddmy, &idmy, &idmy, &ddmy, &idmy, &idmy,
IPARM_, DPARM_);
if( IPARM_[63] < 0 )
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA, "Error %" IPOPT_INDEX_FORMAT " from WSMP initialization.\n", IPARM_[63]);
return false;
}
IPARM_[15] = wsmp_ordering_option; IPARM_[17] = 0; IPARM_[19] = wsmp_ordering_option2; if( wsmp_no_pivoting_ )
{
IPARM_[30] = 1; IPARM_[26] = 1;
}
else
{
IPARM_[30] = 2; }
IPARM_[10] = 2;
IPARM_[9] = wsmp_scaling_;
DPARM_[9] = wsmp_singularity_threshold_;
matrix_file_number_ = 0;
return true;
}
ESymSolverStatus WsmpSolverInterface::MultiSolve(
bool new_matrix,
const Index* ia,
const Index* ja,
Index nrhs,
double* rhs_vals,
bool check_NegEVals,
Index numberOfNegEVals
)
{
DBG_START_METH("WsmpSolverInterface::MultiSolve", dbg_verbosity);
DBG_ASSERT(!check_NegEVals || ProvidesInertia());
DBG_ASSERT(initialized_);
if( !printed_num_threads_ )
{
Jnlst().Printf(J_ITERSUMMARY, J_LINEAR_ALGEBRA,
" -- WSMP is working with %" IPOPT_INDEX_FORMAT " thread%s.\n", IPARM_[32], IPARM_[32] == 1 ? "" : "s");
printed_num_threads_ = true;
}
if( new_matrix || pivtol_changed_ )
{
pivtol_changed_ = false;
ESymSolverStatus retval;
retval = Factorization(ia, ja, check_NegEVals, numberOfNegEVals);
if( retval != SYMSOLVER_SUCCESS )
{
DBG_PRINT((1, "FACTORIZATION FAILED!\n"));
return retval; }
}
return Solve(ia, ja, nrhs, rhs_vals);
}
double* WsmpSolverInterface::GetValuesArrayPtr()
{
DBG_ASSERT(initialized_);
DBG_ASSERT(a_);
return a_;
}
ESymSolverStatus WsmpSolverInterface::InitializeStructure(
Index dim,
Index nonzeros,
const Index* ia,
const Index* ja
)
{
DBG_START_METH("WsmpSolverInterface::InitializeStructure", dbg_verbosity);
dim_ = dim;
nonzeros_ = nonzeros;
delete[] a_;
a_ = NULL;
a_ = new double[nonzeros];
ESymSolverStatus retval = SymbolicFactorization(ia, ja);
if( retval != SYMSOLVER_SUCCESS )
{
return retval;
}
initialized_ = true;
return retval;
}
ESymSolverStatus WsmpSolverInterface::SymbolicFactorization(
const Index* ,
const Index*
)
{
DBG_START_METH("WsmpSolverInterface::SymbolicFactorization",
dbg_verbosity);
return SYMSOLVER_SUCCESS;
}
ESymSolverStatus WsmpSolverInterface::InternalSymFact(
const Index* ia,
const Index* ja,
Index numberOfNegEVals
)
{
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemSymbolicFactorization().Start();
}
delete[] PERM_;
PERM_ = NULL;
delete[] INVP_;
INVP_ = NULL;
delete[] MRP_;
MRP_ = NULL;
PERM_ = new Index[dim_];
INVP_ = new Index[dim_];
MRP_ = new Index[dim_];
Index N = dim_;
#ifdef PARDISO_MATCHING_PREPROCESS
delete[] ia2;
ia2 = NULL;
delete[] ja2;
ja2 = NULL;
delete[] a2_;
a2_ = NULL;
delete[] perm2;
perm2 = NULL;
delete[] scale2;
scale2 = NULL;
ia2 = new Index[N + 1];
ja2 = new Index[nonzeros_];
a2_ = new double[nonzeros_];
perm2 = new Index[N];
scale2 = new double[N];
Index* tmp2_ = new Index[N];
smat_reordering_pardiso_wsmp(&N, ia, ja, a_, ia2, ja2, a2_, perm2, scale2, tmp2_, 0);
delete[] tmp2_;
#endif
Index NAUX = 0;
IPARM_[1] = 1; IPARM_[2] = 2; #ifdef PARDISO_MATCHING_PREPROCESS
IPARM_[9] = 2; IPARM_[15] = -1; IPARM_[30] = 6; DPARM_[21] = 2e-8;#endif
Index idmy = 0;
double ddmy = 0.;
if( wsmp_no_pivoting_ )
{
IPARM_[14] = dim_ - numberOfNegEVals; Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA,
"Restricting WSMP static pivot sequence with IPARM(15) = %" IPOPT_INDEX_FORMAT "\n", IPARM_[14]);
}
Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA,
"Calling WSSMP-1-2 for ordering and symbolic factorization.\n");
#ifdef PARDISO_MATCHING_PREPROCESS
IPOPT_WSMP_FUNC(wssmp, WSSMP)(&N, ia2, ja2, a2_, &ddmy, PERM_, INVP_,
#else
IPOPT_WSMP_FUNC(wssmp, WSSMP)(&N, ia, ja, a_, &ddmy, PERM_, INVP_,
#endif
&ddmy, &idmy, &idmy, &ddmy, &NAUX, MRP_, IPARM_, DPARM_);
Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA,
"Done with WSSMP-1-2 for ordering and symbolic factorization.\n");
Index ierror = IPARM_[63];
if( ierror != 0 )
{
if( ierror == -102 )
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA,
"Error: WSMP is not able to allocate sufficient amount of memory during ordering/symbolic factorization.\n");
}
else if( ierror > 0 )
{
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Matrix appears to be singular (with ierror = %" IPOPT_INDEX_FORMAT ").\n", ierror);
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemSymbolicFactorization().End();
}
return SYMSOLVER_SINGULAR;
}
else
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA,
"Error in WSMP during ordering/symbolic factorization phase.\n Error code is %" IPOPT_INDEX_FORMAT ".\n", ierror);
}
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemSymbolicFactorization().End();
}
return SYMSOLVER_FATAL_ERROR;
}
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Predicted memory usage for WSSMP after symbolic factorization IPARM(23)= %" IPOPT_INDEX_FORMAT ".\n", IPARM_[22]);
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Predicted number of nonzeros in factor for WSSMP after symbolic factorization IPARM(23)= %" IPOPT_INDEX_FORMAT ".\n", IPARM_[23]);
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemSymbolicFactorization().End();
}
return SYMSOLVER_SUCCESS;
}
ESymSolverStatus WsmpSolverInterface::Factorization(
const Index* ia,
const Index* ja,
bool check_NegEVals,
Index numberOfNegEVals
)
{
DBG_START_METH("WsmpSolverInterface::Factorization", dbg_verbosity);
Index iter_count = -1;
if( HaveIpData() )
{
iter_count = IpData().iter_count();
}
if( iter_count == wsmp_write_matrix_iteration_ )
{
matrix_file_number_++;
char buf[256];
Snprintf(buf, 255, "wsmp_matrix_%" IPOPT_INDEX_FORMAT "_%" IPOPT_INDEX_FORMAT ".dat", iter_count, matrix_file_number_);
Jnlst().Printf(J_SUMMARY, J_LINEAR_ALGEBRA,
"Writing WSMP matrix into file %s.\n", buf);
FILE* fp = fopen(buf, "w");
fprintf(fp, "%" IPOPT_INDEX_FORMAT "\n", dim_); for( Index icol = 0; icol < dim_; icol++ )
{
fprintf(fp, "%" IPOPT_INDEX_FORMAT "", ia[icol + 1] - ia[icol]); for( Index irow = ia[icol]; irow < ia[icol + 1]; irow++ )
{
fprintf(fp, " %23.16e %" IPOPT_INDEX_FORMAT "", a_[irow - 1], ja[irow - 1]);
}
fprintf(fp, "\n");
}
fclose(fp);
}
if( !have_symbolic_factorization_ )
{
ESymSolverStatus retval = InternalSymFact(ia, ja, numberOfNegEVals);
if( retval != SYMSOLVER_SUCCESS )
{
return retval;
}
have_symbolic_factorization_ = true;
}
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemFactorization().Start();
}
Index N = dim_;
Index NAUX = 0;
IPARM_[1] = 3; IPARM_[2] = 3; DPARM_[10] = wsmp_pivtol_; Index idmy = 0;
double ddmy = 0.;
#ifdef PARDISO_MATCHING_PREPROCESS
{
Index* tmp2_ = new Index[N];
smat_reordering_pardiso_wsmp(&N, ia, ja, a_, ia2, ja2, a2_, perm2, scale2, tmp2_, 1);
delete[] tmp2_;
}
#endif
Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA,
"Calling WSSMP-3-3 for numerical factorization.\n");
#ifdef PARDISO_MATCHING_PREPROCESS
IPOPT_WSMP_FUNC(wssmp, WSSMP)(&N, ia2, ja2, a2_, &ddmy, PERM_, INVP_, &ddmy, &idmy,
#else
IPOPT_WSMP_FUNC(wssmp, WSSMP)(&N, ia, ja, a_, &ddmy, PERM_, INVP_, &ddmy, &idmy,
#endif
&idmy, &ddmy, &NAUX, MRP_, IPARM_, DPARM_);
Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA,
"Done with WSSMP-3-3 for numerical factorization.\n");
const Index ierror = IPARM_[63];
if( ierror > 0 )
{
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"WSMP detected that the matrix is singular and encountered %" IPOPT_INDEX_FORMAT " zero pivots.\n", dim_ + 1 - ierror);
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemFactorization().End();
}
return SYMSOLVER_SINGULAR;
}
else if( ierror != 0 )
{
if( ierror == -102 )
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA,
"Error: WSMP is not able to allocate sufficient amount of memory during factorization.\n");
}
else
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA,
"Error in WSMP during factorization phase.\n Error code is %" IPOPT_INDEX_FORMAT ".\n", ierror);
}
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemFactorization().End();
}
return SYMSOLVER_FATAL_ERROR;
}
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Memory usage for WSSMP after factorization IPARM(23) = %" IPOPT_INDEX_FORMAT "\n", IPARM_[22]);
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Number of nonzeros in WSSMP after factorization IPARM(24) = %" IPOPT_INDEX_FORMAT "\n", IPARM_[23]);
if( factorizations_since_recomputed_ordering_ != -1 )
{
factorizations_since_recomputed_ordering_++;
}
negevals_ = IPARM_[21];
if( check_NegEVals && (numberOfNegEVals != negevals_) )
{
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Wrong inertia: required are %" IPOPT_INDEX_FORMAT ", but we got %" IPOPT_INDEX_FORMAT ".\n", numberOfNegEVals, negevals_);
if( skip_inertia_check_ )
{
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
" But wsmp_skip_inertia_check is set. Ignore inertia.\n");
IpData().Append_info_string("IC ");
negevals_ = numberOfNegEVals;
}
else
{
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemFactorization().End();
}
return SYMSOLVER_WRONG_INERTIA;
}
}
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemFactorization().End();
}
return SYMSOLVER_SUCCESS;
}
ESymSolverStatus WsmpSolverInterface::Solve(
const Index* ia,
const Index* ja,
Index nrhs,
double* rhs_vals
)
{
DBG_START_METH("WsmpSolverInterface::Solve", dbg_verbosity);
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemBackSolve().Start();
}
Index N = dim_;
Index LDB = dim_;
Index NRHS = nrhs;
Index NAUX = 0;
IPARM_[1] = 4; IPARM_[2] = 5; IPARM_[5] = 1;
DPARM_[5] = 1e-12;
double ddmy;
Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA,
"Calling WSSMP-4-5 for backsolve.\n");
#ifdef PARDISO_MATCHING_PREPROCESS
double* X = new double[nrhs * N];
for (Index i = 0; i < nrhs * N; i++)
{
X[perm2[i]] = scale2[i] * rhs_vals[i];
}
IPOPT_WSMP_FUNC(wssmp, WSSMP)(&N, ia, ja, a_, &ddmy, PERM_, INVP_,
X, &LDB, &NRHS, &ddmy, &NAUX,
MRP_, IPARM_, DPARM_);
for (Index i = 0; i < N; i++)
{
rhs_vals[i] = scale2[i] * X[perm2[i]];
}
#else
IPOPT_WSMP_FUNC(wssmp, WSSMP)(&N, ia, ja, a_, &ddmy, PERM_, INVP_, rhs_vals, &LDB, &NRHS, &ddmy, &NAUX, MRP_, IPARM_,
DPARM_);
#endif
Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA,
"Done with WSSMP-4-5 for backsolve.\n");
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemBackSolve().End();
}
Index ierror = IPARM_[63];
if( ierror != 0 )
{
if( ierror == -102 )
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA,
"Error: WSMP is not able to allocate sufficient amount of memory during ordering/symbolic factorization.\n");
}
else
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA,
"Error in WSMP during ordering/symbolic factorization phase.\n Error code is %" IPOPT_INDEX_FORMAT ".\n", ierror);
}
return SYMSOLVER_FATAL_ERROR;
}
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Number of iterative refinement steps in WSSMP: %" IPOPT_INDEX_FORMAT "\n", IPARM_[5]);
#ifdef PARDISO_MATCHING_PREPROCESS
delete [] X;
#endif
return SYMSOLVER_SUCCESS;
}
Index WsmpSolverInterface::NumberOfNegEVals() const
{
DBG_START_METH("WsmpSolverInterface::NumberOfNegEVals", dbg_verbosity);
DBG_ASSERT(negevals_ >= 0);
return negevals_;
}
bool WsmpSolverInterface::IncreaseQuality()
{
DBG_START_METH("WsmpSolverInterface::IncreaseQuality", dbg_verbosity);
if( factorizations_since_recomputed_ordering_ == -1 || factorizations_since_recomputed_ordering_ > 2 )
{
DPARM_[14] = 1.0;
pivtol_changed_ = true;
IpData().Append_info_string("RO ");
factorizations_since_recomputed_ordering_ = 0;
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Triggering WSMP's recomputation of the ordering for next factorization.\n");
return true;
}
if( wsmp_pivtol_ == wsmp_pivtolmax_ )
{
return false;
}
pivtol_changed_ = true;
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Increasing pivot tolerance for WSMP from %7.2e ", wsmp_pivtol_);
wsmp_pivtol_ = Min(wsmp_pivtolmax_, std::pow(wsmp_pivtol_, 0.75));
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"to %7.2e.\n", wsmp_pivtol_);
return true;
}
bool WsmpSolverInterface::ProvidesDegeneracyDetection() const
{
return true;
}
ESymSolverStatus WsmpSolverInterface::DetermineDependentRows(
const Index* ia,
const Index* ja,
std::list<Index>& c_deps
)
{
DBG_START_METH("WsmpSolverInterface::DetermineDependentRows",
dbg_verbosity);
c_deps.clear();
ASSERT_EXCEPTION(!wsmp_no_pivoting_, OPTION_INVALID, "WSMP dependency detection does not work without pivoting.");
if( !have_symbolic_factorization_ )
{
ESymSolverStatus retval = InternalSymFact(ia, ja, 0);
if( retval != SYMSOLVER_SUCCESS )
{
return retval;
}
have_symbolic_factorization_ = true;
}
Index N = dim_;
Index NAUX = 0;
IPARM_[1] = 3; IPARM_[2] = 3; DPARM_[10] = wsmp_pivtol_; Index idmy = 0;
double ddmy = 0.;
#ifdef PARDISO_MATCHING_PREPROCESS
IPOPT_WSMP_FUNC(wssmp, WSSMP)(&N, ia2, ja2, a2_, &ddmy, PERM_, INVP_, &ddmy, &idmy,
&idmy, &ddmy, &NAUX, MRP_, IPARM_, DPARM_);
#else
IPOPT_WSMP_FUNC(wssmp, WSSMP)(&N, ia, ja, a_, &ddmy, PERM_, INVP_, &ddmy, &idmy, &idmy, &ddmy, &NAUX, MRP_, IPARM_,
DPARM_);
#endif
const Index ierror = IPARM_[63];
if( ierror == 0 )
{
Index ii = 0;
for( Index i = 0; i < N; i++ )
{
if( MRP_[i] == -1 )
{
c_deps.push_back(i);
ii++;
}
}
DBG_ASSERT(ii == IPARM_[20]);
}
if( ierror > 0 )
{
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"WSMP detected that the matrix is singular and encountered %" IPOPT_INDEX_FORMAT " zero pivots.\n", dim_ + 1 - ierror);
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemFactorization().End();
}
return SYMSOLVER_SINGULAR;
}
else if( ierror != 0 )
{
if( ierror == -102 )
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA,
"Error: WSMP is not able to allocate sufficient amount of memory during factorization.\n");
}
else
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA,
"Error in WSMP during factorization phase.\n Error code is %" IPOPT_INDEX_FORMAT ".\n", ierror);
}
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemFactorization().End();
}
return SYMSOLVER_FATAL_ERROR;
}
return SYMSOLVER_SUCCESS;
}
}