/* ------------------------------------------------------------- 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 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 startTmp; for (int k1=0; k1%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 startTmp; for (int k1=0; k1l; 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; k2l; 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; lnzmax; for (int index1 = 0; index1 < length; ++index1) { ((double*)(dZ->x))[index1] = 0.0; } } const int m = cholmodSpace.dyVec.nDim; for (int k=0; kx))[agg_index] -= Akl.ele[i]*dyk; } } } } // end of 'for (int k=0; knzmax; 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; lx); 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; il; 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; inzmax; 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_indexx))[agg_index] += Cl.ele[i]; } } } for (int k=0; kx))[agg_index] -= Akl.ele[i]*(yk+dyk); } } } } for (int l=0; lnzmax; for (int index1 = 0; index1 < length; ++index1) { double value = ((double*)(rDs[l]->x))[index1]; sum += value*value; } } for (int l=0; l