/* ------------------------------------------------------------- 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_linear.h" #include "sdpa_dataset.h" #include "sdpa_dpotrf.h" #include "sdpa_algebra.h" namespace sdpa { double Lal::getMinEigen(DenseMatrix& lMat, DenseMatrix& xMat, DenseMatrix& Q, Vector& out, Vector& b, Vector& r, Vector& q, Vector& qold, Vector& w, Vector& tmp, Vector& diagVec, Vector& diagVec2, Vector& workVec, char charTranspose) { double alpha,beta,value; double min = 1.0e+51, min_old = 1.0e+52; double error = 1.0e+10; int nDim = xMat.nRow; int k = 0, kk = 0; diagVec.initialize(1.0e+50); diagVec2.setZero(); q.setZero(); r.initialize(1.0); beta = sqrt((double)nDim); // norm of "r" // nakata 2004/12/12 while (k 1.0e-16 && ( k<20 || fabs(min-min_old) > (1.0e-5)*fabs(min)+(1.0e-8) // && (fabs(min-min_old) > (1.0e-3)*fabs(min)+(1.0e-6) || fabs(error*beta) > (1.0e-2)*fabs(min)+(1.0e-6) ) ) { // rMessage("k = " << k); qold.copyFrom(q); value = 1.0/beta; Lal::let(q,'=',r,'*',&value); if (charTranspose == 'N') { // w = (lMat^T)*q w.copyFrom(q); dtrmv_fc ((char *)"Lower",(char *)"Transpose", (char *)"NotUnit",&nDim, lMat.de_ele,&nDim,w.ele,&IONE, strlen("Lower"), strlen("Transpose"),strlen("NotUnit")); Lal::let(tmp,'=',xMat,'*',w); w.copyFrom(tmp); dtrmv_fc ((char *)"Lower",(char *)"NoTranspose", (char *)"NotUnit",&nDim, lMat.de_ele,&nDim,w.ele,&IONE, strlen("Lower"), strlen("NoTranspose"),strlen("NotUnit")); // w = lMat*xMat*(lMat^T)*q // rMessage("w = "); // w.display(); } else if (charTranspose == 'T') { // w = lMat*q w.copyFrom(q); dtrmv_fc ((char *)"Lower",(char *)"NoTranspose", (char *)"NotUnit",&nDim, lMat.de_ele,&nDim,w.ele,&IONE, strlen("Lower"), strlen("NoTranspose"),strlen("NotUnit")); Lal::let(tmp,'=',xMat,'*',w); w.copyFrom(tmp); dtrmv_fc ((char *)"Lower",(char *)"Transpose", (char *)"NotUnit",&nDim, lMat.de_ele,&nDim,w.ele,&IONE, strlen("Lower"), strlen("Transpose"),strlen("NotUnit")); // w = lMat^T*xMat*lMat*q // rMessage("w = "); // w.display(); } else { rError("code bug, charTranspose should be 'N' or 'T'"); } Lal::let(alpha,'=',q,'.',w); diagVec.ele[k] = alpha; Lal::let(r,'=',w,'-',q,&alpha); Lal::let(r,'=',r,'-',qold,&beta); // rMessage("r = "); // r.display(); if ( kk>=sqrt((double)k) || k==nDim-1 || k>sqrt((double)nDim+9) ) { kk = 0; out.copyFrom(diagVec); b.copyFrom(diagVec2); out.ele[nDim-1] = diagVec.ele[k]; b.ele[nDim-1] = 0.0; // rMessage("out = "); // out.display(); // rMessage("b = "); // b.display(); int info; int kp1 = k+1; dsteqr_fc ((char *)"I_withEigenvalues",&kp1,out.ele,b.ele, Q.de_ele, &Q.nRow, workVec.ele, &info, strlen("I_withEigenvalues")); if (info < 0) { rError(" rLanczos :: bad argument " << -info << " Q.nRow = " << Q.nRow << ": nDim = " << nDim << ": kp1 = " << kp1); } else if (info > 0) { rMessage(" rLanczos :: cannot converge " << info); break; } // rMessage("out = "); // out.display(); // rMessage("Q = "); // Q.display(); min_old = min; #if 0 min = 1.0e+50; error = 1.0e+10; for (int i=0; iout.ele[i]){ min = out.ele[i]; error = Q.de_ele[k+Q.nCol*i]; } } #else // out have eigen values with ascending order. min = out.ele[0]; error = Q.de_ele[k]; #endif } // end of 'if ( kk>=sqrt(k) ...)' // printf("\n"); Lal::let(value,'=',r,'.',r); beta = sqrt(value); diagVec2.ele[k] = beta; ++k; ++kk; } // end of while // rMessage("k = " << k); return min - fabs(error*beta); } double Lal::getMinEigenValue(DenseMatrix& aMat, Vector& eigenVec, Vector& workVec) { // aMat is rewritten. // aMat must be symmetric. // eigenVec is the space of eigen values // and needs memory of length aMat.nRow // workVec is temporary space and needs // 3*aMat.nRow-1 length memory. int N = aMat.nRow; int LWORK, info; LWORK = 3*N-1; // "N" means that we need not eigen vectors // "L" means that we refer only lower triangular. dsyev_fc((char *)"NonVectors",(char *)"Lower",&N,aMat.de_ele,&N, eigenVec.ele,workVec.ele,&LWORK,&info, strlen("NonVectors"), strlen("Lower")); if (info!=0) { if (info < 0) { rMessage("getMinEigenValue:: info is mistaken " << info); } else { rMessage("getMinEigenValue:: cannot decomposition"); } exit(0); return 0.0; } return eigenVec.ele[0]; } double Lal::getMinEigenValue(CholmodMatrix& cholmodMatrix) { cholmod_factor* Lz = cholmodMatrix.Lz; cholmod_sparse* dZ = cholmodMatrix.dZ; cholmod_common& common = cholmodMatrix.common; const int nDIM = cholmodMatrix.nDim; Vector rVect(nDIM); Vector qVect(nDIM); Vector qoldVect(nDIM); Vector wVect(nDIM); Vector diagVect(nDIM); Vector diag2Vect(nDIM); if (nDIM == 1) { // this block should be handled as an LP block rError("code bug"); } int i,j,k; double alpha,beta,tmp,min=1.0e51,min_old = 1.0e52; double sig,max,mid; k = 0; for (i=0; i 1.0e-16) && ((fabs(min - min_old) > 1.0e-4 * fabs(min) + 1.0e-8))) { qoldVect.copyFrom(qVect); tmp = 1.0 / beta; Lal::let(qVect,'=',rVect,'*',&tmp); // wVect = Lz^{-1} * dZ * Lz^{-T} * qVect double* b_z_ele = (double*) cholmodMatrix.b_z->x; for (i=0; ix; for (i=0; i sqrt((double)nDIM)+20)|| (beta < 1.0e-16)||(3 * k >= sqrt((double)nDIM+20))) { min_old = min; min = diagVect.ele[0] - fabs(diag2Vect.ele[0]); max = diagVect.ele[0] + fabs(diag2Vect.ele[0]); for ( i = 1; i < k ; i++ ) { tmp = diagVect.ele[i] - fabs(diag2Vect.ele[i-1]) - fabs(diag2Vect.ele[i]); if (min > tmp) min = tmp; tmp = diagVect.ele[i] + fabs(diag2Vect.ele[i-1]) + fabs(diag2Vect.ele[i]); if (max < tmp) max = tmp; } tmp = diagVect.ele[k] - fabs(diag2Vect.ele[k-1]); if (min > tmp) min = tmp; tmp = diagVect.ele[k] + fabs(diag2Vect.ele[k-1]); if (max < tmp) max = tmp; for (i = 0; i < 20;i++) { // printf("i = %d min = %lf max = %lf\n", i, min, max); mid = (max + min) / 2.0; sig = diagVect.ele[0] - mid; for (j = 1;j <= k;j++) { if (sig <= 0.0) break; tmp = sig; sig = (diagVect.ele[j] - mid) - diag2Vect.ele[j-1] * diag2Vect.ele[j-1] / tmp; } if (sig <= 0.0) max = mid; else min = mid; } } k++; // printf("%d : %e %e %e\n",k,fabs(min - min_old),fabs(min),beta); } return min; } double Lal::getOneNorm(Vector& b) { double ret = 0.0; int nDim = b.nDim; for (int k=0; k= *n) { // Here is point. rdpotf2_(uplo, n, a, lda, info); } else { for (int j = 0; j < *n; j += nb) { int jb = min(nb,*n- j); dsyrk_fc((char *)"Lower", (char *)"No transpose", &jb, &j, &DMONE, &a[j], lda, &DONE, &a[j+nRow*j], lda, strlen("Lower"), strlen("No transpose")); // Here is point. rdpotf2_((char *)"Lower", &jb, &a[j+nRow*j], lda, info); if (*info != 0) { *info = *info + j - 1; return 0; } if (j + jb <= *n-1) { int i = *n - j - jb; dgemm_fc((char *)"No transpose", (char *)"Transpose", &i, &jb, &j, &DMONE, &a[j + jb], lda, &a[j], lda, &DONE, &a[(j + jb)+nRow*j], lda, strlen("No transpose"), strlen("Transpose")); dtrsm_fc((char *)"Right", (char *)"Lower", (char *)"Transpose", (char *)"Non-unit", &i, &jb, &DONE, &a[j+nRow*j], lda, &a[(j + jb)+nRow*j], lda, strlen("Right"), strlen("Lower"), strlen("Transpose"), strlen("Non-unit")); } } } return 0; } bool Lal::choleskyFactorWithAdjust(DenseMatrix& aMat) { int info=0; #if 1 // aMat.display(); TimeStart(START1); info = rATL_dpotrfL(aMat.nRow, aMat.de_ele,aMat.nRow); TimeEnd(END1); // rMessage("Schur colesky ::" << TimeCal(START1,END1)); // aMat.display(); #elif 1 dpotrf_fc("Lower",&aMat.nRow,aMat.de_ele,&aMat.nRow, &info,strlen("Lower")); #else rdpotrf_("Lower",&aMat.nRow,aMat.de_ele,&aMat.nRow,&info); #endif if (info < 0) { rMessage("cholesky argument is wrong " << -info); } else if (info > 0) { rMessage("cholesky miss condition :: not positive definite" << " :: info = " << info); rMessage("There are some possibilities."); rMessage("1. SDPA finalizes due to inaccuracy of numerical error"); rMessage("2. The input problem may not have (any) interior-points"); rMessage("3. Input matrices are linearly dependent"); return SDPA_FAILURE; } return SDPA_SUCCESS; #if 0 double ZERO_DETECT = 1.0e-3; double NONZERO = 1.0e-7; // no idea version // if Cholesky factorization failed, then exit soon. int info = 1; // info == 0 means success int start = 0; while (start NONZERO*mishi) { // rMessage(" migi*migi > NONZERO*mishi "); migi = sqrt(NONZERO*mishi) * 0.99; shita = sqrt(NONZERO*mishi) * 0.99; } } } rMessage("cholesky adjust position " << start); } if (info < 0) { rError("argument is something wrong " << info); } return SDPA_SUCCESS; #endif } bool Lal::solveSystems(Vector& xVec, DenseMatrix& aMat, Vector& bVec) { // aMat must have done Cholesky factorized. if (aMat.nCol!=xVec.nDim || aMat.nRow!=bVec.nDim || aMat.nRow!=aMat.nCol) { rError("solveSystems:: different memory size"); } xVec.copyFrom(bVec); dtrsv_fc((char *)"Lower", (char *)"NoTranspose", (char *)"NonUnit", &aMat.nRow, aMat.de_ele, &aMat.nCol, xVec.ele,&IONE, strlen("Lower"), strlen("NoTranspose"), strlen("NonUnit")); dtrsv_fc((char *)"Lower", (char *)"Transpose", (char *)"NonUnit", &aMat.nRow, aMat.de_ele, &aMat.nCol, xVec.ele,&IONE, strlen("Lower"), strlen("Transpose"), strlen("NonUnit")); return SDPA_SUCCESS; } // nakata 2004/12/01 bool Lal::solveSystems(Vector& xVec, SparseMatrix& aMat, Vector& bVec) { #define TUNEUP 0 #if TUNEUP if (aMat.nCol!=xVec.nDim || aMat.nRow!=bVec.nDim || aMat.nRow!=aMat.nCol) { printf("A.row:%d A.col:%d x.row:%d b.row:%d\n", aMat.nCol,aMat.nRow,xVec.nDim ,bVec.nDim); rError("solveSystems(sparse):: different memory size"); } int length; int amari,shou,counter; switch(aMat.type) { case SparseMatrix::SPARSE: #endif // Attension: in SPARSE case, only half elements // are stored. And bMat must be DENSE case. // rMessage("aMat.NonZeroCount == " << aMat.NonZeroCount); xVec.copyFrom(bVec); #if TUNEUP shou = aMat.NonZeroCount / 4; amari = aMat.NonZeroCount % 4; int i,j; double value; for (int index=0; indexx)[agg_index] += value*(*scalar); } } } void Lal::plus(CholmodSpace& retMat, CompSpace& aMat, double* scalar) { if (scalar == NULL) { scalar = &DONE; } for (int l_index=0; l_index < aMat.LP_sp_nBlock; ++l_index) { const double value = aMat.LP_sp_block[l_index]; const int l = aMat.LP_sp_index[l_index]; if (l < 0 || l>=retMat.LP_nBlock) { rError("Code bug"); } retMat.LP_Z[l] += value * (*scalar); } for (int l_index=0; l_index < aMat.SDP_sp_nBlock; ++l_index) { const int l = aMat.SDP_sp_index[l_index]; Lal::plus(retMat.SDP_block[l], aMat.SDP_sp_block[l_index], scalar); } } bool Lal::getSymmetrize(DenseLinearSpace& aMat) { bool total_judge = SDPA_SUCCESS; // for SDP for (int l=0; l