#include "IpoptConfig.h"
#include "IpPardisoSolverInterface.hpp"
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <fstream>
#include <iomanip>
namespace Ipopt
{
#if IPOPT_VERBOSITY > 0
static const Index dbg_verbosity = 0;
#endif
static IPOPT_DECL_PARDISOINIT(*user_pardisoinit) = NULL;
static IPOPT_DECL_PARDISO(*user_pardiso) = NULL;
static bool user_isparallel = false;
#ifdef PARDISO_MATCHING_PREPROCESS
static IPOPT_DECL_SMAT_REORDERING_PARDISO_WSMP(*user_smat_reordering_pardiso_wsmp) = NULL;
#endif
PardisoSolverInterface::PardisoSolverInterface(
SmartPtr<LibraryLoader> pardisoloader_
) : a_(NULL),
#ifdef PARDISO_MATCHING_PREPROCESS
ia2(NULL),
ja2(NULL),
a2_(NULL),
perm2(NULL),
scale2(NULL),
#endif
negevals_(-1),
initialized_(false),
MAXFCT_(1),
MNUM_(1),
MTYPE_(-2),
MSGLVL_(0),
debug_last_iter_(-1),
pardisoloader(pardisoloader_),
pardisoinit(NULL),
pardiso(NULL),
#ifdef PARDISO_MATCHING_PREPROCESS
smat_reordering_pardiso_wsmp(NULL),
#endif
pardiso_exist_parallel(false)
{
DBG_START_METH("PardisoSolverInterface::PardisoSolverInterface()", dbg_verbosity);
PT_ = new void* [64];
IPARM_ = new Index[64];
DPARM_ = new Number[64];
}
PardisoSolverInterface::~PardisoSolverInterface()
{
DBG_START_METH("PardisoSolverInterface::~PardisoSolverInterface()",
dbg_verbosity);
if( initialized_ )
{
Index PHASE = -1;
Index N = dim_;
Index NRHS = 0;
Index ERROR;
Index idmy = 0;
Number ddmy = 0.;
pardiso(PT_, &MAXFCT_, &MNUM_, &MTYPE_, &PHASE, &N, &ddmy, &idmy, &idmy, &idmy, &NRHS, IPARM_, &MSGLVL_, &ddmy,
&ddmy, &ERROR, DPARM_);
DBG_ASSERT(ERROR == 0);
}
delete[] PT_;
delete[] IPARM_;
delete[] DPARM_;
delete[] a_;
#ifdef PARDISO_MATCHING_PREPROCESS
delete[] ia2;
delete[] ja2;
delete[] a2_;
delete[] perm2;
delete[] scale2;
#endif
}
void PardisoSolverInterface::RegisterOptions(
SmartPtr<RegisteredOptions> roptions
)
{
roptions->AddStringOption3(
"pardiso_matching_strategy",
"Matching strategy to be used by Pardiso",
"complete+2x2",
"complete", "Match complete (IPAR(13)=1)",
"complete+2x2", "Match complete+2x2 (IPAR(13)=2)",
"constraints", "Match constraints (IPAR(13)=3)",
"This is IPAR(13) in Pardiso manual.");
roptions->AddStringOption2(
"pardiso_redo_symbolic_fact_only_if_inertia_wrong",
"Toggle for handling case when elements were perturbed by Pardiso.",
"no",
"no", "Always redo symbolic factorization when elements were perturbed",
"yes", "Only redo symbolic factorization when elements were perturbed if also the inertia was wrong",
"",
true);
roptions->AddBoolOption(
"pardiso_repeated_perturbation_means_singular",
"Whether to assume that matrix is singular if elements were perturbed after recent symbolic factorization.",
false,
"",
true);
roptions->AddLowerBoundedIntegerOption(
"pardiso_msglvl",
"Pardiso message level",
0,
0,
"This is MSGLVL in the Pardiso manual.");
roptions->AddBoolOption(
"pardiso_skip_inertia_check",
"Whether to 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->AddIntegerOption(
"pardiso_max_iterative_refinement_steps",
"Limit on number of iterative refinement steps.",
0,
"The solver does not perform more than the absolute value of this value steps of iterative refinement and "
"stops the process if a satisfactory level of accuracy of the solution in terms of backward error is achieved. "
"If negative, the accumulation of the residue uses extended precision real and complex data types. "
"Perturbed pivots result in iterative refinement. "
"The solver automatically performs two steps of iterative refinements when perturbed pivots are obtained during the numerical factorization and this option is set to 0.");
roptions->AddStringOption6(
"pardiso_order",
"Controls the fill-in reduction ordering algorithm for the input matrix.",
"metis",
"amd", "minimum degree algorithm",
"one", "",
"metis", "MeTiS nested dissection algorithm",
"pmetis", "parallel (OpenMP) version of MeTiS nested dissection algorithm",
"four", "",
"five", "");
roptions->AddLowerBoundedIntegerOption(
"pardiso_max_iter",
"Maximum number of Krylov-Subspace Iteration",
1,
500,
"DPARM(1)",
true);
roptions->AddBoundedNumberOption(
"pardiso_iter_relative_tol",
"Relative Residual Convergence",
0.0, true,
1.0, true,
1e-6,
"DPARM(2)",
true);
roptions->AddLowerBoundedIntegerOption(
"pardiso_iter_coarse_size",
"Maximum Size of Coarse Grid Matrix",
1,
5000,
"DPARM(3)",
true);
roptions->AddLowerBoundedIntegerOption(
"pardiso_iter_max_levels",
"Maximum Size of Grid Levels",
1,
10,
"DPARM(4)",
true);
roptions->AddBoundedNumberOption(
"pardiso_iter_dropping_factor",
"dropping value for incomplete factor",
0.0, true,
1.0, true,
0.5,
"DPARM(5)",
true);
roptions->AddBoundedNumberOption(
"pardiso_iter_dropping_schur",
"dropping value for sparsify schur complement factor",
0.0, true,
1.0, true,
1e-1,
"DPARM(6)",
true);
roptions->AddLowerBoundedIntegerOption(
"pardiso_iter_max_row_fill",
"max fill for each row",
1,
10000000,
"DPARM(7)",
true);
roptions->AddLowerBoundedNumberOption(
"pardiso_iter_inverse_norm_factor",
"",
1, true,
5000000,
"DPARM(8)",
true);
roptions->AddBoolOption(
"pardiso_iterative",
"Switch for iterative solver in Pardiso library",
false,
"",
true);
roptions->AddLowerBoundedIntegerOption(
"pardiso_max_droptol_corrections",
"Maximal number of decreases of drop tolerance during one solve.",
1,
4,
"This is relevant only for iterative Pardiso options.",
true);
}
void PardisoSolverInterface::SetFunctions(
IPOPT_DECL_PARDISOINIT(*pardisoinit),
IPOPT_DECL_PARDISO(*pardiso),
bool isparallel,
IPOPT_DECL_SMAT_REORDERING_PARDISO_WSMP(*smat_reordering_pardiso_wsmp)
)
{
DBG_ASSERT(pardisoinit != NULL);
DBG_ASSERT(pardiso != NULL);
#ifdef PARDISO_MATCHING_PREPROCESS
DBG_ASSERT(smat_reordering_pardiso_wsmp != NULL);
#endif
user_pardisoinit = pardisoinit;
user_pardiso = pardiso;
user_isparallel = isparallel;
#ifdef PARDISO_MATCHING_PREPROCESS
user_smat_reordering_pardiso_wsmp = smat_reordering_pardiso_wsmp;
#else
(void)smat_reordering_pardiso_wsmp;
#endif
}
bool PardisoSolverInterface::InitializeImpl(
const OptionsList& options,
const std::string& prefix
)
{
if( user_pardisoinit != NULL )
{
pardisoinit = user_pardisoinit;
pardiso = user_pardiso;
pardiso_exist_parallel = user_isparallel;
#ifdef PARDISO_MATCHING_PREPROCESS
smat_reordering_pardiso_wsmp = user_smat_reordering_pardiso_wsmp;
#endif
}
else
{
DBG_ASSERT(IsValid(pardisoloader));
pardisoinit = (IPOPT_DECL_PARDISOINIT(*))pardisoloader->loadSymbol("pardisoinit");
pardiso = (IPOPT_DECL_PARDISO(*))pardisoloader->loadSymbol("pardiso");
#ifdef PARDISO_MATCHING_PREPROCESS
smat_reordering_pardiso_wsmp = (IPOPT_DECL_SMAT_REORDERING_PARDISO_WSMP(*))pardisoloader->loadSymbol("smat_reordering_pardiso_wsmp");
#endif
pardisoloader->loadSymbol("pardiso_ipopt_newinterface");
try
{
pardisoloader->loadSymbol("pardiso_exist_parallel");
pardiso_exist_parallel = true;
}
catch( const DYNAMIC_LIBRARY_FAILURE& )
{
DBG_ASSERT(!pardiso_exist_parallel);
}
}
DBG_ASSERT(pardisoinit != NULL);
DBG_ASSERT(pardiso != NULL);
#ifdef PARDISO_MATCHING_PREPROCESS
DBG_ASSERT(smat_reordering_pardiso_wsmp);
#endif
Index enum_int;
options.GetEnumValue("pardiso_matching_strategy", enum_int, prefix);
match_strat_ = PardisoMatchingStrategy(enum_int);
options.GetBoolValue("pardiso_redo_symbolic_fact_only_if_inertia_wrong",
pardiso_redo_symbolic_fact_only_if_inertia_wrong_, prefix);
options.GetBoolValue("pardiso_repeated_perturbation_means_singular", pardiso_repeated_perturbation_means_singular_,
prefix);
options.GetBoolValue("pardiso_skip_inertia_check", skip_inertia_check_, prefix);
Index pardiso_msglvl;
options.GetIntegerValue("pardiso_msglvl", pardiso_msglvl, prefix);
Index max_iterref_steps;
options.GetIntegerValue("pardiso_max_iterative_refinement_steps", max_iterref_steps, prefix);
Index order;
options.GetEnumValue("pardiso_order", order, prefix);
options.GetBoolValue("pardiso_iterative", pardiso_iterative_, prefix);
Index pardiso_max_iter;
options.GetIntegerValue("pardiso_max_iter", pardiso_max_iter, prefix);
Number pardiso_iter_relative_tol;
options.GetNumericValue("pardiso_iter_relative_tol", pardiso_iter_relative_tol, prefix);
Index pardiso_iter_coarse_size;
options.GetIntegerValue("pardiso_iter_coarse_size", pardiso_iter_coarse_size, prefix);
Index pardiso_iter_max_levels;
options.GetIntegerValue("pardiso_iter_max_levels", pardiso_iter_max_levels, prefix);
Number pardiso_iter_dropping_factor;
options.GetNumericValue("pardiso_iter_dropping_factor", pardiso_iter_dropping_factor, prefix);
Number pardiso_iter_dropping_schur;
options.GetNumericValue("pardiso_iter_dropping_schur", pardiso_iter_dropping_schur, prefix);
Index pardiso_iter_max_row_fill;
options.GetIntegerValue("pardiso_iter_max_row_fill", pardiso_iter_max_row_fill, prefix);
Number pardiso_iter_inverse_norm_factor;
options.GetNumericValue("pardiso_iter_inverse_norm_factor", pardiso_iter_inverse_norm_factor, prefix);
options.GetIntegerValue("pardiso_max_droptol_corrections", pardiso_max_droptol_corrections_, prefix);
if( initialized_ )
{
Index PHASE = -1;
Index N = dim_;
Index NRHS = 0;
Index ERROR;
Index idmy;
Number ddmy;
pardiso(PT_, &MAXFCT_, &MNUM_, &MTYPE_, &PHASE, &N, &ddmy, &idmy, &idmy, &idmy, &NRHS, IPARM_, &MSGLVL_, &ddmy,
&ddmy, &ERROR, DPARM_);
DBG_ASSERT(ERROR == 0);
}
dim_ = 0;
nonzeros_ = 0;
have_symbolic_factorization_ = false;
initialized_ = false;
delete[] a_;
a_ = 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
memset(PT_, 0, 64); IPARM_[0] = 0;
Index ERROR = 0;
Index SOLVER = 0;
pardisoinit(PT_, &MTYPE_, &SOLVER, IPARM_, DPARM_, &ERROR);
if( ERROR != 0 )
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA, "Problem with Pardiso license (error %" IPOPT_INDEX_FORMAT " from pardisoinit).\n", ERROR);
return false;
}
IPARM_[0] = 1;
int num_procs = 1;
if( pardiso_exist_parallel )
{
char* var = getenv("OMP_NUM_THREADS");
if( var != NULL )
{
sscanf(var, "%d", &num_procs);
if( num_procs < 1 )
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA,
"Invalid value for OMP_NUM_THREADS (\"%s\").\n", var);
return false;
}
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Using environment OMP_NUM_THREADS = %d as the number of processors for PARDISO.\n", num_procs);
}
}
else
{
Jnlst().Printf(J_WARNING, J_LINEAR_ALGEBRA,
"You should set the environment variable OMP_NUM_THREADS to the number of processors used in Pardiso (e.g., 1).\n\n");
}
IPARM_[1] = order;
IPARM_[2] = num_procs; IPARM_[5] = 1; IPARM_[7] = max_iterref_steps;
IPARM_[9] = 12;
IPARM_[10] = 2; IPARM_[12] = (int) match_strat_;
IPARM_[20] = 3; IPARM_[23] = 1; IPARM_[24] = 1; #ifdef IPOPT_SINGLE
IPARM_[28] = 1; #else
IPARM_[28] = 0; #endif
IPARM_[29] = 80;
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Pardiso matrix ordering (IPARM(2)): %" IPOPT_INDEX_FORMAT "\n", IPARM_[1]);
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Pardiso max. iterref. steps (IPARM(8)): %" IPOPT_INDEX_FORMAT "\n", IPARM_[7]);
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Pardiso matching strategy (IPARM(13)): %" IPOPT_INDEX_FORMAT "\n", IPARM_[12]);
if( pardiso_iterative_ )
{
IPARM_[31] = 1;
DPARM_[0] = pardiso_max_iter; DPARM_[1] = pardiso_iter_relative_tol; DPARM_[2] = pardiso_iter_coarse_size; DPARM_[3] = pardiso_iter_max_levels; DPARM_[4] = pardiso_iter_dropping_factor; DPARM_[5] = pardiso_iter_dropping_schur; DPARM_[6] = pardiso_iter_max_row_fill; DPARM_[7] = pardiso_iter_inverse_norm_factor; DPARM_[8] = 25; }
MSGLVL_ = pardiso_msglvl;
return true;
}
ESymSolverStatus PardisoSolverInterface::MultiSolve(
bool new_matrix,
const Index* ia,
const Index* ja,
Index nrhs,
Number* rhs_vals,
bool check_NegEVals,
Index numberOfNegEVals
)
{
DBG_START_METH("PardisoSolverInterface::MultiSolve", dbg_verbosity);
DBG_ASSERT(!check_NegEVals || ProvidesInertia());
DBG_ASSERT(initialized_);
if( new_matrix )
{
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);
}
Number* PardisoSolverInterface::GetValuesArrayPtr()
{
DBG_ASSERT(initialized_);
DBG_ASSERT(a_);
return a_;
}
ESymSolverStatus PardisoSolverInterface::InitializeStructure(
Index dim,
Index nonzeros,
const Index* ia,
const Index* ja
)
{
DBG_START_METH("PardisoSolverInterface::InitializeStructure", dbg_verbosity);
dim_ = dim;
nonzeros_ = nonzeros;
delete[] a_;
a_ = NULL;
a_ = new Number[nonzeros_];
ESymSolverStatus retval = SymbolicFactorization(ia, ja);
if( retval != SYMSOLVER_SUCCESS )
{
return retval;
}
initialized_ = true;
return retval;
}
ESymSolverStatus PardisoSolverInterface::SymbolicFactorization(
const Index* ,
const Index*
)
{
DBG_START_METH("PardisoSolverInterface::SymbolicFactorization",
dbg_verbosity);
have_symbolic_factorization_ = false;
return SYMSOLVER_SUCCESS;
}
static
void write_iajaa_matrix(
Index N,
const Index* ia,
const Index* ja,
Number* a_,
Number* rhs_vals,
int iter_cnt,
int sol_cnt
)
{
if( getenv("IPOPT_WRITE_MAT") )
{
char mat_name[128];
char mat_pref[32];
Index NNZ = ia[N] - 1;
Index i;
if( getenv("IPOPT_WRITE_PREFIX") )
{
strcpy(mat_pref, getenv("IPOPT_WRITE_PREFIX"));
}
else
{
strcpy(mat_pref, "mat-ipopt");
}
Snprintf(mat_name, 127, "%s_%03d-%02d.iajaa", mat_pref, iter_cnt, sol_cnt);
std::ofstream mat_file(mat_name);
mat_file << std::setprecision(std::numeric_limits<Number>::digits10 + 1);
mat_file << N << std::endl;
mat_file << NNZ << std::endl;
for( i = 0; i < N + 1; i++ )
{
mat_file << ia[i] << std::endl;
}
for( i = 0; i < NNZ; i++ )
{
mat_file << ja[i] << std::endl;
}
for( i = 0; i < NNZ; i++ )
{
mat_file << a_[i] << std::endl;
}
if( rhs_vals )
for( i = 0; i < N; i++ )
{
mat_file << rhs_vals[i] << std::endl;
}
}
if( getenv("IPOPT_WRITE_MAT_MTX") )
{
char mat_name[128];
char mat_pref[32];
Index i;
Index j;
if( getenv("IPOPT_WRITE_PREFIX") )
{
strcpy(mat_pref, getenv("IPOPT_WRITE_PREFIX"));
}
else
{
strcpy(mat_pref, "mat-ipopt");
}
Snprintf(mat_name, 127, "%s_%03d-%02d.mtx", mat_pref, iter_cnt, sol_cnt);
std::ofstream mat_file(mat_name);
mat_file << std::setprecision(std::numeric_limits<Number>::digits10 + 1);
for( i = 0; i < N; i++ )
for( j = ia[i]; j < ia[i + 1] - 1; j++ )
{
mat_file << ' ' << i + 1 << ' ' << ja[j - 1] << ' ' << a_[j - 1] << std::endl;
}
}
}
ESymSolverStatus PardisoSolverInterface::Factorization(
const Index* ia,
const Index* ja,
bool check_NegEVals,
Index numberOfNegEVals
)
{
DBG_START_METH("PardisoSolverInterface::Factorization", dbg_verbosity);
Index PHASE;
Index N = dim_;
Index PERM; Index NRHS = 0;
Number B; Number X; Index ERROR;
bool done = false;
bool just_performed_symbolic_factorization = false;
while( !done )
{
if( !have_symbolic_factorization_ )
{
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemSymbolicFactorization().Start();
}
PHASE = 11;
#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 Number[nonzeros_];
perm2 = new Index[N];
scale2 = new Number[N];
Index* tmp2_ = new Index[N];
smat_reordering_pardiso_wsmp(&N, ia, ja, a_, ia2, ja2, a2_, perm2, scale2, tmp2_, 0);
delete[] tmp2_;
#endif
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Calling Pardiso for symbolic factorization.\n");
pardiso(PT_, &MAXFCT_, &MNUM_, &MTYPE_,
#ifdef PARDISO_MATCHING_PREPROCESS
&PHASE, &N, a2_, ia2, ja2, &PERM,
#else
&PHASE, &N, a_, ia, ja, &PERM,
#endif
&NRHS, IPARM_, &MSGLVL_, &B, &X, &ERROR, DPARM_);
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemSymbolicFactorization().End();
}
if( ERROR == -7 )
{
Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA,
"Pardiso symbolic factorization returns ERROR = %" IPOPT_INDEX_FORMAT ". Matrix is singular.\n", ERROR);
return SYMSOLVER_SINGULAR;
}
else if( ERROR != 0 )
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA,
"Error in Pardiso during symbolic factorization phase. ERROR = %" IPOPT_INDEX_FORMAT ".\n", ERROR);
return SYMSOLVER_FATAL_ERROR;
}
have_symbolic_factorization_ = true;
just_performed_symbolic_factorization = true;
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Memory in KB required for the symbolic factorization = %" IPOPT_INDEX_FORMAT ".\n", IPARM_[14]);
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Integer memory in KB required for the numerical factorization = %" IPOPT_INDEX_FORMAT ".\n", IPARM_[15]);
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Double memory in KB required for the numerical factorization = %" IPOPT_INDEX_FORMAT ".\n", IPARM_[16]);
}
PHASE = 22;
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemFactorization().Start();
}
Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA,
"Calling Pardiso for factorization.\n");
if( HaveIpData() )
{
if( IpData().iter_count() != debug_last_iter_ )
{
debug_cnt_ = 0;
}
debug_last_iter_ = IpData().iter_count();
debug_cnt_++;
}
else
{
debug_cnt_ = 0;
debug_last_iter_ = 0;
}
#ifdef PARDISO_MATCHING_PREPROCESS
Index* tmp3_ = new Index[N];
smat_reordering_pardiso_wsmp(&N, ia, ja, a_, ia2, ja2, a2_, perm2, scale2, tmp3_, 1);
delete[] tmp3_;
#endif
pardiso(PT_, &MAXFCT_, &MNUM_, &MTYPE_,
#ifdef PARDISO_MATCHING_PREPROCESS
&PHASE, &N, a2_, ia2, ja2, &PERM,
#else
&PHASE, &N, a_, ia, ja, &PERM,
#endif
&NRHS, IPARM_, &MSGLVL_, &B, &X, &ERROR, DPARM_);
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemFactorization().End();
}
if( ERROR == -7 )
{
Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA,
"Pardiso factorization returns ERROR = %" IPOPT_INDEX_FORMAT ". Matrix is singular.\n", ERROR);
return SYMSOLVER_SINGULAR;
}
else if( ERROR == -4 )
{
return SYMSOLVER_SINGULAR;
}
else if( ERROR != 0 )
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA,
"Error in Pardiso during factorization phase. ERROR = %" IPOPT_INDEX_FORMAT ".\n", ERROR);
return SYMSOLVER_FATAL_ERROR;
}
negevals_ = Max(IPARM_[22], numberOfNegEVals);
if( IPARM_[13] != 0 )
{
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Number of perturbed pivots in factorization phase = %" IPOPT_INDEX_FORMAT ".\n", IPARM_[13]);
if( !pardiso_redo_symbolic_fact_only_if_inertia_wrong_ || (negevals_ != numberOfNegEVals) )
{
if( HaveIpData() )
{
IpData().Append_info_string("Pn");
}
have_symbolic_factorization_ = false;
if( just_performed_symbolic_factorization )
{
if( pardiso_repeated_perturbation_means_singular_ )
{
if( HaveIpData() )
{
IpData().Append_info_string("Ps");
}
return SYMSOLVER_SINGULAR;
}
else
{
done = true;
}
}
else
{
done = false;
}
}
else
{
if( HaveIpData() )
{
IpData().Append_info_string("Pp");
}
done = true;
}
}
else
{
done = true;
}
}
DBG_ASSERT(IPARM_[21] + IPARM_[22] == dim_);
if( skip_inertia_check_ )
{
numberOfNegEVals = negevals_;
}
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_);
return SYMSOLVER_WRONG_INERTIA;
}
return SYMSOLVER_SUCCESS;
}
ESymSolverStatus PardisoSolverInterface::Solve(
const Index* ia,
const Index* ja,
Index nrhs,
Number* rhs_vals
)
{
DBG_START_METH("PardisoSolverInterface::Solve", dbg_verbosity);
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemBackSolve().Start();
}
Index PHASE = 33;
Index N = dim_;
Index PERM; Index NRHS = nrhs;
Number* X = new Number[nrhs * dim_];
Number* ORIG_RHS = new Number[nrhs * dim_];
Index ERROR;
for( Index i = 0; i < N; i++ )
{
X[i] = 0.;
ORIG_RHS[i] = rhs_vals[i];
}
Index iter_count = 0;
if( HaveIpData() )
{
iter_count = IpData().iter_count();
}
#ifdef PARDISO_MATCHING_PREPROCESS
write_iajaa_matrix (N, ia2, ja2, a2_, rhs_vals, iter_count, debug_cnt_);
#else
write_iajaa_matrix(N, ia, ja, a_, rhs_vals, iter_count, debug_cnt_);
#endif
int attempts = 0;
const int max_attempts = pardiso_iterative_ ? pardiso_max_droptol_corrections_ + 1 : 1;
DBG_ASSERT(max_attempts > 0);
while( attempts < max_attempts )
{
#ifdef PARDISO_MATCHING_PREPROCESS
for (Index i = 0; i < N; i++)
{
rhs_vals[perm2[i]] = scale2[i] * ORIG_RHS[ i ];
}
pardiso(PT_, &MAXFCT_, &MNUM_, &MTYPE_,
&PHASE, &N, a2_, ia2, ja2, &PERM,
&NRHS, IPARM_, &MSGLVL_, rhs_vals, X,
&ERROR, DPARM_);
for (Index i = 0; i < N; i++)
{
X[i] = rhs_vals[ perm2[i]];
}
for (Index i = 0; i < N; i++)
{
rhs_vals[i] = scale2[i] * X[i];
}
#else
for( Index i = 0; i < N; i++ )
{
rhs_vals[i] = ORIG_RHS[i];
}
pardiso(PT_, &MAXFCT_, &MNUM_, &MTYPE_, &PHASE, &N, a_, ia, ja, &PERM, &NRHS, IPARM_, &MSGLVL_, rhs_vals, X,
&ERROR, DPARM_);
#endif
if( ERROR <= -100 && ERROR >= -102 )
{
Jnlst().Printf(J_WARNING, J_LINEAR_ALGEBRA,
"Iterative solver in Pardiso did not converge (ERROR = %" IPOPT_INDEX_FORMAT ")\n", ERROR);
Jnlst().Printf(J_WARNING, J_LINEAR_ALGEBRA,
" Decreasing drop tolerances from DPARM_[4] = %e and DPARM_[5] = %e\n", DPARM_[4], DPARM_[5]);
PHASE = 23;
DPARM_[4] /= 2.0;
DPARM_[5] /= 2.0;
Jnlst().Printf(J_WARNING, J_LINEAR_ALGEBRA,
" to DPARM_[4] = %e and DPARM_[5] = %e\n", DPARM_[4], DPARM_[5]);
attempts++;
ERROR = 0;
}
else
{
attempts = max_attempts;
}
}
delete[] X;
delete[] ORIG_RHS;
if( IPARM_[6] != 0 )
{
Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA,
"Number of iterative refinement steps = %" IPOPT_INDEX_FORMAT ".\n", IPARM_[6]);
if( HaveIpData() )
{
IpData().Append_info_string("Pi");
}
}
if( HaveIpData() )
{
IpData().TimingStats().LinearSystemBackSolve().End();
}
if( ERROR != 0 )
{
Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA,
"Error in Pardiso during solve phase. ERROR = %" IPOPT_INDEX_FORMAT ".\n", ERROR);
return SYMSOLVER_FATAL_ERROR;
}
return SYMSOLVER_SUCCESS;
}
Index PardisoSolverInterface::NumberOfNegEVals() const
{
DBG_START_METH("PardisoSolverInterface::NumberOfNegEVals", dbg_verbosity);
DBG_ASSERT(negevals_ >= 0);
return negevals_;
}
bool PardisoSolverInterface::IncreaseQuality()
{
return false;
}
}