Files
Seele/external/sdpa/sdpa_newton.cpp
T
2023-01-21 18:43:21 +01:00

1890 lines
59 KiB
C++

/* -------------------------------------------------------------
This file is a component of SDPA
Copyright (C) 2004-2013 SDPA Project
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
------------------------------------------------------------- */
#include "sdpa_newton.h"
#include "sdpa_parts.h"
#include "sdpa_linear.h"
#include "sdpa_algebra.h"
namespace sdpa {
pthread_mutex_t Newton::job_mutex = PTHREAD_MUTEX_INITIALIZER;
int Newton::Column_Number = 0;
int Newton::Column_NumberDx = 0;
Newton::Newton()
{
// Caution: if SDPA doesn't use sparse bMat,
// following variables are indefinite.
this->SDP_nBlock = -1;
SDP_number = NULL; SDP_location_sparse_bMat = NULL;
SDP_constraint1 = NULL; SDP_constraint2 = NULL;
SDP_blockIndex1 = NULL; SDP_blockIndex2 = NULL;
this->LP_nBlock = -1;
LP_number = NULL; LP_location_sparse_bMat = NULL;
LP_constraint1 = NULL; LP_constraint2 = NULL;
LP_blockIndex1 = NULL; LP_blockIndex2 = NULL;
diagonalIndex = NULL;
NUM_THREADS = 1;
}
Newton::Newton(int m, BlockStruct& bs)
{
initialize(m, bs);
}
Newton::~Newton()
{
finalize();
}
void Newton::initialize(int m, BlockStruct& bs)
{
gVec.initialize(m);
SDP_nBlock = bs.SDP_nBlock;
LP_nBlock = bs.LP_nBlock;
bMat_type = DENSE;
// Caution: if SDPA doesn't use sparse bMat,
// following variables are indefinite.
this->SDP_nBlock = -1;
SDP_number = NULL; SDP_location_sparse_bMat = NULL;
SDP_constraint1 = NULL; SDP_constraint2 = NULL;
SDP_blockIndex1 = NULL; SDP_blockIndex2 = NULL;
this->LP_nBlock = -1;
LP_number = NULL; LP_location_sparse_bMat = NULL;
LP_constraint1 = NULL; LP_constraint2 = NULL;
LP_blockIndex1 = NULL; LP_blockIndex2 = NULL;
diagonalIndex = NULL;
}
void Newton::finalize()
{
if (bMat_type == SPARSE){
if (SDP_location_sparse_bMat && SDP_constraint1 && SDP_constraint2
&& SDP_blockIndex1 && SDP_blockIndex2) {
for (int l=0; l<SDP_nBlock; ++l) {
DeleteArray(SDP_location_sparse_bMat[l]);
DeleteArray(SDP_constraint1[l]);
DeleteArray(SDP_constraint2[l]);
DeleteArray(SDP_blockIndex1[l]);
DeleteArray(SDP_blockIndex2[l]);
DeleteArray(SDP_startIndex2[l]);
}
DeleteArray(SDP_number);
DeleteArray(SDP_location_sparse_bMat);
DeleteArray(SDP_constraint1);
DeleteArray(SDP_constraint2);
DeleteArray(SDP_blockIndex1);
DeleteArray(SDP_blockIndex2);
DeleteArray(SDP_startIndex2);
DeleteArray(SDP_nStartIndex2);
}
if (LP_location_sparse_bMat && LP_constraint1 && LP_constraint2
&& LP_blockIndex1 && LP_blockIndex2) {
for (int l=0; l<LP_nBlock; ++l) {
DeleteArray(LP_location_sparse_bMat[l]);
DeleteArray(LP_constraint1[l]);
DeleteArray(LP_constraint2[l]);
DeleteArray(LP_blockIndex1[l]);
DeleteArray(LP_blockIndex2[l]);
DeleteArray(LP_startIndex2[l]);
}
DeleteArray(LP_number);
DeleteArray(LP_location_sparse_bMat);
DeleteArray(LP_constraint1);
DeleteArray(LP_constraint2);
DeleteArray(LP_blockIndex1);
DeleteArray(LP_blockIndex2);
DeleteArray(LP_startIndex2);
DeleteArray(LP_nStartIndex2);
}
DeleteArray(diagonalIndex);
sparse_bMat.finalize();
} else { // bMat_type == DENSE
bMat.finalize();
}
int m = gVec.nDim;
gVec.finalize();
}
void Newton::initialize_dense_bMat(int m)
{
// bMat_type = DENSE;
// printf("DENSE computations\n");
bMat.initialize(m,m);
}
// 2008/03/12 kazuhide nakata
void Newton::initialize_sparse_bMat(int m)
{
// bMat_type = SPARSE;
// printf("SPARSE computation\n");
// initialize sparse_bMat by Chordal::makeGraph
// sparse_bMat.display();
bool isEmptyMatrix = false;
// make index of diagonalIndex
NewArray(diagonalIndex,int,m+1);
int k=0;
for (int index=0; index<sparse_bMat.NonZeroCount; index++){
if (sparse_bMat.row_index[index] == sparse_bMat.column_index[index]) {
diagonalIndex[k] = index;
if (sparse_bMat.row_index[index] != k+1) {
rMessage("The matrix [" << (sparse_bMat.row_index[index]-1)
<< "] is empty");
isEmptyMatrix = true;
diagonalIndex[k+1] = diagonalIndex[k];
k++;
}
k++;
}
}
if (isEmptyMatrix) {
rMessage("Input Data Error :: Some Input Matricies are Empty");
}
diagonalIndex[m] = sparse_bMat.NonZeroCount;
#if 0
rMessage("diagonalIndex = ");
for (int index=0; index <m; ++index) {
printf(" [%d:%d]",index,diagonalIndex[index]);
}
printf("\n");
#endif
}
// 2008/03/12 kazuhide nakata
void Newton::initialize_bMat(int m, Chordal& chordal,
InputData& inputData,
FILE* Display,
FILE* fpOut)
{
/* Create clique tree */
switch (chordal.best) {
case SELECT_DENSE:
bMat_type = DENSE;
if (Display) {
fprintf(Display,"Schur computation : DENSE \n");
}
if (fpOut) {
fprintf(fpOut,"Schur computation : DENSE \n");
}
initialize_dense_bMat(m);
// Here, we release MUMPS and sparse_bMat
chordal.finalize();
break;
case SELECT_MUMPS_BEST:
bMat_type = SPARSE;
if (Display) {
fprintf(Display,"Schur computation : SPARSE \n");
}
if (fpOut) {
fprintf(fpOut,"Schur computation : SPARSE \n");
}
initialize_sparse_bMat(m);
make_aggrigateIndex(inputData);
break;
default:
rError("Wrong Ordering Obtained");
break;
}
}
int Newton::binarySearchIndex(int i, int j)
{
// binary search for index of sparse_bMat
int t = -1;
// We store only the lower triangular
int ii = i, jj = j;
if (i<j) {
jj = i;
ii = j;
}
int begin = diagonalIndex[jj];
int end = diagonalIndex[jj+1]-1;
int target = (begin + end) / 2;
while (end - begin > 1){
if (sparse_bMat.row_index[target] < ii+1){
begin = target;
target = (begin + end) / 2;
} else if (sparse_bMat.row_index[target] > ii+1){
end = target;
target = (begin + end) / 2;
} else if (sparse_bMat.row_index[target] == ii+1) {
t = target;
break;
}
}
if (t == -1){
if (sparse_bMat.row_index[begin] == ii+1){
t = begin;
} else if (sparse_bMat.row_index[end] == ii+1){
t = end;
} else {
#if 0
int m = sparse_bMat.nRow;
rMessage("Trouble ii = " << ii << " jj = " << j << " m = " << m);
for (int k = 0; k<sparse_bMat.NonZeroCount; ++k) {
fprintf(stdout,"[%04d,%04d] at %04d\n",
sparse_bMat.row_index[k],
sparse_bMat.column_index[k],
k);
}
#endif
// rError("Newton::make_aggrigateIndex program bug");
}
}
return t;
}
void Newton::make_aggrigateIndex_SDP(InputData& inputData)
{
SDP_nBlock = inputData.SDP_nBlock;
NewArray(SDP_number,int,SDP_nBlock);
// memory allocate for aggrigateIndex
NewArray(SDP_constraint1,int*,SDP_nBlock);
NewArray(SDP_constraint2,int*,SDP_nBlock);
NewArray(SDP_blockIndex1,int*,SDP_nBlock);
NewArray(SDP_blockIndex2,int*,SDP_nBlock);
NewArray(SDP_location_sparse_bMat,int*,SDP_nBlock);
NewArray(SDP_nStartIndex2, int, SDP_nBlock);
NewArray(SDP_startIndex2, int*, SDP_nBlock);
for (int l=0; l<SDP_nBlock; l++){
const int size = (inputData.SDP_nConstraint[l] + 1)
* inputData.SDP_nConstraint[l] / 2;
SDP_number[l] = size;
NewArray(SDP_constraint1[l],int,size);
NewArray(SDP_constraint2[l],int,size);
NewArray(SDP_blockIndex1[l],int,size);
NewArray(SDP_blockIndex2[l],int,size);
NewArray(SDP_location_sparse_bMat[l],int,size);
}
for (int l = 0; l<SDP_nBlock; l++){
int NonZeroCount = 0;
vector<int> startTmp;
for (int k1=0; k1<inputData.SDP_nConstraint[l]; k1++){
int j = inputData.SDP_constraint[l][k1];
int jb = inputData.SDP_blockIndex[l][k1];
startTmp.push_back(NonZeroCount);
for (int k2=0; k2<inputData.SDP_nConstraint[l]; k2++){
int i = inputData.SDP_constraint[l][k2];
int ib = inputData.SDP_blockIndex[l][k2];
if (i < j) {
continue;
}
// set index which A_i and A_j are not zero matrix
int target = binarySearchIndex(i,j);
if (target == -1) {
rMessage("("<<(i+1)<<","<<(j+1)<<") might have index");
SDP_number[l]--;
continue;
}
SDP_constraint1[l][NonZeroCount] = i;
SDP_constraint2[l][NonZeroCount] = j;
SDP_blockIndex1[l][NonZeroCount] = ib;
SDP_blockIndex2[l][NonZeroCount] = jb;
SDP_location_sparse_bMat[l][NonZeroCount] = target;
NonZeroCount++;
}
} // for k1
// The last element to stop the array
startTmp.push_back(NonZeroCount);
const int startTmp_size = startTmp.size();
SDP_nStartIndex2[l] = startTmp_size-1; // the last is the stopper
NewArray(SDP_startIndex2[l], int, startTmp_size);
for (int index1 = 0; index1 < startTmp_size; ++index1) {
SDP_startIndex2[l][index1] = startTmp[index1];
}
#if 0
rMessage("SDP_startIndex["<<l
<<"][" << startTmp_size << "] = ");
for (int index1 = 0; index1 < startTmp_size; ++index1) {
printf("%d->%d ", index1,startTmp[index1]);
}
#endif
} //for l lth block
}
void Newton::make_aggrigateIndex_LP(InputData& inputData)
{
LP_nBlock = inputData.LP_nBlock;
NewArray(LP_number,int,LP_nBlock);
// memory allocate for aggrigateIndex
NewArray(LP_constraint1,int*,LP_nBlock);
NewArray(LP_constraint2,int*,LP_nBlock);
NewArray(LP_blockIndex1,int*,LP_nBlock);
NewArray(LP_blockIndex2,int*,LP_nBlock);
NewArray(LP_location_sparse_bMat,int*,LP_nBlock);
NewArray(LP_nStartIndex2, int, LP_nBlock);
NewArray(LP_startIndex2, int*, LP_nBlock);
for (int l=0; l<LP_nBlock; l++){
int size = (inputData.LP_nConstraint[l]+1)
* inputData.LP_nConstraint[l]/2;
LP_number[l] = size;
NewArray(LP_constraint1[l],int,size);
NewArray(LP_constraint2[l],int,size);
NewArray(LP_blockIndex1[l],int,size);
NewArray(LP_blockIndex2[l],int,size);
NewArray(LP_location_sparse_bMat[l],int,size);
}
for (int l = 0; l<LP_nBlock; l++){
int NonZeroCount = 0;
vector<int> startTmp;
for (int k1=0; k1<inputData.LP_nConstraint[l]; k1++){
int j = inputData.LP_constraint[l][k1];
int jb = inputData.LP_blockIndex[l][k1];
startTmp.push_back(NonZeroCount);
for (int k2=0; k2<inputData.LP_nConstraint[l]; k2++){
int i = inputData.LP_constraint[l][k2];
int ib = inputData.LP_blockIndex[l][k2];
if (i < j){
continue;
}
// set index which A_i and A_j are not zero matrix
LP_constraint1[l][NonZeroCount] = i;
LP_constraint2[l][NonZeroCount] = j;
LP_blockIndex1[l][NonZeroCount] = ib;
LP_blockIndex2[l][NonZeroCount] = jb;
int target = binarySearchIndex(i,j);
LP_location_sparse_bMat[l][NonZeroCount] = target;
NonZeroCount++;
}
} // for k1
// The last element to stop the array
startTmp.push_back(NonZeroCount);
const int startTmp_size = startTmp.size();
LP_nStartIndex2[l] = startTmp_size-1; // the last is the stopper
NewArray(LP_startIndex2[l], int, startTmp_size);
for (int index1 = 0; index1 < startTmp_size; ++index1) {
LP_startIndex2[l][index1] = startTmp[index1];
}
} //for l lth block
}
void Newton::make_aggrigateIndex(InputData& inputData)
{
make_aggrigateIndex_SDP(inputData);
make_aggrigateIndex_LP(inputData);
}
void Newton::setNumThreads(FILE* Display, FILE* fpOut, int NumThreads)
{
if (NumThreads == 0) { // Automatic from OMP_NUM_THREADS
char* env1 = NULL;
env1 = getenv("OMP_NUM_THREADS");
if (env1 != NULL) {
NUM_THREADS = atoi(env1);
if (NUM_THREADS < 0) {
rError("OMP_NUM_THREADS is negative!!");
}
}
else {
NUM_THREADS = 1;
}
}
else {
NUM_THREADS = NumThreads;
}
if (Display) {
fprintf(Display,"NumThreads is set as %d\n", NUM_THREADS);
}
if (fpOut) {
fprintf(fpOut, "NumThreads is set as %d\n", NUM_THREADS);
}
// This affects for only OpenBLAS
blas_set_num_threads(NUM_THREADS);
}
void Newton::compute_bMatgVec_dense(InputData& inputData,
Solutions& currentPt,
Residuals& currentRes,
AverageComplementarity& mu,
DirectionParameter& beta,
Phase& phase,
ComputeTime& com)
{
const int m = currentPt.mDim;
const int LP_nBlock = inputData.LP_nBlock;
const double target_mu = beta.value * mu.current;
// rMessage("mu.current = " << mu.current);
// rMessage("target_mu = " << target_mu);
CholmodSpace& cholmodSpace = currentPt.cholmodSpace;
// rMessage("cholmodSpace = "); cholmodSpace.display();
TimeStart(LP_START);
for (int l=0; l<LP_nBlock; ++l) {
const double xMat = cholmodSpace.LP_X[l];
const double invzMat = cholmodSpace.LP_invZ[l];
const double rD = cholmodSpace.LP_rD[l];
for (int k1=0; k1<inputData.LP_nConstraint[l]; k1++) {
const int j = inputData.LP_constraint[l][k1];
const int jb = inputData.LP_blockIndex[l][k1];
const double Aj = inputData.A[j].LP_sp_block[jb];
const double xMatInvzMatAj = xMat * invzMat * Aj;
for (int k2=k1; k2<inputData.LP_nConstraint[l]; k2++) {
int i = inputData.LP_constraint[l][k2];
int ib = inputData.LP_blockIndex[l][k2];
double Ai = inputData.A[i].LP_sp_block[ib];
double value = xMatInvzMatAj * Ai;
// only lower triangular will be computed
// rMessage("add to (" << i << " , " << j << ")");
bMat.de_ele[i+m*j] += value;
} // end of 'for (int i)'
double gadd = 0.0;
if (phase.value == SolveInfo:: pFEAS
|| phase.value == SolveInfo::noINFO) {
gadd = xMat * rD;
}
gVec.ele[j] += Aj * invzMat * (gadd - target_mu);
} // end of 'for (int j)'
} // end of 'for (int l)'
TimeEnd(LP_END);
com.B_DIAG += TimeCal(LP_START, LP_END);
TimeStart(SDP_START);
const int SDP_nBlock = inputData.SDP_nBlock;
for (int l=0; l<SDP_nBlock; ++l) {
CholmodMatrix& cholmodMatrix = cholmodSpace.SDP_block[l];
for (int k1=0; k1<inputData.SDP_nConstraint[l]; k1++) {
int j = inputData.SDP_constraint[l][k1];
int jb = inputData.SDP_blockIndex[l][k1];
// rMessage("j = " << j << " : jb = " << jb);
CompMatrix& Aj = inputData.A[j].SDP_sp_block[jb];
const int nCol = Aj.nzColumn;
double gj1 = 0.0;
double gj2 = 0.0;
for (int k_index = 0; k_index < nCol; ++k_index) {
const int k = Aj.column_index[k_index];
// rMessage("k = " << k << ", k_index = " << k_index);
// rMessage("j = " << j << " : jb = " << jb);
cholmodMatrix.setB_Zzero();
double* b_z = (double*)(cholmodMatrix.b_z->x);
const int i_start = Aj.column_start[k_index];
const int i_end = Aj.column_start[k_index+1];
for (int i_index = i_start; i_index < i_end; ++i_index) {
const int i2 = Aj.row_index[i_index];
b_z[i2] = Aj.ele[i_index];
}
cholmodMatrix.solveByZ();
cholmodMatrix.setB_Xzero();
double* b_x = (double*)(cholmodMatrix.b_x->x);
b_x[k] = 1.0;
cholmodMatrix.solveByX();
double* x_z = (double*)(cholmodMatrix.x_z->x);
double* x_x = (double*)(cholmodMatrix.x_x->x);
#if 0
rMessage("Aj = "); Aj.display();
rMessage(" b_x = ");
CholmodMatrix::display_dense(cholmodMatrix.b_x);
rMessage(" x_x = ");
CholmodMatrix::display_dense(cholmodMatrix.x_x);
rMessage(" b_z = ");
CholmodMatrix::display_dense(cholmodMatrix.b_z);
rMessage(" x_z = ");
CholmodMatrix::display_dense(cholmodMatrix.x_z);
// rMessage(" rD = ");
// CholmodMatrix::display_sparse(cholmodMatrix.rD);
#endif
double gadd = 0.0;
if (phase.value == SolveInfo:: pFEAS
|| phase.value == SolveInfo::noINFO) {
Lal::getInnerProduct(gadd, cholmodMatrix.rD, x_x, x_z);
}
// rMessage("gj1 = " << gadd << " : gj2 = " << x_z[k] << " : k = " << k);
gj1 += gadd;
gj2 += x_z[k];
for (int k2=k1; k2<inputData.SDP_nConstraint[l]; k2++) {
int i = inputData.SDP_constraint[l][k2];
int ib = inputData.SDP_blockIndex[l][k2];
CompMatrix& Ai = inputData.A[i].SDP_sp_block[ib];
double Badd = 0.0;
Lal::getInnerProduct(Badd, Ai, x_x, x_z);
bMat.de_ele[i+j*m] += Badd;
#if 0
rMessage("i=" << i << ", j=" << j
<< ", k=" << k << ", Badd=" << Badd );
rMessage(" b_x = ");
CholmodMatrix::display_dense(cholmodMatrix.b_x);
rMessage(" x_x = ");
CholmodMatrix::display_dense(cholmodMatrix.x_x);
rMessage(" b_z = ");
CholmodMatrix::display_dense(cholmodMatrix.b_z);
rMessage(" x_z = ");
CholmodMatrix::display_dense(cholmodMatrix.x_z);
rMessage(" Ai = "); Ai.display();
#endif
}
} // end of 'for (int k_index = 0; k_index < nCol; ++k_index)'
// rMessage("target_mu = " << target_mu);
gVec.ele[j] += (gj1 - target_mu * gj2);
} // end of 'for (int k1)'
} // end of 'for (int l)'
TimeEnd(SDP_END);
com.B_F2 += TimeCal(SDP_START, SDP_END);
}
void Newton::compute_bMatgVec_dense_threads(InputData& inputData,
Solutions& currentPt,
Residuals& currentRes,
AverageComplementarity& mu,
DirectionParameter& beta,
Phase& phase,
ComputeTime& com)
{
const int m = currentPt.mDim;
const int LP_nBlock = inputData.LP_nBlock;
const double target_mu = beta.value * mu.current;
// rMessage("mu.current = " << mu.current);
// rMessage("target_mu = " << target_mu);
CholmodSpace& cholmodSpace = currentPt.cholmodSpace;
// rMessage("cholmodSpace = "); cholmodSpace.display();
TimeStart(LP_START);
for (int l=0; l<LP_nBlock; ++l) {
const double xMat = cholmodSpace.LP_X[l];
const double invzMat = cholmodSpace.LP_invZ[l];
const double rD = cholmodSpace.LP_rD[l];
for (int k1=0; k1<inputData.LP_nConstraint[l]; k1++) {
const int j = inputData.LP_constraint[l][k1];
const int jb = inputData.LP_blockIndex[l][k1];
const double Aj = inputData.A[j].LP_sp_block[jb];
const double xMatInvzMatAj = xMat * invzMat * Aj;
for (int k2=k1; k2<inputData.LP_nConstraint[l]; k2++) {
int i = inputData.LP_constraint[l][k2];
int ib = inputData.LP_blockIndex[l][k2];
double Ai = inputData.A[i].LP_sp_block[ib];
double value = xMatInvzMatAj * Ai;
// only lower triangular will be computed
// rMessage("add to (" << i << " , " << j << ")");
bMat.de_ele[i+m*j] += value;
} // end of 'for (int i)'
double gadd = 0.0;
if (phase.value == SolveInfo:: pFEAS
|| phase.value == SolveInfo::noINFO) {
gadd = xMat * rD;
}
gVec.ele[j] += Aj * invzMat * (gadd - target_mu);
} // end of 'for (int j)'
} // end of 'for (int l)'
TimeEnd(LP_END);
com.B_DIAG += TimeCal(LP_START, LP_END);
TimeStart(SDP_START);
const int SDP_nBlock = inputData.SDP_nBlock;
// To improve CHOLMOD performance, turn off BLAS parallel
blas_set_num_threads(1);
int ret;
ret = pthread_mutex_init(&job_mutex, NULL);
if (ret != 0) {
rError("pthread_mutex_init error");
}
pthread_t* handle;
NewArray(handle, pthread_t, NUM_THREADS);
thread_arg_t* targ;
NewArray(targ, thread_arg_t, NUM_THREADS);
for (int thread_num = 0; thread_num < NUM_THREADS; ++thread_num) {
targ[thread_num].m = m;
targ[thread_num].target_mu = target_mu;
targ[thread_num].thread_num = thread_num;
targ[thread_num].addr_inputData = &inputData;
targ[thread_num].addr_bMat = &bMat;
targ[thread_num].addr_gVec = &gVec;
targ[thread_num].addr_phase = &phase;
}
for (int l=0; l<SDP_nBlock; ++l) {
CholmodMatrix& cholmodMatrix = cholmodSpace.SDP_block[l];
Column_Number = 0;
for (int thread_num = 0; thread_num < NUM_THREADS; ++ thread_num) {
targ[thread_num].l = l;
targ[thread_num].addr_cholmodMatrix = &cholmodMatrix;
pthread_create(&handle[thread_num], NULL,
compute_bMatgVec_dense_threads_SDP,
(void *)&targ[thread_num]);
}
for (int thread_num = 0; thread_num < NUM_THREADS; ++ thread_num) {
pthread_join(handle[thread_num], NULL);
}
}
DeleteArray(handle);
DeleteArray(targ);
ret = pthread_mutex_destroy(&job_mutex);
if (ret != 0) {
rError("pthread_mutex_destroy error in sdpa_newton.cpp");
}
blas_set_num_threads(NUM_THREADS);
TimeEnd(SDP_END);
com.B_F2 += TimeCal(SDP_START, SDP_END);
}
void* Newton::compute_bMatgVec_dense_threads_SDP(void* arg)
{
thread_arg_t* targ = (thread_arg_t*) arg;
const int l = targ->l;
const int m = targ->m;
const double target_mu = targ->target_mu;
const int thread_num = targ->thread_num;
InputData& inputData = *(targ->addr_inputData);
CholmodMatrix& cholmodMatrix = *(targ->addr_cholmodMatrix);
DenseMatrix& bMat = *(targ->addr_bMat);
Vector& gVec = *(targ->addr_gVec);
Phase& phase = *(targ->addr_phase);
CompSpace* A = inputData.A;
const int nDim = cholmodMatrix.nDim;
cholmod_common& common = cholmodMatrix.common;
const int SDP_nConstraintl = inputData.SDP_nConstraint[l];
int* SDP_constraintl = inputData.SDP_constraint[l];
int* SDP_blockIndexl = inputData.SDP_blockIndex[l];
// for multi-threads computing work space
cholmod_dense* b_x1;
cholmod_dense* b_z1;
b_x1 = cholmod_allocate_dense(nDim,1,nDim,CHOLMOD_REAL,
&common);
b_z1 = cholmod_allocate_dense(nDim,1,nDim,CHOLMOD_REAL,
&common);
double* b_x = (double*)(b_x1->x);
double* b_z = (double*)(b_z1->x);
cholmod_factor* Lz = cholmodMatrix.Lz;
cholmod_factor* Lx = cholmodMatrix.Lx;
int k1 = 0; // dummy initialize
while (1) {
pthread_mutex_lock(&job_mutex);
k1 = Column_Number;
Column_Number++;
pthread_mutex_unlock(&job_mutex);
if (k1>=SDP_nConstraintl) {
break;
}
int j = SDP_constraintl[k1];
int jb = SDP_blockIndexl[k1];
// rMessage("j = " << j << " : jb = " << jb);
CompMatrix& Aj = A[j].SDP_sp_block[jb];
const int nCol = Aj.nzColumn;
double gj1 = 0.0;
double gj2 = 0.0;
for (int k_index = 0; k_index < nCol; ++k_index) {
const int k = Aj.column_index[k_index];
// rMessage("k = " << k << ", k_index = " << k_index);
// rMessage("j = " << j << " : jb = " << jb);
for (int index1=0;index1 < nDim; ++index1) {
b_z[index1] = 0.0;
}
const int i_start = Aj.column_start[k_index];
const int i_end = Aj.column_start[k_index+1];
for (int i_index = i_start; i_index < i_end; ++i_index) {
const int i2 = Aj.row_index[i_index];
b_z[i2] = Aj.ele[i_index];
}
cholmod_dense* b2 = cholmod_solve(CHOLMOD_P, Lz, b_z1, &common);
cholmod_dense* x_z2 = cholmod_solve(CHOLMOD_LDLt, Lz, b2, &common);
cholmod_dense* x_z1 = cholmod_solve(CHOLMOD_Pt, Lz, x_z2, &common);
double* x_z = (double*)(x_z1->x);
for (int index1=0;index1 < nDim; ++index1) {
b_x[index1] = 0.0;
}
b_x[k] = 1.0;
cholmod_dense* b_x2 = cholmod_solve(CHOLMOD_P, Lx, b_x1, &common);
cholmod_dense* x_x3 = cholmod_solve(CHOLMOD_L, Lx, b_x2, &common);
cholmod_dense* x_x2 = cholmod_solve(CHOLMOD_Lt,Lx, x_x3, &common);
cholmod_dense* x_x1 = cholmod_solve(CHOLMOD_Pt, Lx, x_x2, &common);
double* x_x = (double*)(x_x1->x);
#if 0
rMessage("Aj = "); Aj.display();
rMessage(" b_x = ");
CholmodMatrix::display_dense(cholmodMatrix.b_x1);
rMessage(" x_x = ");
CholmodMatrix::display_dense(cholmodMatrix.x_x1);
rMessage(" b_z = ");
CholmodMatrix::display_dense(cholmodMatrix.b_z1);
rMessage(" x_z = ");
CholmodMatrix::display_dense(cholmodMatrix.x_z1);
// rMessage(" rD = ");
// CholmodMatrix::display_sparse(cholmodMatrix.rD);
#endif
double gadd = 0.0;
if (phase.value == SolveInfo::pFEAS
|| phase.value == SolveInfo::noINFO) {
Lal::getInnerProduct(gadd, cholmodMatrix.rD, x_x, x_z);
}
// rMessage("gj1 = " << gadd << " : gj2 = " << x_z[k] << " : k = " << k);
gj1 += gadd;
gj2 += x_z[k];
for (int k2=k1; k2<inputData.SDP_nConstraint[l]; k2++) {
int i = SDP_constraintl[k2];
int ib = SDP_blockIndexl[k2];
CompMatrix& Ai = A[i].SDP_sp_block[ib];
double Badd = 0.0;
Lal::getInnerProduct(Badd, Ai, x_x, x_z);
bMat.de_ele[i+j*m] += Badd;
#if 0
rMessage("i=" << i << ", j=" << j
<< ", k=" << k << ", Badd=" << Badd );
rMessage(" b_x = ");
CholmodMatrix::display_dense(cholmodMatrix.b_x1);
rMessage(" x_x = ");
CholmodMatrix::display_dense(cholmodMatrix.x_x1);
rMessage(" b_z = ");
CholmodMatrix::display_dense(cholmodMatrix.b_z1);
rMessage(" x_z = ");
CholmodMatrix::display_dense(cholmodMatrix.x_z1);
rMessage(" Ai = "); Ai.display();
#endif
}
cholmod_free_dense(&b2,&common);
cholmod_free_dense(&x_z2,&common);
cholmod_free_dense(&b_x2,&common);
cholmod_free_dense(&x_x3,&common);
cholmod_free_dense(&x_x2,&common);
cholmod_free_dense(&x_x1,&common);
cholmod_free_dense(&x_z1,&common);
} // end of 'for (int k_index = 0; k_index < nCol; ++k_index)'
// rMessage("target_mu = " << target_mu);
gVec.ele[j] += (gj1 - target_mu * gj2);
} // end of 'for (int k1)'
cholmod_free_dense(&b_x1,&common);
cholmod_free_dense(&b_z1,&common);
}
void Newton::compute_bMatgVec_sparse(InputData& inputData,
Solutions& currentPt,
Residuals& currentRes,
AverageComplementarity& mu,
DirectionParameter& beta,
Phase& phase,
ComputeTime& com)
{
const int m = currentPt.mDim;
const int LP_nBlock = inputData.LP_nBlock;
const double target_mu = beta.value * mu.current;
CholmodSpace& cholmodSpace = currentPt.cholmodSpace;
TimeStart(LP_START);
for (int l=0; l<LP_nBlock; ++l) {
const double xMat = cholmodSpace.LP_X[l];
const double invzMat = cholmodSpace.LP_invZ[l];
const double rD = cholmodSpace.LP_rD[l];
for (int index2 = 0; index2 < LP_nStartIndex2[l]; ++index2) {
const int start_iter = LP_startIndex2[l][index2];
const int end_iter = LP_startIndex2[l][index2+1];
const int j = LP_constraint2[l][start_iter];
const int jb = LP_blockIndex2[l][start_iter];
const double Aj = inputData.A[j].LP_sp_block[jb];
gVec.ele[j] += Aj * invzMat * ( xMat * rD - target_mu);
for (int iter = start_iter; iter < end_iter; ++iter) {
const int i = LP_constraint1[l][iter];
const int ib = LP_blockIndex1[l][iter];
const double Ai = inputData.A[i].LP_sp_block[ib];
const double value = xMat * invzMat * Ai * Aj;
sparse_bMat.sp_ele[LP_location_sparse_bMat[l][iter]] += value;
}
} // end of 'for (int start_iter)'
} // end of 'for (int l)'
TimeEnd(LP_END);
com.B_DIAG += TimeCal(LP_START, LP_END);
TimeStart(SDP_START);
const int SDP_nBlock = inputData.SDP_nBlock;
for (int l=0; l<SDP_nBlock; ++l) {
CholmodMatrix& cholmodMatrix = cholmodSpace.SDP_block[l];
for (int index2 = 0; index2 < SDP_nStartIndex2[l]; ++index2) {
const int start_iter = SDP_startIndex2[l][index2];
const int end_iter = SDP_startIndex2[l][index2+1];
int j = SDP_constraint2[l][start_iter];
int jb = SDP_blockIndex2[l][start_iter];
CompMatrix& Aj = inputData.A[j].SDP_sp_block[jb];
const int nCol = Aj.nzColumn;
double gj1 = 0.0;
double gj2 = 0.0;
for (int k_index = 0; k_index < nCol; ++k_index) {
const int k = Aj.column_index[k_index];
cholmodMatrix.setB_Zzero();
double* b_z = (double*)(cholmodMatrix.b_z->x);
const int i_start = Aj.column_start[k_index];
const int i_end = Aj.column_start[k_index+1];
for (int i_index = i_start; i_index < i_end; ++i_index) {
const int i2 = Aj.row_index[i_index];
b_z[i2] = Aj.ele[i_index];
}
cholmodMatrix.solveByZ();
cholmodMatrix.setB_Xzero();
double* b_x = (double*)(cholmodMatrix.b_x->x);
b_x[k] = 1.0;
cholmodMatrix.solveByX();
double* x_z = (double*)(cholmodMatrix.x_z->x);
double* x_x = (double*)(cholmodMatrix.x_x->x);
#if 0
rMessage(" x_x = ");
CholmodMatrix::display_dense(cholmodMatrix.x_x);
rMessage(" x_z = ");
CholmodMatrix::display_dense(cholmodMatrix.x_z);
rMessage(" rD = ");
CholmodMatrix::display_sparse(cholmodMatrix.rD);
#endif
double gadd = 0.0;
if (phase.value == SolveInfo:: pFEAS
|| phase.value == SolveInfo::noINFO) {
Lal::getInnerProduct(gadd, cholmodMatrix.rD, x_x, x_z);
// rMessage("gj1 = " << gadd << " : gj2 = " << x_z[k] << " : k = " << k);
}
gj1 += gadd;
gj2 += x_z[k];
for (int iter = start_iter; iter < end_iter; ++iter) {
int i = SDP_constraint1[l][iter];
int ib = SDP_blockIndex1[l][iter];
CompMatrix& Ai = inputData.A[i].SDP_sp_block[ib];
double Badd = 0.0;
Lal::getInnerProduct(Badd, Ai, x_x, x_z);
sparse_bMat.sp_ele[SDP_location_sparse_bMat[l][iter]] += Badd;
}
} // end of 'for (int k_index)'
gVec.ele[j] += (gj1 - target_mu * gj2);
} // end of 'for (int j)'
}
TimeEnd(SDP_END);
com.B_F2 += TimeCal(SDP_START, SDP_END);
}
void Newton::compute_bMatgVec_sparse_threads(InputData& inputData,
Solutions& currentPt,
Residuals& currentRes,
AverageComplementarity& mu,
DirectionParameter& beta,
Phase& phase,
ComputeTime& com)
{
const int m = currentPt.mDim;
const int LP_nBlock = inputData.LP_nBlock;
const double target_mu = beta.value * mu.current;
CholmodSpace& cholmodSpace = currentPt.cholmodSpace;
TimeStart(LP_START);
for (int l=0; l<LP_nBlock; ++l) {
const double xMat = cholmodSpace.LP_X[l];
const double invzMat = cholmodSpace.LP_invZ[l];
const double rD = cholmodSpace.LP_rD[l];
for (int index2 = 0; index2 < LP_nStartIndex2[l]; ++index2) {
const int start_iter = LP_startIndex2[l][index2];
const int end_iter = LP_startIndex2[l][index2+1];
const int j = LP_constraint2[l][start_iter];
const int jb = LP_blockIndex2[l][start_iter];
const double Aj = inputData.A[j].LP_sp_block[jb];
gVec.ele[j] += Aj * invzMat * ( xMat * rD - target_mu);
for (int iter = start_iter; iter < end_iter; ++iter) {
const int i = LP_constraint1[l][iter];
const int ib = LP_blockIndex1[l][iter];
const double Ai = inputData.A[i].LP_sp_block[ib];
const double value = xMat * invzMat * Ai * Aj;
sparse_bMat.sp_ele[LP_location_sparse_bMat[l][iter]] += value;
}
} // end of 'for (int start_iter)'
} // end of 'for (int l)'
TimeEnd(LP_END);
com.B_DIAG += TimeCal(LP_START, LP_END);
TimeStart(SDP_START);
const int SDP_nBlock = inputData.SDP_nBlock;
// To improve CHOLMOD performance, turn off BLAS parallel
blas_set_num_threads(1);
int ret;
ret = pthread_mutex_init(&job_mutex, NULL);
if (ret != 0) {
rError("pthread_mutex_init error");
}
pthread_t* handle;
NewArray(handle, pthread_t, NUM_THREADS);
thread_arg_s* targ;
NewArray(targ, thread_arg_s, NUM_THREADS);
for (int thread_num = 0; thread_num < NUM_THREADS; ++thread_num) {
targ[thread_num].m = m;
targ[thread_num].target_mu = target_mu;
targ[thread_num].thread_num = thread_num;
targ[thread_num].addr_inputData = &inputData;
targ[thread_num].addr_sparse_bMat = &sparse_bMat;
targ[thread_num].addr_gVec = &gVec;
targ[thread_num].addr_phase = &phase;
targ[thread_num].addr_newton = this;
}
for (int l=0; l<SDP_nBlock; ++l) {
CholmodMatrix& cholmodMatrix = cholmodSpace.SDP_block[l];
Column_Number = 0;
for (int thread_num = 0; thread_num < NUM_THREADS; ++ thread_num) {
targ[thread_num].l = l;
targ[thread_num].addr_cholmodMatrix = &cholmodMatrix;
pthread_create(&handle[thread_num], NULL,
compute_bMatgVec_sparse_threads_SDP,
(void *)&targ[thread_num]);
}
for (int thread_num = 0; thread_num < NUM_THREADS; ++ thread_num) {
pthread_join(handle[thread_num], NULL);
}
}
DeleteArray(handle);
DeleteArray(targ);
ret = pthread_mutex_destroy(&job_mutex);
if (ret != 0) {
rError("pthread_mutex_destroy error in sdpa_newton.cpp");
}
blas_set_num_threads(NUM_THREADS);
TimeEnd(SDP_END);
com.B_F2 += TimeCal(SDP_START, SDP_END);
}
void* Newton::compute_bMatgVec_sparse_threads_SDP(void* arg)
{
thread_arg_s* targ = (thread_arg_s*) arg;
const int l = targ->l;
const int m = targ->m;
const double target_mu = targ->target_mu;
const int thread_num = targ->thread_num;
InputData& inputData = *(targ->addr_inputData);
CholmodMatrix& cholmodMatrix = *(targ->addr_cholmodMatrix);
SparseMatrix& sparse_bMat = *(targ->addr_sparse_bMat);
Vector& gVec = *(targ->addr_gVec);
Phase& phase = *(targ->addr_phase);
Newton& newton = *(targ->addr_newton);
CompSpace* A = inputData.A;
const int nDim = cholmodMatrix.nDim;
cholmod_common& common = cholmodMatrix.common;
int* SDP_constraint1l = newton.SDP_constraint1[l];
int* SDP_blockIndex1l = newton.SDP_blockIndex1[l];
int* SDP_constraint2l = newton.SDP_constraint2[l];
int* SDP_blockIndex2l = newton.SDP_blockIndex2[l];
int* SDP_startIndex2l = newton.SDP_startIndex2[l];
const int SDP_nStartIndex2l = newton.SDP_nStartIndex2[l];
int* SDP_location_sparse_bMatl = newton.SDP_location_sparse_bMat[l];
// for multi-threads computing work space
cholmod_dense* b_x1;
cholmod_dense* b_z1;
b_x1 = cholmod_allocate_dense(nDim,1,nDim,CHOLMOD_REAL,
&common);
b_z1 = cholmod_allocate_dense(nDim,1,nDim,CHOLMOD_REAL,
&common);
double* b_x = (double*)(b_x1->x);
double* b_z = (double*)(b_z1->x);
cholmod_factor* Lz = cholmodMatrix.Lz;
cholmod_factor* Lx = cholmodMatrix.Lx;
int index2 = 0; // dummy initialize
while (1) {
pthread_mutex_lock(&job_mutex);
index2 = Column_Number++;
pthread_mutex_unlock(&job_mutex);
if (index2 >= SDP_nStartIndex2l) {
break;
}
const int start_iter = SDP_startIndex2l[index2];
const int end_iter = SDP_startIndex2l[index2+1];
int j = SDP_constraint2l[start_iter];
int jb = SDP_blockIndex2l[start_iter];
CompMatrix& Aj = A[j].SDP_sp_block[jb];
const int nCol = Aj.nzColumn;
double gj1 = 0.0;
double gj2 = 0.0;
for (int k_index = 0; k_index < nCol; ++k_index) {
const int k = Aj.column_index[k_index];
for (int index1=0;index1 < nDim; ++index1) {
b_z[index1] = 0.0;
}
const int i_start = Aj.column_start[k_index];
const int i_end = Aj.column_start[k_index+1];
for (int i_index = i_start; i_index < i_end; ++i_index) {
const int i2 = Aj.row_index[i_index];
b_z[i2] = Aj.ele[i_index];
}
cholmod_dense* b2 = cholmod_solve(CHOLMOD_P, Lz, b_z1, &common);
cholmod_dense* x_z2 = cholmod_solve(CHOLMOD_LDLt, Lz, b2, &common);
cholmod_dense* x_z1 = cholmod_solve(CHOLMOD_Pt, Lz, x_z2, &common);
double* x_z = (double*)(x_z1->x);
for (int index1=0;index1 < nDim; ++index1) {
b_x[index1] = 0.0;
}
b_x[k] = 1.0;
cholmod_dense* b_x2 = cholmod_solve(CHOLMOD_P, Lx, b_x1, &common);
cholmod_dense* x_x3 = cholmod_solve(CHOLMOD_L, Lx, b_x2, &common);
cholmod_dense* x_x2 = cholmod_solve(CHOLMOD_Lt,Lx, x_x3, &common);
cholmod_dense* x_x1 = cholmod_solve(CHOLMOD_Pt, Lx, x_x2, &common);
double* x_x = (double*)(x_x1->x);
#if 0
rMessage(" x_x = ");
CholmodMatrix::display_dense(cholmodMatrix.x_x);
rMessage(" x_z = ");
CholmodMatrix::display_dense(cholmodMatrix.x_z);
rMessage(" rD = ");
CholmodMatrix::display_sparse(cholmodMatrix.rD);
#endif
double gadd = 0.0;
if (phase.value == SolveInfo:: pFEAS
|| phase.value == SolveInfo::noINFO) {
Lal::getInnerProduct(gadd, cholmodMatrix.rD, x_x, x_z);
// rMessage("gj1 = " << gadd << " : gj2 = " << x_z[k] << " : k = " << k);
}
gj1 += gadd;
gj2 += x_z[k];
for (int iter = start_iter; iter < end_iter; ++iter) {
int i = SDP_constraint1l[iter];
int ib = SDP_blockIndex1l[iter];
CompMatrix& Ai = A[i].SDP_sp_block[ib];
double Badd = 0.0;
Lal::getInnerProduct(Badd, Ai, x_x, x_z);
sparse_bMat.sp_ele[SDP_location_sparse_bMatl[iter]] += Badd;
}
cholmod_free_dense(&b2,&common);
cholmod_free_dense(&x_z2,&common);
cholmod_free_dense(&b_x2,&common);
cholmod_free_dense(&x_x3,&common);
cholmod_free_dense(&x_x2,&common);
cholmod_free_dense(&x_x1,&common);
cholmod_free_dense(&x_z1,&common);
} // end of 'for (int k_index)'
gVec.ele[j] += (gj1 - target_mu * gj2);
} // end of 'for (int index2, aka j)'
cholmod_free_dense(&b_x1,&common);
cholmod_free_dense(&b_z1,&common);
}
void Newton::Make_bMatgVec(InputData& inputData,
Solutions& currentPt,
Residuals& currentRes,
AverageComplementarity& mu,
DirectionParameter& beta,
Phase& phase,
ComputeTime& com)
{
TimeStart(START3);
gVec.copyFrom(inputData.b);
if (bMat_type == SPARSE){
// set sparse_bMat zero
sdpa_dset(sparse_bMat.NonZeroCount, 0.0, sparse_bMat.sp_ele, 1);
#if 0
compute_bMatgVec_sparse(inputData, currentPt, currentRes, mu, beta,
phase, com);
#else
compute_bMatgVec_sparse_threads(inputData, currentPt, currentRes, mu, beta,
phase, com);
#endif
} else {
bMat.setZero();
#if 0
compute_bMatgVec_dense(inputData, currentPt, currentRes, mu, beta,
phase, com);
#else
compute_bMatgVec_dense_threads(inputData, currentPt, currentRes, mu, beta,
phase, com);
#endif
}
#if 0
// display_index();
rMessage("bMat = ");
if (bMat_type == DENSE) {
bMat.display();
}
else {
sparse_bMat.display();
}
rMessage("gVec = ");
gVec.display();
#endif
TimeEnd(END3);
com.makebMatgVec += TimeCal(START3,END3);
}
bool Newton::compute_DyVec(Newton::WHICH_DIRECTION direction,
int m,
InputData& inputData,
Chordal& chordal,
Solutions& currentPt,
ComputeTime& com,
FILE* Display, FILE* fpOut)
{
if (direction == PREDICTOR) {
TimeStart(START3_2);
if (bMat_type == SPARSE){
bool ret = chordal.factorizeSchur(m, diagonalIndex, Display, fpOut);
if (ret == SDPA_FAILURE) {
return SDPA_FAILURE;
}
} else {
bool ret = Lal::choleskyFactorWithAdjust(bMat);
if (ret == SDPA_FAILURE) {
return SDPA_FAILURE;
}
}
// rMessage("Cholesky of bMat = ");
// bMat.display();
// sparse_bMat.display();
TimeEnd(END3_2);
com.choleskybMat += TimeCal(START3_2,END3_2);
}
// bMat is already cholesky factorized.
Vector& DyVec = currentPt.cholmodSpace.dyVec;
TimeStart(START4);
if (bMat_type == SPARSE){
DyVec.copyFrom(gVec);
chordal.solveSchur(DyVec);
} else {
Lal::let(DyVec,'=',bMat,'/',gVec);
}
TimeEnd(END4);
com.solve += TimeCal(START4,END4);
// rMessage("DyVec = ");
// DyVec.display();
return SDPA_SUCCESS;
}
void Newton::compute_DzMat(InputData& inputData,
Solutions& currentPt,
Residuals& currentRes,
Phase& phase,
ComputeTime& com)
{
TimeStart(START_SUMDZ);
CholmodSpace& cholmodSpace = currentPt.cholmodSpace;
CompSpace* A = inputData.A;
for (int l=0; l<cholmodSpace.LP_nBlock; ++l) {
cholmodSpace.LP_dZ[l] = 0.0;
}
for (int l=0; l<cholmodSpace.SDP_nBlock; ++l) {
cholmod_sparse* dZ = cholmodSpace.SDP_block[l].dZ;
const int length = dZ->nzmax;
for (int index1 = 0; index1 < length; ++index1) {
((double*)(dZ->x))[index1] = 0.0;
}
}
const int m = cholmodSpace.dyVec.nDim;
for (int k=0; k<m; ++k) {
const double dyk = cholmodSpace.dyVec.ele[k];
for (int l_index=0; l_index < A[k].LP_sp_nBlock; ++l_index) {
const int l = A[k].LP_sp_index[l_index];
const double value = A[k].LP_sp_block[l_index];
cholmodSpace.LP_dZ[l] -= dyk * value;
}
for (int l_index=0; l_index < A[k].SDP_sp_nBlock; ++l_index) {
const int l = A[k].SDP_sp_index[l_index];
CompMatrix& Akl = A[k].SDP_sp_block[l_index];
cholmod_sparse* dZ = cholmodSpace.SDP_block[l].dZ;
for (int j_index = 0; j_index<Akl.nzColumn; ++j_index) {
const int row_start = Akl.diag_index[j_index];
const int row_end = Akl.column_start[j_index+1];
if (row_start == -1) {
continue;
}
for (int i = row_start; i < row_end; ++i) {
const int agg_index = Akl.agg_index[i];
((double*)(dZ->x))[agg_index] -= Akl.ele[i]*dyk;
}
}
}
} // end of 'for (int k=0; k<m; ++k)'
if (phase.value == SolveInfo:: pFEAS
|| phase.value == SolveInfo::noINFO) {
for (int l=0; l<cholmodSpace.LP_nBlock; ++l) {
cholmodSpace.LP_dZ[l] += cholmodSpace.LP_rD[l];
}
for (int l=0; l<cholmodSpace.SDP_nBlock; ++l) {
cholmod_sparse* dZ = cholmodSpace.SDP_block[l].dZ;
cholmod_sparse* rD = cholmodSpace.SDP_block[l].rD;
const int length = dZ->nzmax;
for (int index1 = 0; index1 < length; ++index1) {
((double*)(dZ->x))[index1] += ((double*)(rD->x))[index1];
}
}
}
TimeEnd(END_SUMDZ);
com.sumDz += TimeCal(START_SUMDZ,END_SUMDZ);
}
void Newton::compute_DxMat(Solutions& currentPt,
AverageComplementarity& mu,
DirectionParameter& beta,
ComputeTime& com)
{
TimeStart(START_DX);
CholmodSpace& cholmodSpace = currentPt.cholmodSpace;
OrderingSpace& orderingSpace = currentPt.order;
const double target_mu = beta.value * mu.current;
for (int l=0; l<cholmodSpace.LP_nBlock; ++l) {
cholmodSpace.LP_dX[l] = target_mu * cholmodSpace.LP_invZ[l]
- cholmodSpace.LP_X[l]
- cholmodSpace.LP_X[l] * cholmodSpace.LP_dZ[l] * cholmodSpace.LP_invZ[l];
}
for (int l=0; l<cholmodSpace.SDP_nBlock; ++l) {
OrderingMatrix& order = orderingSpace.SDP_block[l];
CholmodMatrix& cholmodMatrix = cholmodSpace.SDP_block[l];
CliqueMatrix& clique_xMat = cholmodMatrix.clique_xMat;
CliqueMatrix& clique_dX = cholmodMatrix.clique_dX;
for (int l2=0; l2<clique_xMat.nBlock; ++l2) {
Lal::multiply(clique_dX.ele[l2],clique_xMat.ele[l2],&DMONE);
}
cholmod_factor* Lz = cholmodMatrix.Lz;
cholmod_factor* Lx = cholmodMatrix.Lx;
cholmod_sparse* dZ = cholmodMatrix.dZ;
cholmod_common& common = cholmodMatrix.common;
const int nDim = cholmodMatrix.nDim;
for (int k=0; k<nDim; ++k) {
cholmodMatrix.setB_Zzero();
double* b_z = (double*)(cholmodMatrix.b_z->x);
b_z[k] = 1.0;
cholmodMatrix.solveByZ();
double* x_z = (double*)(cholmodMatrix.x_z->x);
// x_z is now Zinv[*k]
double one[2] = {1.0, 0.0};
double zero[2] = {0.0, 0.0} ;
int transpose = 0; // 0 means no transpose
double* b_x = (double*)(cholmodMatrix.b_x->x);
cholmod_sdmult(dZ, transpose, one, zero, cholmodMatrix.x_z,
cholmodMatrix.b_x, &common);
cholmodMatrix.solveByX();
double* x_x = (double*)(cholmodMatrix.x_x->x);
for (int i=0; i<nDim; ++i) {
x_x[i] = target_mu * x_z[i] + -x_x[i];
}
int dXtNonzeros = order.dXtNonzeros[k];
int* dXtIndex = order.dXtIndex[k];
int* dXtClique = order.dXtClique[k];
int* dXtBlock = order.dXtBlock[k];
for (int index1 = 0; index1 < dXtNonzeros; ++index1) {
DenseMatrix& targetMatrix = clique_dX.ele[dXtClique[index1]];
targetMatrix.de_ele[dXtBlock[index1]] += x_x[dXtIndex[index1]];
}
} // end of 'for (int k=0; k<nDim; ++k)'
} // end of 'for (int l=0; l<cholmodSpace.SDP_nBlock; ++l)'
TimeEnd(END_DX);
TimeStart(START_SYMM);
for (int l=0; l<cholmodSpace.SDP_nBlock; ++l) {
CliqueMatrix& clique_dX = cholmodSpace.SDP_block[l].clique_dX;
for (int l2=0; l2<clique_dX.nBlock; ++l2) {
Lal::getSymmetrize(clique_dX.ele[l2]);
}
}
TimeEnd(END_SYMM);
com.makedX += TimeCal(START_DX,END_DX);
com.symmetriseDx += TimeCal(START_SYMM,END_SYMM);
}
void Newton::compute_DxMat_threads(Solutions& currentPt,
AverageComplementarity& mu,
DirectionParameter& beta,
ComputeTime& com)
{
TimeStart(START_DX);
CholmodSpace& cholmodSpace = currentPt.cholmodSpace;
OrderingSpace& orderingSpace = currentPt.order;
const double target_mu = beta.value * mu.current;
for (int l=0; l<cholmodSpace.LP_nBlock; ++l) {
cholmodSpace.LP_dX[l] = target_mu * cholmodSpace.LP_invZ[l]
- cholmodSpace.LP_X[l]
- cholmodSpace.LP_X[l] * cholmodSpace.LP_dZ[l] * cholmodSpace.LP_invZ[l];
}
// To improve CHOLMOD performance, turn off BLAS parallel
blas_set_num_threads(1);
int ret;
ret = pthread_mutex_init(&job_mutex, NULL);
if (ret != 0) {
rError("pthread_mutex_init error");
}
pthread_t* handle;
NewArray(handle, pthread_t, NUM_THREADS);
thread_DX_t* tDX;
NewArray(tDX, thread_DX_t, NUM_THREADS);
for (int thread_num = 0; thread_num < NUM_THREADS; ++thread_num) {
tDX[thread_num].target_mu = target_mu;
tDX[thread_num].thread_num = thread_num;
}
for (int l=0; l<cholmodSpace.SDP_nBlock; ++l) {
OrderingMatrix& order = orderingSpace.SDP_block[l];
CholmodMatrix& cholmodMatrix = cholmodSpace.SDP_block[l];
CliqueMatrix& clique_xMat = cholmodMatrix.clique_xMat;
CliqueMatrix& clique_dX = cholmodMatrix.clique_dX;
for (int l2=0; l2<clique_xMat.nBlock; ++l2) {
Lal::multiply(clique_dX.ele[l2],clique_xMat.ele[l2],&DMONE);
}
const int nDim = cholmodMatrix.nDim;
Column_NumberDx = 0;
for (int thread_num = 0; thread_num < NUM_THREADS; ++thread_num) {
tDX[thread_num].l = l;
tDX[thread_num].addr_cholmodMatrix = &cholmodMatrix;
tDX[thread_num].addr_order = &order;
pthread_create(&handle[thread_num], NULL,
compute_DxMat_threads_SDP,
(void *)&tDX[thread_num]);
}
for (int thread_num = 0; thread_num < NUM_THREADS; ++thread_num) {
pthread_join(handle[thread_num], NULL);
}
} // end of 'for (int l=0; l<cholmodSpace.SDP_nBlock; ++l)'
DeleteArray(handle);
DeleteArray(tDX);
ret = pthread_mutex_destroy(&job_mutex);
if (ret != 0) {
rError("pthread_mutex_destroy error in sdpa_newton.cpp");
}
blas_set_num_threads(NUM_THREADS);
TimeEnd(END_DX);
TimeStart(START_SYMM);
for (int l=0; l<cholmodSpace.SDP_nBlock; ++l) {
CliqueMatrix& clique_dX = cholmodSpace.SDP_block[l].clique_dX;
for (int l2=0; l2<clique_dX.nBlock; ++l2) {
Lal::getSymmetrize(clique_dX.ele[l2]);
}
}
TimeEnd(END_SYMM);
com.makedX += TimeCal(START_DX,END_DX);
com.symmetriseDx += TimeCal(START_SYMM,END_SYMM);
}
void* Newton::compute_DxMat_threads_SDP(void* arg)
{
thread_DX_t* tDX = (thread_DX_t*) arg;
const int l = tDX->l;
const int thread_num = tDX->thread_num;
const double target_mu = tDX->target_mu;
CholmodMatrix& cholmodMatrix = *(tDX->addr_cholmodMatrix);
OrderingMatrix& order = *(tDX->addr_order);
const int nDim = cholmodMatrix.nDim;
cholmod_factor* Lz = cholmodMatrix.Lz;
cholmod_factor* Lx = cholmodMatrix.Lx;
cholmod_sparse* dZ = cholmodMatrix.dZ;
cholmod_common& common = cholmodMatrix.common;
CliqueMatrix& clique_dX = cholmodMatrix.clique_dX;
cholmod_dense* b_x1;
cholmod_dense* b_z1;
b_x1 = cholmod_allocate_dense(nDim,1,nDim,CHOLMOD_REAL,
&common);
b_z1 = cholmod_allocate_dense(nDim,1,nDim,CHOLMOD_REAL,
&common);
double* b_x = (double*)(b_x1->x);
double* b_z = (double*)(b_z1->x);
int k = 0; // dummy initialize
while (1) {
pthread_mutex_lock(&job_mutex);
k = Column_NumberDx;
Column_NumberDx++;
pthread_mutex_unlock(&job_mutex);
if (k >= nDim) {
break;
}
for (int index1=0;index1 < nDim; ++index1) {
b_z[index1] = 0.0;
}
b_z[k] = 1.0;
cholmod_dense* b2 = cholmod_solve(CHOLMOD_P, Lz, b_z1, &common);
cholmod_dense* x_z2 = cholmod_solve(CHOLMOD_LDLt, Lz, b2, &common);
cholmod_dense* x_z1 = cholmod_solve(CHOLMOD_Pt, Lz, x_z2, &common);
double* x_z = (double*)(x_z1->x);
// x_z is now Zinv[*k]
double one[2] = {1.0, 0.0};
double zero[2] = {0.0, 0.0} ;
int transpose = 0; // 0 means no transpose
cholmod_sdmult(dZ, transpose, one, zero, x_z1,
b_x1, &common);
cholmod_dense* b_x2 = cholmod_solve(CHOLMOD_P, Lx, b_x1, &common);
cholmod_dense* x_x3 = cholmod_solve(CHOLMOD_L, Lx, b_x2, &common);
cholmod_dense* x_x2 = cholmod_solve(CHOLMOD_Lt,Lx, x_x3, &common);
cholmod_dense* x_x1 = cholmod_solve(CHOLMOD_Pt, Lx, x_x2, &common);
double* x_x = (double*)(x_x1->x);
for (int i=0; i<nDim; ++i) {
x_x[i] = target_mu * x_z[i] + -x_x[i];
}
int dXtNonzeros = order.dXtNonzeros[k];
int* dXtIndex = order.dXtIndex[k];
int* dXtClique = order.dXtClique[k];
int* dXtBlock = order.dXtBlock[k];
for (int index1 = 0; index1 < dXtNonzeros; ++index1) {
DenseMatrix& targetMatrix = clique_dX.ele[dXtClique[index1]];
targetMatrix.de_ele[dXtBlock[index1]] += x_x[dXtIndex[index1]];
}
cholmod_free_dense(&b2,&common);
cholmod_free_dense(&x_z2,&common);
cholmod_free_dense(&x_z1,&common);
cholmod_free_dense(&b_x2,&common);
cholmod_free_dense(&x_x3,&common);
cholmod_free_dense(&x_x2,&common);
cholmod_free_dense(&x_x1,&common);
} // end of 'for (int k=0; k<nDim; ++k)'
cholmod_free_dense(&b_x1,&common);
cholmod_free_dense(&b_z1,&common);
}
bool Newton::Mehrotra(Newton::WHICH_DIRECTION direction,
int m,
InputData& inputData,
Chordal& chordal,
Solutions& currentPt,
Residuals& currentRes,
AverageComplementarity& mu,
DirectionParameter& beta,
Switch& reduction,
Phase& phase,
ComputeTime& com,
FILE* Display, FILE* fpOut)
{
// rMessage("BEFORE CHOLESKY"); currentPt.display();
if (direction == PREDICTOR) {
if (currentPt.cholmodSpace.getCholesky(currentPt.order) == SDPA_FAILURE) {
return SDPA_FAILURE;
}
}
// rMessage("AFTER CHOLESKY"); currentPt.display();
if (direction == PREDICTOR) {
Make_bMatgVec(inputData, currentPt, currentRes, mu,
beta, phase, com);
}
bool ret = compute_DyVec(direction,
m, inputData, chordal,
currentPt, com, Display, fpOut);
if (ret == SDPA_FAILURE) {
return SDPA_FAILURE;
}
// rMessage("dy = ");
// currentPt.cholmodSpace.dyVec.display();
compute_DzMat(inputData, currentPt, currentRes, phase, com);
TimeStart(START5);
#if 0
compute_DxMat(currentPt, mu, beta, com);
#else
compute_DxMat_threads(currentPt, mu, beta, com);
#endif
TimeEnd(END5);
com.makedXdZ += TimeCal(START5,END5);
// rMessage("After Schur currentPt"); currentPt.display();
return true;
}
void Newton::checkDirection(int m, InputData& inputData,
Solutions& currentPt,
Residuals& currentRes,
AverageComplementarity& mu,
DirectionParameter& beta,
Switch& reduction,
Phase& phase,
ComputeTime& com,
FILE* Display, FILE* fpOut)
{ // Check the direction
rMessage("Checking Directions");
CholmodSpace& cholmodSpace = currentPt.cholmodSpace;
OrderingSpace& order = currentPt.order;
CompSpace& C = inputData.C;
CompSpace* A = inputData.A;
Vector& b = inputData.b;
// Check [A \bullet (X+dX) == b]
double* rp;
NewArray(rp, double, m);
for (int k=0; k<m; ++k) {
double ip = 0.0; // dummy initialize
cholmodSpace.getInnerProductAX(ip, A[k], order);
double dip = 0.0; // dummy initialize
cholmodSpace.getInnerProductAdX(dip, A[k], order);
rp[k] = b.ele[k] - ip - dip;
}
double sum = 0.0;
for (int k=0; k<m; ++k) {
sum += rp[k]*rp[k];
}
double norm_rp = sqrt(sum);
DeleteArray(rp);
// printf("norm_dp = %e\n", norm_dp);
// Check [I == clique_invCholeskyX^T * clique_xMat * clique_invCholeskyX]
sum = 0.0;
for (int l=0; l<cholmodSpace.LP_nBlock; ++l) {
double diff = cholmodSpace.LP_X[l]*cholmodSpace.LP_invX[l] - 1.0;
sum += diff*diff;
}
for (int l=0; l<cholmodSpace.SDP_nBlock; ++l) {
CholmodMatrix& cholmodMatrix = cholmodSpace.SDP_block[l];
for (int l2=0; l2<cholmodMatrix.clique_xMat.nBlock; ++l2) {
DenseMatrix& xMat = cholmodMatrix.clique_xMat.ele[l2];
DenseMatrix& invCholeskyX = cholmodMatrix.clique_invCholeskyX.ele[l2];
DenseMatrix multi1;
multi1.initialize(xMat.nRow, xMat.nCol);
Lal::tran_multiply(multi1,invCholeskyX,xMat);
DenseMatrix multi2;
multi2.initialize(xMat.nRow, xMat.nCol);
Lal::multiply(multi2, multi1, invCholeskyX);
#if 0
rMessage("xMat = "); xMat.display();
rMessage("invCholeskyX = "); invCholeskyX.display();
rMessage("multi1 = "); multi1.display();
rMessage("multi2 = "); multi2.display();
#endif
double* ele = multi2.de_ele;
for (int i=0; i<xMat.nRow; ++i) {
ele[i+xMat.nRow*i] -= 1.0;
}
for (int i=0; i<xMat.nRow*xMat.nCol; ++i) {
sum += ele[i]*ele[i];
}
}
}
double norm_invX = sqrt(sum);
// printf("norm_invX = %e\n", norm_invX);
// Check [C - A^(y+dy) - (Z+dZ) == O]
sum = 0.0;
double* rDl;
NewArray(rDl, double, cholmodSpace.LP_nBlock);
for (int l=0; l < cholmodSpace.LP_nBlock; ++l) {
rDl[l] = 0.0;
}
for (int l_index = 0; l_index < C.LP_sp_nBlock; ++l_index) {
const int l = C.LP_sp_index[l_index];
const double value = C.LP_sp_block[l_index];
rDl[l] = value;
}
for (int k=0; k<m; ++k) {
const double yk = cholmodSpace.yVec.ele[k];
const double dyk = cholmodSpace.dyVec.ele[k];
for (int l_index = 0; l_index < A[k].LP_sp_nBlock; ++l_index) {
const int l = A[k].LP_sp_index[l_index];
const double value = A[k].LP_sp_block[l_index];
rDl[l] -= value*(yk+dyk);
}
}
for (int l=0; l<cholmodSpace.LP_nBlock; ++l) {
rDl[l] -= (cholmodSpace.LP_Z[l] + cholmodSpace.LP_dZ[l]);
}
for (int l=0; l<cholmodSpace.LP_nBlock; ++l) {
sum += rDl[l]*rDl[l];
}
cholmod_sparse** rDs;
NewArray(rDs, cholmod_sparse*, cholmodSpace.SDP_nBlock);
for (int l=0; l<cholmodSpace.SDP_nBlock; ++l) {
CholmodMatrix& cholmodMatrix = cholmodSpace.SDP_block[l];
cholmod_sparse* Z = cholmodMatrix.Z;
cholmod_sparse* dZ = cholmodMatrix.dZ;
rDs[l] = cholmod_copy_sparse(Z, &cholmodMatrix.common);
const int length = Z->nzmax;
for (int index1 = 0; index1 < length; ++index1) {
((double*)(rDs[l]->x))[index1] = -((double*)(Z->x))[index1] -((double*)(dZ->x))[index1];
}
}
for (int l_index=0; l_index < C.SDP_sp_nBlock; ++l_index) {
const int l = C.SDP_sp_index[l_index];
CompMatrix& Cl = C.SDP_sp_block[l_index];
cholmod_sparse* rD = rDs[l];
for (int j_index = 0; j_index<Cl.nzColumn; ++j_index) {
const int row_start = Cl.diag_index[j_index];
const int row_end = Cl.column_start[j_index+1];
if (row_start == -1) {
continue;
}
for (int i = row_start; i < row_end; ++i) {
int agg_index = Cl.agg_index[i];
((double*)(rD->x))[agg_index] += Cl.ele[i];
}
}
}
for (int k=0; k<m; ++k) {
const double yk = cholmodSpace.yVec.ele[k];
const double dyk = cholmodSpace.dyVec.ele[k];
for (int l_index=0; l_index < A[k].SDP_sp_nBlock; ++l_index) {
const int l = A[k].SDP_sp_index[l_index];
CompMatrix& Akl = A[k].SDP_sp_block[l_index];
cholmod_sparse* rD = rDs[l];
for (int j_index = 0; j_index<Akl.nzColumn; ++j_index) {
const int row_start = Akl.diag_index[j_index];
const int row_end = Akl.column_start[j_index+1];
if (row_start == -1) {
continue;
}
for (int i = row_start; i < row_end; ++i) {
int agg_index = Akl.agg_index[i];
((double*)(rD->x))[agg_index] -= Akl.ele[i]*(yk+dyk);
}
}
}
}
for (int l=0; l<cholmodSpace.SDP_nBlock; ++l) {
const int length = rDs[l]->nzmax;
for (int index1 = 0; index1 < length; ++index1) {
double value = ((double*)(rDs[l]->x))[index1];
sum += value*value;
}
}
for (int l=0; l<cholmodSpace.SDP_nBlock; ++l) {
cholmod_free_sparse(&rDs[l], &cholmodSpace.SDP_block[l].common);
}
DeleteArray(rDs);
double norm_rD = sqrt(sum);
// printf("norm_rD = %e\n", norm_rD);
const double target_mu = beta.value * mu.current;
// Check [(X+dX)*(dZ+Z) - mu*I == O]
sum = 0.0;
double min_X = 1.0e+50;
double min_Z = 1.0e+50;
for (int l=0; l<cholmodSpace.LP_nBlock; ++l) {
double X = cholmodSpace.LP_X[l];
double dX = cholmodSpace.LP_dX[l];
double Z = cholmodSpace.LP_Z[l];
double dZ = cholmodSpace.LP_dZ[l];
double diff = (X+dX)*(dZ+Z) - target_mu * 1;
// rMessage("diff = " << diff);
sum += diff*diff;
if (X < min_X) {
min_X = X;
}
if (Z < min_Z) {
min_Z = Z;
}
}
for (int l=0; l<cholmodSpace.SDP_nBlock; ++l) {
CholmodMatrix& cholmodMatrix = cholmodSpace.SDP_block[l];
int nDim = cholmodMatrix.nDim;
cholmod_sparse* Z = cholmodMatrix.Z;
cholmod_sparse* dZ = cholmodMatrix.dZ;
DenseMatrix D_Z;
DenseMatrix D_ZdZ;
D_Z.initialize(nDim, nDim);
D_Z.setZero();
D_ZdZ.initialize(nDim, nDim);
D_ZdZ.setZero();
DenseMatrix D_Result;
D_Result.initialize(nDim, nDim);
D_Result.setZero();
const int ncol = (int) Z->ncol;
for (int j=0; j < ncol; ++j) {
const int start_row = ((int*)Z->p)[j];
const int end_row = ((int*)Z->p)[j+1];
for (int i_index = start_row; i_index < end_row; ++i_index) {
const int i = (( int*)Z->i)[i_index];
const double value = ((double*)Z->x)[i_index];
const double dvalue = ((double*)dZ->x)[i_index];
D_Z.de_ele[i+j*nDim] = value;
D_Z.de_ele[j+i*nDim] = value;
D_ZdZ.de_ele[i+j*nDim] = value+dvalue;
D_ZdZ.de_ele[j+i*nDim] = value+dvalue;
}
}
}
rMessage("This routine is only check");
rMessage("This routine is not implemented fully");
rMessage("The computation of R is not implemented fully");
double norm_R = sqrt(sum);
rMessage("inv(X)*X = inv(Z)*Z = I?");
sum = 0.0;
for (int k=0; k<m; ++k) {
const double yk = cholmodSpace.yVec.ele[k];
sum += yk*yk;
}
double norm_y = sqrt(sum);
sum = 0.0;
for (int k=0; k<m; ++k) {
const double dyk = cholmodSpace.dyVec.ele[k];
sum += dyk*dyk;
}
double norm_dy = sqrt(sum);
printf("norm :: rp=%.2e, invX=%.2e, rD=%.2e, R=%.2e\n",
norm_rp, norm_invX, norm_rD, norm_R);
// printf("min_X = %.2e, min_Z = %.2e\n", min_X, min_Z);
// printf("norm :: y=%.2e, dy=%.2e\n", norm_y, norm_dy);
}
void Newton::display(FILE* fpout)
{
if (fpout == NULL) {
return;
}
rMessage("This function is not implemented in SDPA-C");
#if 0
fprintf(fpout,"rNewton.DxMat = \n");
DxMat.display(fpout);
fprintf(fpout,"rNewton.DyVec = \n");
DyVec.display(fpout);
fprintf(fpout,"rNewton.DzMat = \n");
DzMat.display(fpout);
#endif
}
void Newton::display_index(FILE* fpout)
{
if (fpout == NULL) {
return;
}
printf("display_index: %d %d\n",SDP_nBlock,LP_nBlock);
for (int l=0; l<SDP_nBlock; l++){
printf("SDP:%dth block\n",l);
for (int k=0; k<SDP_number[l]; k++){
printf("SDP(i=%d,ib=%d; j=%d,jb=%d) for target = %d\n",
SDP_constraint1[l][k],SDP_blockIndex1[l][k],
SDP_constraint2[l][k],SDP_blockIndex2[l][k],
SDP_location_sparse_bMat[l][k]);
}
}
for (int l=0; l<LP_nBlock; l++){
printf("LP:%dth block\n",l);
for (int k=0; k<LP_number[l]; k++){
printf("LP(i=%d,ib=%d; j=%d,jb=%d) for target = %d\n",
LP_constraint1[l][k],LP_blockIndex1[l][k],
LP_constraint2[l][k],LP_blockIndex2[l][k],
LP_location_sparse_bMat[l][k]);
}
}
}
void Newton::display_sparse_bMat(FILE* fpout)
{
if (fpout == NULL) {
return;
}
fprintf(fpout,"{\n");
for (int index=0; index<sparse_bMat.NonZeroCount; ++index) {
int i = sparse_bMat.row_index[index];
int j = sparse_bMat.column_index[index];
double value = sparse_bMat.sp_ele[index];
fprintf(fpout,"val[%d,%d] = %e\n", i,j,value);
}
fprintf(fpout,"}\n");
}
} // end of namespace 'sdpa'