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

3643 lines
88 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_struct.h"
#include "sdpa_algebra.h"
#include "sdpa_linear.h"
#include "sdpa_dataset.h"
#include <algorithm>
namespace sdpa{
Vector::Vector()
{
initialize();
}
Vector::Vector(int nDim, double value)
{
initialize();
initialize(nDim,value);
}
Vector::~Vector()
{
finalize();
}
void Vector::initialize()
{
nDim = 0;
ele = NULL;
}
void Vector::initialize(int nDim, double value)
{
// rMessage("Vector initialize");
if (nDim<=0) {
rError("Vector:: nDim is nonpositive");
}
if (this->nDim!=nDim && ele != NULL) {
DeleteArray(ele);
}
this->nDim = nDim;
if (ele == NULL) {
NewArray(ele,double,nDim);
}
sdpa_dset(nDim,value,ele,IONE);
}
void Vector::initialize(double value)
{
if (ele==NULL) {
NewArray(ele,double,nDim);
}
sdpa_dset(nDim,value,ele,IONE);
}
void Vector::finalize()
{
DeleteArray(ele);
}
void Vector::setZero()
{
initialize(0.0);
}
void Vector::display(FILE* fpout, char* printFormat)
{
if (fpout == NULL) {
return;
}
if (strcmp(printFormat,NO_P_FORMAT) == 0) {
fprintf(fpout,"%s\n",NO_P_FORMAT);
return;
}
fprintf(fpout,"{");
for (int j=0; j<nDim-1; ++j) {
fprintf(fpout,printFormat,ele[j]);
fprintf(fpout, ",");
}
if (nDim>0) {
fprintf(fpout,printFormat,ele[nDim-1]);
fprintf(fpout,"}\n");
} else {
fprintf(fpout," }\n");
}
}
void Vector::display(FILE* fpout,double scalar, char* printFormat)
{
if (fpout == NULL) {
return;
}
if (strcmp(printFormat,NO_P_FORMAT) == 0) {
fprintf(fpout,"%s\n",NO_P_FORMAT);
return;
}
fprintf(fpout,"{");
for (int j=0; j<nDim-1; ++j) {
fprintf(fpout,printFormat,ele[j]*scalar);
fprintf(fpout,",");
}
if (nDim>0) {
fprintf(fpout,printFormat,ele[nDim-1]*scalar);
fprintf(fpout,"}\n");
} else {
fprintf(fpout," }\n");
}
}
bool Vector::copyFrom(Vector& other)
{
if (this == &other) {
return SDPA_SUCCESS;
}
if (other.nDim<=0) {
rError("Vector:: nDim is nonpositive");
}
if (nDim != other.nDim) {
DeleteArray(ele);
}
nDim = other.nDim;
if (ele==NULL) {
NewArray(ele,double,nDim);
}
dcopy_fc(&nDim,other.ele,&IONE,ele,&IONE);
return SDPA_SUCCESS;
}
BlockVector::BlockVector()
{
nBlock = 0;
blockStruct = NULL;
ele = NULL;
}
BlockVector::BlockVector(BlockStruct& bs, double value)
{
initialize(bs.SDP_nBlock,bs.SDP_blockStruct,value);
}
BlockVector::BlockVector(int nBlock, int* blockStruct,
double value)
{
initialize(nBlock,blockStruct,value);
}
BlockVector::~BlockVector()
{
finalize();
}
void BlockVector::initialize(BlockStruct& bs, double value)
{
initialize(bs.SDP_nBlock,bs.SDP_blockStruct,value);
}
void BlockVector::initialize(int nBlock, int* blockStruct,
double value)
{
// rMessage("BlockVector initialize");
if (nBlock<=0) {
rError("BlockVector:: nBlock is nonpositive");
}
this->nBlock = nBlock;
NewArray(this->blockStruct,int,nBlock);
for (int l=0; l<nBlock; ++l) {
this->blockStruct[l] = blockStruct[l];
}
NewArray(ele,Vector,nBlock);
for (int l=0; l<nBlock; ++l) {
int size = blockStruct[l];
if (size<0) {
size = -size;
}
ele[l].initialize(size,value);
}
}
void BlockVector::initialize(double value)
{
if (nBlock>0 && blockStruct && ele) {
for (int l=0; l<nBlock; ++l) {
ele[l].initialize(value);
}
}
}
void BlockVector::finalize()
{
if (ele && blockStruct && nBlock>=0) {
for (int l=0; l<nBlock; ++l) {
ele[l].finalize();
}
DeleteArray(ele);
DeleteArray(blockStruct);
}
}
void BlockVector::setZero()
{
if (nBlock>0 && blockStruct && ele) {
for (int l=0; l<nBlock; ++l) {
ele[l].setZero();
}
}
}
void BlockVector::display(FILE* fpout, char* printFormat)
{
if (fpout == NULL) {
return;
}
if (strcmp(printFormat,NO_P_FORMAT) == 0) {
fprintf(fpout,"%s\n",NO_P_FORMAT);
return;
}
fprintf(fpout,"{ ");
if (nBlock>0 && blockStruct && ele) {
for (int l=0; l<nBlock; ++l) {
ele[l].display(fpout,printFormat);
}
}
fprintf(fpout,"} \n");
}
bool BlockVector::copyFrom(BlockVector& other)
{
if (this == &other) {
return SDPA_SUCCESS;
}
if (other.nBlock<=0) {
rError("BlockVector:: nBlock is nonpositive");
}
if (nBlock!=other.nBlock && blockStruct) {
DeleteArray(blockStruct);
DeleteArray(ele);
}
if (blockStruct==NULL) {
nBlock = other.nBlock;
NewArray(blockStruct,int,nBlock);
for (int l=0; l<nBlock; ++l) {
blockStruct[l] = other.blockStruct[l];
}
}
if (ele==NULL) {
NewArray(ele,Vector,nBlock);
}
for (int l=0; l<nBlock; ++l) {
ele[l].copyFrom(other.ele[l]);
}
return SDPA_SUCCESS;
}
SparseMatrix::SparseMatrix()
{
nRow = 0;
nCol = 0;
type = SPARSE;
NonZeroNumber = 0;
de_ele = NULL;
row_index = NULL;
column_index = NULL;
sp_ele = NULL;
DataStruct = DSarrays;
DataS = NULL;
NonZeroCount = 0;
NonZeroEffect = 0;
}
SparseMatrix::SparseMatrix(int nRow, int nCol,
SparseMatrix::Type type,
int NonZeroNumber)
{
initialize(nRow, nCol, type, NonZeroNumber);
}
SparseMatrix::~SparseMatrix()
{
finalize();
}
void SparseMatrix::initialize(int nRow, int nCol,
SparseMatrix::Type type,
int NonZeroNumber,
SparseMatrix::dsType DataStruct)
{
// rMessage("SparseMatrix initialize");
SparseMatrix();
if (nRow<=0 || nCol<=0) {
rError("SparseMatrix:: Dimensions are nonpositive");
}
this->nRow = nRow;
this->nCol = nCol;
this->type = type;
this->DataStruct = DataStruct;
int length;
switch(type) {
case SPARSE:
this->NonZeroNumber = NonZeroNumber;
this->NonZeroCount = 0;
this->NonZeroEffect = 0;
if (NonZeroNumber > 0) {
if (DataStruct == DSarrays) {
NewArray(row_index,int,NonZeroNumber);
NewArray(column_index,int,NonZeroNumber);
NewArray(sp_ele,double,NonZeroNumber);
if (row_index==NULL || column_index==NULL
|| sp_ele==NULL) {
rError("SparseMatrix:: memory exhausted");
}
}
else {
NewArray(DataS, SparseElement, NonZeroNumber);
if (DataS == NULL) {
rError("SparseElement:: memory exhausted");
}
}
}
break;
case DENSE:
this->NonZeroNumber = nRow*nCol;
this->NonZeroCount = nRow*nCol;
this->NonZeroEffect = nRow*nCol;
NewArray(de_ele,double,NonZeroNumber);
if (de_ele==NULL) {
rError("SparseMatrix:: memory exhausted");
}
length = nRow*nCol;
sdpa_dset(length,DZERO,de_ele,IONE);
// all elements are 0.
break;
}
}
void SparseMatrix::finalize()
{
DeleteArray(de_ele);
if (DataStruct == DSarrays) {
DeleteArray(row_index);
DeleteArray(column_index);
DeleteArray(sp_ele);
}
else {
DeleteArray(DataS);
}
}
void SparseMatrix::display(FILE* fpout, char* printFormat)
{
int i, j;
double value;
if (fpout == NULL) {
return;
}
if (strcmp(printFormat,NO_P_FORMAT) == 0) {
fprintf(fpout,"%s\n",NO_P_FORMAT);
return;
}
switch(type) {
case SPARSE:
fprintf(fpout,"{");
for (int index=0; index<NonZeroCount; ++index) {
if (DataStruct == DSarrays) {
i = row_index[index];
j = column_index[index];
value = sp_ele[index];
}
else {
i = DataS[index].vRow;
j = DataS[index].vCol;
value = DataS[index].vEle;
}
fprintf(fpout,"val[%d,%d] = ", i,j);
fprintf(fpout,printFormat,value);
fprintf(fpout,"\n");
}
fprintf(fpout,"}\n");
break;
case DENSE:
fprintf(fpout,"{\n");
for (int i=0; i<nRow-1; ++i) {
if (i==0) {
fprintf(fpout," ");
} else {
fprintf(fpout," ");
}
fprintf(fpout,"{");
for (int j=0; j<nCol-1; ++j) {
fprintf(fpout,printFormat,de_ele[i+nCol*j]);
fprintf(fpout, ",");
}
fprintf(fpout,printFormat,de_ele[i+nCol*(nCol-1)]);
fprintf(fpout, " },\n");
}
if (nRow>1) {
fprintf(fpout," {");
}
for (int j=0; j<nCol-1; ++j) {
fprintf(fpout,printFormat,de_ele[(nRow-1)+nCol*j]);
fprintf(fpout, ",");
}
fprintf(fpout,printFormat,de_ele[(nRow-1)+nCol*(nCol-1)]);
fprintf(fpout, " }");
if (nRow>1) {
fprintf(fpout," }\n");
} else {
fprintf(fpout,"\n");
}
break;
}
}
bool SparseMatrix::copyFrom(SparseMatrix& other)
{
if (type != other.type || nRow != other.nRow
|| nCol != other.nCol) {
this->~SparseMatrix();
initialize(other.nRow,other.nCol,other.type,
NonZeroNumber);
NonZeroCount = other.NonZeroCount;
NonZeroEffect = other.NonZeroEffect;
int length;
switch(type) {
case SPARSE:
for (int index = 0; index<NonZeroCount;++index) {
if (DataStruct == DSarrays) {
row_index[index] = other.row_index[index];
column_index[index] = other.column_index[index];
sp_ele[index] = other.sp_ele[index];
}
else {
DataS[index].vRow = other.DataS[index].vRow;
DataS[index].vCol = other.DataS[index].vCol;
DataS[index].vEle = other.DataS[index].vEle;
}
}
break;
case DENSE:
length = nRow*nCol;
dcopy_fc(&length,other.de_ele,&IONE,de_ele,&IONE);
break;
}
} else { // Sp_De_Di == other.Sp_De_Di
// && nRow == other.nRow && nCol == other.nCol
NonZeroCount = other.NonZeroCount;
NonZeroEffect = other.NonZeroEffect;
int length;
switch(type) {
case SPARSE:
if (NonZeroNumber!=other.NonZeroNumber) {
if (DataStruct == DSarrays) {
DeleteArray(row_index);
DeleteArray(column_index);
DeleteArray(sp_ele);
NewArray(row_index ,int ,NonZeroNumber);
NewArray(column_index,int ,NonZeroNumber);
NewArray(sp_ele ,double,NonZeroNumber);
}
else {
NewArray(DataS, SparseElement,NonZeroNumber);
}
}
for (int index = 0; index<NonZeroCount;++index) {
if (DataStruct == DSarrays) {
row_index[index] = other.row_index[index];
column_index[index] = other.column_index[index];
sp_ele[index] = other.sp_ele[index];
}
else {
DataS[index].vRow = other.DataS[index].vRow;
DataS[index].vCol = other.DataS[index].vCol;
DataS[index].vEle = other.DataS[index].vEle;
}
}
break;
case DENSE:
length = nRow*nCol;
dcopy_fc(&length,other.de_ele,&IONE,de_ele,&IONE);
break;
} // end of switch
} // end of else
return SDPA_SUCCESS;
}
void SparseMatrix::changeToDense(bool forceChange)
{
if (type!=SPARSE) {
return;
}
// if (false)
// rMessage(" NonZeroCount " << NonZeroCount);
// rMessage(" nRow*nCol*0.2 " << nRow*nCol*0.2);
if (forceChange == false && NonZeroCount < (nRow*nCol) * 0.20) {
// if the number of elements are less than 20 percent,
// we don't change to Dense.
return;
}
// rMessage("change");
type = DENSE;
de_ele = NULL;
int length = nRow*nCol;
NewArray(de_ele,double,length);
sdpa_dset(length,DZERO,de_ele,IONE);
// all elements are set 0.
for (int index=0; index<NonZeroCount; ++index) {
#if DATA_CAPSULE
int i = DataS[index].vRow;
int j = DataS[index].vCol;
double value = DataS[index].vEle;
#else
int i = row_index[index];
int j = column_index[index];
double value = sp_ele[index];
#endif
if (i==j) {
de_ele[i+nCol*j] = value;
} else {
de_ele[i+nCol*j] = de_ele[j+nCol*i] = value;
}
}
NonZeroCount = NonZeroNumber = NonZeroEffect = length;
if (DataStruct == DSarrays) {
DeleteArray(row_index);
DeleteArray(column_index);
DeleteArray(sp_ele);
}
else {
DeleteArray(DataS);
}
}
void SparseMatrix::setZero()
{
int length;
switch(type) {
case SPARSE:
NonZeroCount = 0;
NonZeroEffect = 0;
// No element is stored.
break;
case DENSE:
length = nRow*nCol;
sdpa_dset(length,DZERO,de_ele,IONE);
break;
}
}
void SparseMatrix::setIdentity(double scalar)
{
if (nRow != nCol) {
rError("SparseMatrix:: Identity matrix must be square matrix");
}
int length,step;
switch(type) {
case SPARSE:
if (nCol > NonZeroNumber) {
rError("SparseMatrix:: cannot store over NonZeroNumber");
// the number of Diagonal elements equals nCol.
}
NonZeroCount = nCol;
NonZeroEffect = nCol;
for (int index=0; index< NonZeroCount; ++index) {
#if DATA_CAPSULE
DataS[index].vRow = index;
DataS[index].vCol = index;
DataS[index].vEle = scalar;
#else
row_index[index] = index;
column_index[index] = index;
sp_ele[index] = scalar;
#endif
}
break;
case DENSE:
length = nRow*nCol;
sdpa_dset(length,DZERO,de_ele,IONE);
step = nCol+1;
sdpa_dset(nCol,scalar,de_ele,step);
// only diagonal elements are set the value of scalar.
break;
}
}
bool SparseMatrix::sortSparseIndex(int& i, int& j)
{
// if this matrix is not symmetric,
// return the index(i,j) whose values are not symmetric.
i = -1;
j = -1;
const double tolerance = 1.0e-8;
switch(type) {
case SPARSE:
// Make matrix as Upper Triangluar
for (int i1=0; i1<NonZeroCount; ++i1) {
#if DATA_CAPSULE
int tmpi = DataS[i1].vRow;
int tmpj = DataS[i1].vCol;
if (tmpi>tmpj) {
DataS[i1].vRow = tmpj;
DataS[i1].vCol = tmpi;
}
#else
int tmpi = row_index[i1];
int tmpj = column_index[i1];
if (tmpi>tmpj) {
row_index [i1] = tmpj;
column_index[i1] = tmpi;
}
#endif
}
// simple sort
for (int i1=0; i1<NonZeroCount; ++i1) {
for (int i2=0; i2<i1; ++i2) {
#if DATA_CAPSULE
int index1 = DataS[i1].vRow + DataS[i1].vCol;
int index2 = DataS[i2].vRow + DataS[i2].vCol;
if (index1<index2) {
int tmpi = DataS[i2].vRow;
int tmpj = DataS[i2].vCol;
double tmpv = DataS[i2].vEle;
DataS[i2].vRow = DataS[i1].vRow;
DataS[i2].vCol = DataS[i1].vCol;
DataS[i2].vEle = DataS[i1].vEle;
DataS[i1].vRow = tmpi;
DataS[i1].vCol = tmpj;
DataS[i1].vEle = tmpv;
}
#else
int index1 = row_index[i1]+nCol*column_index[i1];
int index2 = row_index[i2]+nCol*column_index[i2];
if (index1<index2) {
int tmpi = row_index [i2];
int tmpj = column_index[i2];
double tmpv = sp_ele [i2];
row_index [i2] = row_index [i1];
column_index[i2] = column_index[i1];
sp_ele [i2] = sp_ele [i1];
row_index [i1] = tmpi;
column_index[i1] = tmpj;
sp_ele [i1] = tmpv;
}
#endif
}
}
// the process for the same index
for (int i1=0; i1<NonZeroCount-1; ++i1) {
#if DATA_CAPSULE
int index1 = DataS[i1].vRow + DataS[i1].vCol;
int index2 = DataS[i1+1].vRow + DataS[i1+1].vCol;
if (index1 == index2) {
if (fabs(DataS[index1].vEle - DataS[index2].vEle) > tolerance) {
// Here must not be symmetric
if (i<0 || j<0) {
i = DataS[i1].vRow;
j = DataS[i1].vCol;
}
}
// remove redudunt
for (int i2 = i1+1; i2<NonZeroCount-2;++i2) {
DataS[i2].vRow = DataS[i2+1].vRow;
DataS[i2].vCol = DataS[i2+1].vCol;
DataS[i2].vEle = DataS[i2+1].vEle;
}
NonZeroCount--;
if (i==j) {
NonZeroEffect--;
} else {
NonZeroEffect -= 2;
}
} // end of 'if (index1==index2)'
#else
int index1 = row_index[i1 ]+nCol*column_index[i1 ];
int index2 = row_index[i1+1]+nCol*column_index[i1+1];
if (index1 == index2) {
if (fabs(sp_ele[index1] - sp_ele[index2]) > tolerance) {
// Here must not be symmetric
if (i<0 || j<0) {
i = row_index [i1];
j = column_index[i1];
}
}
// remove redudunt
for (int i2 = i1+1; i2<NonZeroCount-2;++i2) {
row_index [i2] = row_index [i2+1];
column_index[i2] = column_index[i2+1];
sp_ele [i2] = sp_ele [i2+1];
}
NonZeroCount--;
if (i==j) {
NonZeroEffect--;
} else {
NonZeroEffect -= 2;
}
} // end of 'if (index1==index2)'
#endif
}
break;
case DENSE:
if (nRow!=nCol) {
return SDPA_FAILURE;
}
for (j=1; j<nCol; ++j) {
for (i=0; i<j; ++i) {
if (fabs(de_ele[i+nCol*j]-de_ele[j+nCol*i]) > tolerance) {
return SDPA_FAILURE;
}
}
}
break;
}
return SDPA_SUCCESS;
}
DenseMatrix::DenseMatrix()
{
initialize();
}
void DenseMatrix::initialize()
{
nRow = 0;
nCol = 0;
de_ele = NULL;
}
DenseMatrix::~DenseMatrix()
{
finalize();
}
void DenseMatrix::initialize(int nRow, int nCol)
{
// rMessage("DenseMatrix::initialize");
DenseMatrix();
if (nRow<=0 || nCol<=0) {
rError("DenseMatrix:: Dimensions are nonpositive");
}
int old_length = this->nRow*this->nCol;
this->nRow = nRow;
this->nCol = nCol;
int length;
length = nRow*nCol;
if (de_ele != NULL && old_length!=length) {
DeleteArray(de_ele);
}
if (de_ele==NULL) {
NewArray(de_ele,double,length);
}
sdpa_dset(length,DZERO,de_ele,IONE);
}
void DenseMatrix::finalize()
{
DeleteArray(de_ele);
}
void DenseMatrix::display(FILE* fpout, char* printFormat)
{
if (fpout == NULL) {
return;
}
fprintf(fpout,"{");
for (int i=0; i<nRow-1; ++i) {
if (i==0) {
fprintf(fpout," ");
} else {
fprintf(fpout," ");
}
fprintf(fpout,"{");
for (int j=0; j<nCol-1; ++j) {
fprintf(fpout,printFormat,de_ele[i+nCol*j]);
fprintf(fpout, ",");
}
fprintf(fpout,printFormat,de_ele[i+nCol*(nCol-1)]);
fprintf(fpout, " },\n");
}
if (nRow>1) {
fprintf(fpout," {");
}
for (int j=0; j<nCol-1; ++j) {
fprintf(fpout,printFormat,de_ele[(nRow-1)+nCol*j]);
fprintf(fpout, ",");
}
fprintf(fpout,printFormat,de_ele[(nRow-1)+nCol*(nCol-1)]);
fprintf(fpout, " }");
if (nRow>1) {
fprintf(fpout," }\n");
} else {
fprintf(fpout,"\n");
}
}
bool DenseMatrix::copyFrom(SparseMatrix& other)
{
int length;
switch(other.type) {
case SparseMatrix::SPARSE:
DeleteArray(de_ele);
nRow = other.nRow;
nCol = other.nCol;
NewArray(de_ele,double,nRow*nCol);
length = nRow*nCol;
sdpa_dset(length,DZERO,de_ele,IONE);
for (int index = 0; index<other.NonZeroCount; ++index) {
#if DATA_CAPSULE
int i = other.DataS[index].vRow;
int j = other.DataS[index].vCol;
double value = other.DataS[index].vEle;
#else
int i = other.row_index[index];
int j = other.column_index[index];
double value = other.sp_ele[index];
#endif
de_ele[i+nCol*j] = de_ele[j+nCol*i] = value;
}
break;
case SparseMatrix::DENSE:
if (other.nRow!=nRow || other.nCol!=nCol) {
DeleteArray(de_ele);
}
nRow = other.nRow;
nCol = other.nCol;
NewArray(de_ele,double,nRow*nCol);
length = nRow*nCol;
dcopy_fc(&length,other.de_ele,&IONE,de_ele,&IONE);
break;
}
return SDPA_SUCCESS;
}
bool DenseMatrix::copyFrom(DenseMatrix& other)
{
if (this == &other) {
return SDPA_SUCCESS;
}
int length;
if (other.nRow!=nRow || other.nCol!=nCol) {
DeleteArray(de_ele);
}
nRow = other.nRow;
nCol = other.nCol;
if (de_ele==NULL) {
NewArray(de_ele,double,nRow*nCol);
}
length = nRow*nCol;
dcopy_fc(&length,other.de_ele,&IONE,de_ele,&IONE);
return SDPA_SUCCESS;
}
void DenseMatrix::setZero()
{
int length = nRow*nCol;
sdpa_dset(length,DZERO,de_ele,IONE);
}
void DenseMatrix::setIdentity(double scalar)
{
if (nRow != nCol) {
rError("SparseMatrix:: Identity matrix must be square matrix");
}
int length,step;
length = nRow*nCol;
sdpa_dset(length,DZERO,de_ele,IONE);
step = nCol+1;
sdpa_dset(nCol,scalar,de_ele,step);
}
SparseLinearSpace::SparseLinearSpace()
{
SDP_sp_nBlock = 0;
SDP_sp_index = NULL;
SDP_sp_block = NULL;
SOCP_sp_nBlock = 0;
SOCP_sp_index = NULL;
SOCP_sp_block = NULL;
LP_sp_nBlock = 0;
LP_sp_index = NULL;
LP_sp_block = NULL;
}
SparseLinearSpace::SparseLinearSpace(int SDP_nBlock,
int* SDP_blockStruct,
int* SDP_NonZeroNumber,
int SOCP_nBlock,
int* SOCP_blockStruct,
int* SOCP_NonZeroNumber,
int LP_nBlock,
bool* LP_NonZeroNumber)
{
initialize(SDP_nBlock, SDP_blockStruct, SDP_NonZeroNumber,
SOCP_nBlock, SOCP_blockStruct, SOCP_NonZeroNumber,
LP_nBlock, LP_NonZeroNumber);
}
SparseLinearSpace::SparseLinearSpace(int SDP_sp_nBlock,
int* SDP_sp_index,
int* SDP_sp_blockStruct,
int* SDP_sp_NonZeroNumber,
int SOCP_sp_nBlock,
int* SOCP_sp_index,
int* SOCP_sp_blockStruct,
int* SOCP_sp_NonZeroNumber,
int LP_sp_nBlock,
int* LP_sp_index)
{
initialize(SDP_sp_nBlock, SDP_sp_index,
SDP_sp_blockStruct, SDP_sp_NonZeroNumber,
SOCP_sp_nBlock, SOCP_sp_index,
SOCP_sp_blockStruct, SOCP_sp_NonZeroNumber,
LP_sp_nBlock, LP_sp_index);
}
SparseLinearSpace::~SparseLinearSpace()
{
finalize();
}
// dense form of block index
void SparseLinearSpace::initialize(int SDP_nBlock,
int* SDP_blockStruct,
int* SDP_NonZeroNumber,
int SOCP_nBlock,
int* SOCP_blockStruct,
int* SOCP_NonZeroNumber,
int LP_nBlock,
bool* LP_NonZeroNumber)
{
// rMessage("SparseLinearSpace::initialize");
SDP_sp_nBlock = 0;
SOCP_sp_nBlock = 0;
LP_sp_nBlock = 0;
int counter;
// for SDP
for (int l=0; l<SDP_nBlock; l++){
if (SDP_NonZeroNumber[l] > 0){
SDP_sp_nBlock++;
}
}
if (SDP_sp_nBlock > 0){
NewArray(SDP_sp_index,int,SDP_sp_nBlock);
NewArray(SDP_sp_block,SparseMatrix,SDP_sp_nBlock);
}
counter = 0;
for (int l=0; l<SDP_nBlock; ++l) {
if (SDP_NonZeroNumber[l] > 0){
SDP_sp_index[counter] = l;
int size = SDP_blockStruct[l];
SDP_sp_block[counter].initialize(size,size,SparseMatrix::SPARSE,
SDP_NonZeroNumber[l]);
counter++;
}
}
// for SOCP
#if 0
for (int l=0; l<SOCP_nBlock; l++){
if (SOCP_NonZeroNumber[l] > 0){
SOCP_sp_nBlock++;
}
}
if (SOCP_sp_nBlock > 0){
NewArray(SOCP_sp_index,int,SOCP_sp_nBLock);
NewArray(SOCP_sp_block,SparseMatrix,SOCP_sp_nBLock);
}
counter = 0;
for (int l=0; l<SOCP_nBlock; ++l) {
if (SOCP_NonZeroNumber[l] > 0){
SOCP_sp_index[counter] = l;
int size = SOCP_blockStruct[l];
SOCP_sp_block[counter].initialize(size,size,SparseMatrix::SPARSE,
SOCP_NonZeroNumber[l]);
counter++;
}
}
#endif
// for LP
for (int l=0; l<LP_nBlock; l++){
if (LP_NonZeroNumber[l] == true){
LP_sp_nBlock++;
}
}
if (LP_sp_nBlock > 0){
NewArray(LP_sp_index,int,LP_sp_nBlock);
NewArray(LP_sp_block,double,LP_sp_nBlock);
}
counter = 0;
for (int l=0; l<LP_nBlock; ++l) {
if (LP_NonZeroNumber[l] == true){
LP_sp_index[counter] = l;
counter++;
}
}
}
// sparse form of block index 2008/02/27 kazuhide nakata
void SparseLinearSpace::initialize(int SDP_sp_nBlock,
int* SDP_sp_index,
int* SDP_sp_blockStruct,
int* SDP_sp_NonZeroNumber,
int SOCP_sp_nBlock,
int* SOCP_sp_index,
int* SOCP_sp_blockStruct,
int* SOCP_sp_NonZeroNumber,
int LP_sp_nBlock,
int* LP_sp_index)
{
// rMessage("SparseLinearSpace::initialize");
// for SDP
this->SDP_sp_nBlock = SDP_sp_nBlock;
if (SDP_sp_nBlock > 0){
NewArray(this->SDP_sp_index,int,SDP_sp_nBlock);
NewArray(this->SDP_sp_block,SparseMatrix,SDP_sp_nBlock);
}
for (int l=0; l<SDP_sp_nBlock; ++l) {
this->SDP_sp_index[l] = SDP_sp_index[l];
int size = SDP_sp_blockStruct[l];
SDP_sp_block[l].initialize(size,size,SparseMatrix::SPARSE,
SDP_sp_NonZeroNumber[l]);
}
// for SOCP
#if 0
this->SOCP_sp_nBlock = SOCP_sp_nBlock;
if (SOCP_sp_nBlock > 0){
NewArray(this->SOCP_sp_index,int,SOCP_sp_nBlock);
NewArray(this->SOCP_sp_block,SparseMatrix,SOCP_sp_nBlock);
}
for (int l=0; l<SOCP_sp_nBlock; ++l) {
this->SOCP_sp_index[l] = SOCP_sp_index[l];
int size = SOCP_sp_blockStruct[l];
SOCP_sp_block[l].initialize(size,size,SparseMatrix::SPARSE,
SOCP_sp_NonZeroNumber[l]);
}
#endif
// for LP
this->LP_sp_nBlock = LP_sp_nBlock;
if (LP_sp_nBlock > 0){
NewArray(this->LP_sp_index,int,LP_sp_nBlock);
NewArray(this->LP_sp_block,double,LP_sp_nBlock);
}
for (int l=0; l<LP_sp_nBlock; ++l) {
this->LP_sp_index[l] = LP_sp_index[l];
}
}
void SparseLinearSpace::finalize()
{
// for SDP
if (SDP_sp_block && SDP_sp_index && SDP_sp_nBlock>=0) {
for (int l=0; l<SDP_sp_nBlock; ++l) {
SDP_sp_block[l].finalize();
}
DeleteArray(SDP_sp_block);
DeleteArray(SDP_sp_index);
}
// for SOCP
#if 0
if (SOCP_sp_block && SOCP_sp_index && SOCP_sp_nBlock>=0) {
for (int l=0; l<SOCP_sp_nBlock; ++l) {
SOCP_sp_block[l].finalize();
}
DeleteArray(SOCP_sp_block);
DeleteArray(SOCP_sp_index);
}
#endif
// for LP
if (LP_sp_block && LP_sp_index && LP_sp_nBlock>=0) {
DeleteArray(LP_sp_block);
DeleteArray(LP_sp_index);
}
}
void SparseLinearSpace::changeToDense(bool forceChange)
{
if (SDP_sp_nBlock>0 && SDP_sp_index && SDP_sp_block) {
for (int l=0; l<SDP_sp_nBlock; ++l) {
SDP_sp_block[l].changeToDense(forceChange);
}
}
#if 0
if (SOCP_nBlock>0 && SOCP_sp_index && SOCP_sp_block) {
for (int l=0; l<SOCP_nBlock; ++l) {
SOCP_sp_block[l].changeToDense(forceChange);
}
}
#endif
}
void SparseLinearSpace::display(FILE* fpout, char* printFormat)
{
if (fpout == NULL) {
return;
}
if (strcmp(printFormat,NO_P_FORMAT) == 0) {
fprintf(fpout,"%s\n",NO_P_FORMAT);
return;
}
// SDP
if (SDP_sp_nBlock>0 && SDP_sp_index && SDP_sp_block) {
fprintf(fpout,"SDP part{\n");
for (int l=0; l<SDP_sp_nBlock; ++l) {
fprintf(fpout,"block %d\n",SDP_sp_index[l]);
SDP_sp_block[l].display(fpout,printFormat);
}
fprintf(fpout,"} \n");
}
// for SOCP
#if 0
if (SOCP_sp_nBlock>0 && SOCP_sp_index && SOCP_sp_block) {
fprintf(fpout,"SOCP part{\n");
for (int l=0; l<SOCP_sp_nBlock; ++l) {
fprintf(fpout,"block %d\n",SOCP_sp_index[l]);
SOCP_sp_block[l].display(fpout,printFormat);
}
fprintf(fpout,"} \n");
}
#endif
// LP
if (LP_sp_nBlock>0 && LP_sp_index && LP_sp_block) {
fprintf(fpout,"LP part{\n");
for (int l=0; l<LP_sp_nBlock; ++l) {
fprintf(fpout,"index: %d, element ",LP_sp_index[l]);
fprintf(fpout,printFormat,LP_sp_block[l]);
fprintf(fpout,"\n");
}
fprintf(fpout,"} \n");
}
}
bool SparseLinearSpace::copyFrom(SparseLinearSpace& other)
{
bool total_judge;
if (this == &other) {
return SDPA_SUCCESS;
}
if (other.SDP_sp_nBlock+other.SOCP_sp_nBlock+LP_sp_nBlock < 0) {
rError("SparseLinearSpace:: nBlock is negative");
}
// for SDP
if (other.SDP_sp_nBlock < 0) {
rError("SparseLinearSpace:: SDP_nBlock is negative");
}
if (SDP_sp_nBlock!=other.SDP_sp_nBlock) {
DeleteArray(SDP_sp_index);
DeleteArray(SDP_sp_block);
}
SDP_sp_nBlock = other.SDP_sp_nBlock;
if ( SDP_sp_nBlock > 0 && SDP_sp_index==NULL ) {
NewArray(SDP_sp_index,int,SDP_sp_nBlock);
for (int l=0; l<SDP_sp_nBlock; ++l) {
SDP_sp_index[l] = other.SDP_sp_index[l];
}
}
if ( SDP_sp_nBlock > 0 && SDP_sp_block==NULL ) {
NewArray(SDP_sp_block,SparseMatrix,SDP_sp_nBlock);
}
total_judge = SDPA_SUCCESS;
for (int l=0; l<SDP_sp_nBlock; ++l) {
total_judge = SDP_sp_block[l].copyFrom(other.SDP_sp_block[l]);
}
if (total_judge==SDPA_FAILURE) {
rError("SparseLinearSpace:: copy miss");
}
// for SOCP
#if 0
if (other.SOCP_sp_nBlock<0) {
rError("SparseLinearSpace:: SOCP_nBlock is negative");
}
if (SOCP_sp_nBlock!=other.SOCP_sp_nBlock) {
DeleteArray(SOCP_sp_index);
DeleteArray(SOCP_sp_block);
}
SOCP_sp_nBlock = other.SOCP_sp_nBlock;
if ( SOCP_sp_nBlock > 0 && SOCP_sp_index==NULL) {
NewArray(SOCP_sp_index,int,SOCP_sp_nBlock);
for (int l=0; l<SOCP_sp_nBlock; ++l) {
SOCP_sp_index[l] = other.SOCP_sp_index[l];
}
}
if ( SOCP_sp_nBlock > 0 && SOCP_sp_block==NULL) {
NewArray(SOCP_sp_block,SparseMatrix,SOCP_sp_nBlock);
}
total_judge = SDPA_SUCCESS;
for (int l=0; l<SOCP_sp_nBlock; ++l) {
total_judge = SOCP_sp_block[l].copyFrom(other.SOCP_sp_block[l]);
}
if (total_judge==SDPA_FAILURE) {
rError("SparseLinearSpace:: copy miss");
}
#endif
// for LP
if (other.LP_sp_nBlock<0) {
rError("SparseLinearSpace:: LP_nBlock is negative");
}
if (LP_sp_nBlock!=other.LP_sp_nBlock) {
DeleteArray(LP_sp_index);
DeleteArray(LP_sp_block);
}
LP_sp_nBlock = other.LP_sp_nBlock;
if ( LP_sp_nBlock > 0 && LP_sp_index==NULL) {
NewArray(LP_sp_index,int,LP_sp_nBlock);
for (int l=0; l<LP_sp_nBlock; ++l) {
LP_sp_index[l] = other.LP_sp_index[l];
}
}
if ( LP_sp_nBlock > 0 && LP_sp_block==NULL) {
NewArray(LP_sp_block,double,LP_sp_nBlock);
}
total_judge = SDPA_SUCCESS;
for (int l=0; l<LP_sp_nBlock; ++l) {
LP_sp_block[l] = other.LP_sp_block[l];
}
if (total_judge==SDPA_FAILURE) {
rError("SparseLinearSpace:: copy miss");
}
return total_judge;
}
void SparseLinearSpace::setElement_SDP(int block,
int i, int j, double ele)
{
int l;
// seek block
for (l=0; l<SDP_sp_nBlock; l++){
if (SDP_sp_index[l] == block){
break;
}
}
if (l == SDP_sp_nBlock){
rError("SparseLinearSpace::setElement no block");
}
// check range
if (SDP_sp_block[l].NonZeroCount >= SDP_sp_block[l].NonZeroNumber){
rError("SparseLinearSpace::setElement NonZeroCount >= NonZeroNumber");
}
if ((i >= SDP_sp_block[l].nRow) || (j >= SDP_sp_block[l].nCol)){
rError("out of range in input data");
}
// set element
int count = SDP_sp_block[l].NonZeroCount;
#if DATA_CAPSULE
SDP_sp_block[l].DataS[count].vRow = i;
SDP_sp_block[l].DataS[count].vCol = j;
SDP_sp_block[l].DataS[count].vEle = ele;
#else
SDP_sp_block[l].row_index[count] = i;
SDP_sp_block[l].column_index[count] = j;
SDP_sp_block[l].sp_ele[count] = ele;
#endif
SDP_sp_block[l].NonZeroCount++;
if (i==j){
SDP_sp_block[l].NonZeroEffect++;
} else {
SDP_sp_block[l].NonZeroEffect += 2;
}
}
void SparseLinearSpace::setElement_SOCP(int block, int i, int j,
double ele)
{
rError("DenseLinearSpace:: current version does not support SOCP");
}
void SparseLinearSpace::setElement_LP(int block, double ele)
{
int l;
for (l=0; l<LP_sp_nBlock; l++){
if (LP_sp_index[l] == block){
break;
}
}
if (l == LP_sp_nBlock){
rError("SparseLinearSpace::"
"setElement cannot find the appropriate block");
}
LP_sp_block[l] = ele;
}
void SparseLinearSpace::setZero()
{
// for SDP
if (SDP_sp_nBlock>0 && SDP_sp_index && SDP_sp_block) {
for (int l=0; l<SDP_sp_nBlock; ++l) {
SDP_sp_block[l].setZero();
}
}
// for SOCP
#if 0
if (SOCP_sp_nBlock>0 && SOCP_sp_index && SOCP_sp_block) {
for (int l=0; l<SOCP_sp_nBlock; ++l) {
SOCP_sp_block[l].setZero();
}
}
#endif
// for LP
if (LP_sp_nBlock>0 && LP_sp_index && LP_sp_block) {
for (int l=0; l<LP_sp_nBlock; ++l) {
LP_sp_block[l] = 0;
}
}
}
void SparseLinearSpace::setIdentity(double scalar)
{
rError("SparseLinearSpace::setIdentity no support");
if (SDP_sp_nBlock>0 && SDP_sp_index && SDP_sp_block) {
for (int l=0; l<SDP_sp_nBlock; ++l) {
SDP_sp_block[l].setIdentity(scalar);
}
}
#if 0
if (SOCP_sp_nBlock>0 && SOCP_sp_index && SOCP_sp_block) {
for (int l=0; l<SOCP_sp_nBlock; ++l) {
SOCP_sp_block[l].setIdentity(scalar);
}
}
if (LP_sp_nBlock>0 && LP_sp_index && LP_sp_block) {
for (int l=0; l<LP_sp_nBlock; ++l) {
LP_sp_block[l].setIdentity(scalar);
}
}
#endif
}
bool SparseLinearSpace::sortSparseIndex(int& l, int& i, int& j)
{
bool total_judge = SDPA_SUCCESS;
l = -1;
int i_in,j_in;
// for SDP
if (SDP_sp_nBlock>0 && SDP_sp_index && SDP_sp_block) {
for (int l_in=0; l_in<SDP_sp_nBlock; ++l_in) {
total_judge = SDP_sp_block[l_in].sortSparseIndex(i_in,j_in);
if (total_judge==SDPA_FAILURE && l<0) {
l = l_in;
i = i_in;
j = j_in;
}
}
}
// for SOCP
l = -1;
if (SOCP_sp_nBlock>0 && SOCP_sp_index && SOCP_sp_block) {
for (int l_in=0; l_in<SOCP_sp_nBlock; ++l_in) {
total_judge = SOCP_sp_block[l_in].sortSparseIndex(i_in,j_in);
if (total_judge==SDPA_FAILURE && l<0) {
l = l_in;
i = i_in;
j = j_in;
}
}
}
return total_judge;
}
DenseLinearSpace::DenseLinearSpace()
{
SDP_nBlock = 0;
SDP_block = NULL;
LP_nBlock = 0;
LP_block = NULL;
}
DenseLinearSpace::DenseLinearSpace(BlockStruct& bs)
{
initialize(bs);
}
DenseLinearSpace::~DenseLinearSpace()
{
finalize();
}
void DenseLinearSpace::initialize(BlockStruct& bs)
{
// First clean up, then initialzie
finalize();
this->SDP_nBlock = bs.SDP_nBlock;
this->LP_nBlock = bs.LP_nBlock;
SDP_block = NULL;
LP_block = NULL;
// rMessage("DenseLinearSpace::initialize");
if (SDP_nBlock + LP_nBlock <= 0) {
rError("DenseLinearSpace:: SDP + LP Block is nonpositive");
}
// for SDP
if (SDP_nBlock<0) {
rError("DenseLinearSpace:: SDP_nBlock is negative");
}
if (SDP_nBlock > 0) {
NewArray(SDP_block,DenseMatrix,SDP_nBlock);
}
for (int l=0; l<SDP_nBlock; ++l) {
int size = bs.SDP_blockStruct[l];
if (size>0) {
SDP_block[l].initialize(size,size);
} else {
rError("DenseLinearSpace:: SDP size is nonpositive");
}
}
// for LP
if (LP_nBlock<0) {
rError("DenseLinearSpace:: LP_nBlock is negative");
}
if (LP_nBlock > 0) {
NewArray(LP_block,double,LP_nBlock);
}
for (int l=0; l<LP_nBlock; ++l) {
LP_block[l] = 0.0;
}
}
void DenseLinearSpace::finalize()
{
// for SDP
if (SDP_block && SDP_nBlock>0) {
for (int l=0; l<SDP_nBlock; ++l) {
SDP_block[l].finalize();
}
DeleteArray(SDP_block);
}
// SOCP
#if 0
if (SOCP_block && SOCP_nBlock>0) {
for (int l=0; l<SOCP_nBlock; ++l) {
SOCP_block[l].finalize();
}
DeleteArray(SOCP_block);
}
#endif
// LP
if (LP_block && LP_nBlock>0) {
DeleteArray(LP_block);
}
}
void DenseLinearSpace::display(FILE* fpout, char* printFormat)
{
if (fpout == NULL) {
return;
}
if (strcmp(printFormat,NO_P_FORMAT) == 0) {
fprintf(fpout,"%s\n",NO_P_FORMAT);
return;
}
if (SDP_nBlock>0 && SDP_block) {
fprintf(fpout,"SDP part{\n");
for (int l=0; l<SDP_nBlock; ++l) {
SDP_block[l].display(fpout);
}
fprintf(fpout,"} \n");
}
#if 0
if (SOCP_nBlock>0 && SOCP_block) {
fprintf(fpout,"SOCP part{\n");
for (int l=0; l<SOCP_nBlock; ++l) {
SOCP_block[l].display(fpout);
}
fprintf(fpout,"} \n");
}
#endif
if (LP_nBlock>0 && LP_block) {
fprintf(fpout,"LP part{\n");
for (int l=0; l<LP_nBlock; ++l) {
fprintf(fpout,printFormat,LP_block[l]);
fprintf(fpout,", ");
}
fprintf(fpout,"} \n");
}
}
void DenseLinearSpace::displaySolution(BlockStruct& bs,
FILE* fpout,
char* printFormat)
{
if (fpout == NULL) {
return;
}
if (strcmp(printFormat,NO_P_FORMAT) == 0) {
fprintf(fpout,"%s\n",NO_P_FORMAT);
return;
}
fprintf(fpout,"{\n");
for (int l=0; l<bs.nBlock; l++){
if (bs.blockType[l] == BlockStruct::btSDP) {
int l2 = bs.blockNumber[l];
SDP_block[l2].display(fpout,printFormat);
}
else if (bs.blockType[l] == BlockStruct::btLP) {
fprintf(fpout,"{");
int size = bs.blockStruct[l];
int start = bs.blockNumber[l];
for (int l2=0; l2<size-1; ++l2) {
fprintf(fpout,printFormat,LP_block[start+l2]);
fprintf(fpout,",");
}
if (size > 0) {
fprintf(fpout,printFormat,LP_block[start+size-1]);
fprintf(fpout,"}\n");
} else {
fprintf(fpout," }\n");
}
} else {
rError("io::displayDenseLinearSpaceLast not valid blockType");
}
}
fprintf(fpout,"}\n");
}
bool DenseLinearSpace::copyFrom(DenseLinearSpace& other)
{
if (this == &other) {
return SDPA_SUCCESS;
}
if (other.SDP_nBlock+other.LP_nBlock<=0) {
rError("DenseLinearSpace:: SDP + LP Block is nonpositive");
}
bool total_judge = SDPA_SUCCESS;
// for SDP
if (other.SDP_nBlock<0) {
rError("DenseLinearSpace:: SDP_nBlock is negative");
}
if (SDP_nBlock!=other.SDP_nBlock) {
DeleteArray(SDP_block);
}
SDP_nBlock = other.SDP_nBlock;
if (SDP_nBlock > 0 && SDP_block == NULL) {
NewArray(SDP_block,DenseMatrix,SDP_nBlock);
}
for (int l=0; l<SDP_nBlock; ++l) {
total_judge = SDP_block[l].copyFrom(other.SDP_block[l]);
}
if (total_judge==SDPA_FAILURE) {
rError("DenseLinearSpace:: copy miss");
}
// for LP
if (other.LP_nBlock<0) {
rError("DenseLinearSpace:: LP_nBlock is negative");
}
if (LP_nBlock!=other.LP_nBlock) {
delete[] LP_block;
LP_block = NULL;
}
LP_nBlock = other.LP_nBlock;
if ((LP_nBlock > 0) && (LP_block == NULL)) {
LP_block = new double[LP_nBlock];
if (LP_block==NULL) {
rError("DenseLinearSpace:: memory exhausted");
}
}
for (int l=0; l<LP_nBlock; ++l) {
LP_block[l] = other.LP_block[l];
}
return total_judge;
}
void DenseLinearSpace::setElement_SDP(int block, int i, int j, double ele)
{
// check range
if (block >= SDP_nBlock){
rError("out of range in input data");
}
if ((i >= SDP_block[block].nRow) || (j >= SDP_block[block].nCol)){
rError("out of range in input data");
}
int nCol = SDP_block[block].nCol;
SDP_block[block].de_ele[i + j * nCol] = ele;
SDP_block[block].de_ele[j + i * nCol] = ele;
}
void DenseLinearSpace::setElement_SOCP(int block, int i, int j,
double ele)
{
rError("DenseLinearSpace:: current version does not support SOCP");
}
void DenseLinearSpace::setElement_LP(int block, double ele)
{
// check range
if (block >= LP_nBlock){
rError("out of range in input data");
}
LP_block[block] = ele;
}
void DenseLinearSpace::setZero()
{
// for SDP
if (SDP_nBlock>0 && SDP_block) {
for (int l=0; l<SDP_nBlock; ++l) {
SDP_block[l].setZero();
}
}
// for LP
if (LP_nBlock>0 && LP_block) {
for (int l=0; l<LP_nBlock; ++l) {
LP_block[l] = 0.0;
}
}
}
void DenseLinearSpace::setIdentity(double scalar)
{
// for SDP
if (SDP_nBlock>0 && SDP_block) {
for (int l=0; l<SDP_nBlock; ++l) {
SDP_block[l].setIdentity(scalar);
}
}
// for LP
if (LP_nBlock>0 && LP_block) {
for (int l=0; l<LP_nBlock; ++l) {
LP_block[l] = scalar;
}
}
}
void CompMatrix::display(FILE* fpout, char* printFormat)
{
if (fpout == NULL) {
return;
}
if (nzColumn == 0 || NNZ == 0) {
fprintf(fpout, "EMPTY Matrix\n");
return;
}
fprintf(fpout, "NNZ = %d, lowerNNZ = %d\n", NNZ, lowerNNZ);
fprintf(fpout, "nzColumn = %d, effectiveNzColumn = %d\n",
nzColumn, effectiveNzColumn);
fprintf(fpout,"{\n");
for (int ncol = 0; ncol < nzColumn; ++ncol) {
const int j = column_index[ncol];
fprintf(fpout, "j = %d [%d:%d], diag = %d\n",
j, column_start[ncol], column_start[ncol+1],
diag_index[ncol]);
for (int index1 = column_start[ncol];
index1 < column_start[ncol+1]; ++index1) {
const int i = row_index[index1];
const double v = ele[index1];
const int agg = agg_index[index1];
fprintf(fpout, "[%d,%d,",i,j);
fprintf(fpout,printFormat,v);
fprintf(fpout, "]:index[%d],agg[%d]\n",index1,agg);
}
}
fprintf(fpout,"}\n");
fprintf(fpout, "nzColumn_diag = %d : ", nzColumn_diag);
for (int ncol = 0; ncol < nzColumn_diag; ++ncol) {
fprintf(fpout, "%d ", column_index[column_diag_index[ncol]]);
}
fprintf(fpout, "\n");
fprintf(fpout, "nzColumn_nondiag = %d : ", nzColumn_nondiag);
for (int ncol = 0; ncol < nzColumn_nondiag; ++ncol) {
fprintf(fpout, "%d ", column_index[column_nondiag_index[ncol]]);
}
fprintf(fpout, "\n");
}
void CompMatrix::initialize()
{
nRow = 0;
nCol = 0;
nzColumn = 0;
effectiveNzColumn = 0;
column_index = NULL;
NNZ = 0;
lowerNNZ = 0;
column_start = NULL;
row_index = NULL;
ele = NULL;
diag_index = NULL;
agg_index = NULL;
blockNumber = NULL;
blockIndex = NULL;
nzColumn_diag = 0;
column_diag_index = NULL;
nzColumn_nondiag = 0;
column_nondiag_index = NULL;
inputVector = NULL;
}
CompMatrix::CompMatrix()
{
initialize();
}
void CompMatrix::finalize()
{
DeleteArray(column_index);
DeleteArray(column_start);
DeleteArray(row_index);
DeleteArray(diag_index);
DeleteArray(agg_index);
DeleteArray(blockNumber);
DeleteArray(blockIndex);
DeleteArray(ele);
DeleteArray(column_diag_index);
DeleteArray(column_nondiag_index);
if (inputVector != NULL) {
const int size = inputVector->size();
for (int index = 0; index < size; ++index) {
DeleteArray(inputVector->at(index));
}
}
DeleteArray(inputVector);
nRow = 0;
nCol = 0;
nzColumn = 0;
NNZ = 0;
lowerNNZ = 0;
nzColumn_diag = 0;
nzColumn_nondiag = 0;
}
CompMatrix::~CompMatrix()
{
finalize();
}
void CompMatrix::initializeInputVector()
{
NewArray(inputVector,vector<CompMatrix::inputIJV*>,1);
}
void CompMatrix::setElement(int i, int j, double v)
{
CompMatrix::inputIJV* ele;
NewArray(ele, inputIJV, 1);
ele[0].i = i;
ele[0].j = j;
ele[0].v = v;
inputVector->push_back(ele);
// both upper and lower triangular are assigned
if (i!=j) {
CompMatrix::inputIJV* ele2;
NewArray(ele2, inputIJV, 1);
ele2[0].i = j;
ele2[0].j = i;
ele2[0].v = v;
inputVector->push_back(ele2);
}
}
void CompMatrix::sortInputVector()
{
const int size = inputVector->size();
// to make sort easier, (i,j) information is wrapped into (i)
for (int index = 0; index < size; ++index) {
CompMatrix::inputIJV* ele = inputVector->at(index);
ele->i = ele->i + (ele->j)*nRow;
}
sort(inputVector->begin(), inputVector->end(),
CompMatrix::compareIJV);
for (int index = 0; index < size; ++index) {
CompMatrix::inputIJV* ele = inputVector->at(index);
ele->i = ele->i - (ele->j)*nRow;
}
}
bool CompMatrix::compareIJV(CompMatrix::inputIJV* a,
CompMatrix::inputIJV* b)
{
// sort by [i + j*nRow] (now this value is inserted in i)
// that is, sort by column-wise
if (a->i < b-> i) {
return true;
}
else if (a->i > b-> i){
return false;
}
return false; // a==b
}
void CompMatrix::checkInputDataStructure(int& i, int& j, double& v1, double& v2)
{
// if correct, minus numbers are assigned to (i,j)
// otherwise, the index of duplicate values are assigned to (i,j)
i = -100;
j = -100;
v1 = 0.0;
v2 = 0.0;
const int size = inputVector->size();
if (size == 0) {
return;
}
CompMatrix::inputIJV* ele = inputVector->at(0);
for (int index = 1; index < size; ++index) {
CompMatrix::inputIJV* eleNext = inputVector->at(index);
#if 0
printf("ele[%d] => i=%d, j=%d, v=%lf\n",
index-1, ele->i, ele->j, ele->v);
printf("eleNext[%d] => i=%d, j=%d, v=%lf\n",
index, eleNext->i, eleNext->j, eleNext->v);
#endif
if (ele->i == eleNext->i && ele->j == eleNext->j) {
i = ele->i;
j = ele->j;
v1 = ele->v;
v2 = eleNext->v;
return;
}
ele = eleNext;
}
}
void CompMatrix::makeInternalStructure()
{
// this routine should be called after checkInputVector
NNZ = inputVector->size();
// rMessage("NNZ = " << NNZ);
nzColumn = 0;
int oldColumn = -1;
for (int index = 0; index < NNZ; ++index) {
CompMatrix::inputIJV* ele1 = inputVector->at(index);
const int currentColumn = ele1->j;
if (currentColumn != oldColumn) {
nzColumn++;
oldColumn = currentColumn;
}
}
NewArray(column_index, int, nzColumn);
NewArray(column_start, int, nzColumn+1);
NewArray(diag_index, int, nzColumn);
NewArray(row_index, int, NNZ);
NewArray(agg_index, int, NNZ);
NewArray(blockNumber, int, NNZ);
NewArray(blockIndex, int, NNZ);
NewArray(ele, double, NNZ);
for (int index1=0; index1 < nzColumn; ++index1) {
diag_index[index1] = -1; // -1 means "not assiged"
}
for (int index1=0; index1 < NNZ; ++index1) {
agg_index[index1] = -1; // -1 means "not assiged"
}
column_start[nzColumn] = NNZ;
oldColumn = -1;
lowerNNZ = 0;
int columnIndex = -1; // this should be -1 precisely
for (int index1=0; index1 < NNZ; ++index1) {
CompMatrix::inputIJV* ele1 = inputVector->at(index1);
#if 0
rMessage("i = " << ele1->i << ": j = " << ele1->j
<< ": value = " << ele1->v);
#endif
const int currentColumn = ele1->j;
if (currentColumn != oldColumn) {
columnIndex++;
column_index[columnIndex] = currentColumn;
column_start[columnIndex] = index1;
oldColumn = currentColumn;
}
if (diag_index[columnIndex] == -1 && ele1->i >= ele1->j) {
diag_index[columnIndex] = index1;
}
if (diag_index[columnIndex] >= 0) {
lowerNNZ++;
}
row_index[index1] = ele1->i;
ele[index1] = ele1->v;
DeleteArray(ele1);
}
DeleteArray(inputVector);
effectiveNzColumn = nzColumn;
for (int ncol = 0; ncol < nzColumn; ++ncol) {
if (diag_index[ncol] == -1) { // only upper part
effectiveNzColumn--;
}
}
nzColumn_diag = 0;
nzColumn_nondiag = 0;
for (int ncol = 0; ncol < nzColumn; ++ncol) {
if (diag_index[ncol] == -1) {
continue;
}
const int j = column_index[ncol];
if (row_index[diag_index[ncol]] == j) {
nzColumn_diag++;
}
else {
nzColumn_nondiag++;
}
}
NewArray(column_diag_index, int, nzColumn_diag);
NewArray(column_nondiag_index, int, nzColumn_nondiag);
nzColumn_diag = 0;
nzColumn_nondiag = 0;
for (int ncol = 0; ncol < nzColumn; ++ncol) {
if (diag_index[ncol] == -1) {
continue;
}
const int j = column_index[ncol];
if (row_index[diag_index[ncol]] == j) {
column_diag_index[nzColumn_diag] = ncol;
nzColumn_diag++;
}
else {
column_nondiag_index[nzColumn_nondiag] = ncol;
nzColumn_nondiag++;
}
}
}
void CompMatrix::assignAgg(CholmodMatrix& cholmodMatrix)
{
cholmod_sparse* Z = cholmodMatrix.Z;
// agg_index in Aggregate-matrix is already computed in indexAgg
for (int ncol = 0; ncol < nzColumn; ++ncol) {
const int j = column_index[ncol];
if (diag_index[ncol] < 0) {
continue;
}
// column_index of aggregate should contain all columns
const int agg_start = ((int*)Z->p)[j];
const int agg_end = ((int*)Z->p)[j+1];
int index2 = agg_start;
// only lower elements will have valid agg_index
for (int index1 = diag_index[ncol];
index1 < column_start[ncol+1]; ++index1) {
const int i = row_index[index1];
// Next 'while' must find target,
// because Aggregate must contain this information
while (i != ((int*)Z->i)[index2]) {
index2++;
}
agg_index[index1] = index2;
}
}
}
void CompMatrix::assignBlockIndex(OrderingMatrix& order)
{
for (int j_index = 0; j_index < nzColumn; ++j_index) {
int j = column_index[j_index];
const int row_start = column_start[j_index];
const int row_end = column_start[j_index+1];
for (int i_index = row_start; i_index < row_end; ++i_index) {
const int i = row_index[i_index];
order.getIndex(i,j,blockNumber[i_index],blockIndex[i_index]);
}
}
}
CompSpace::CompSpace()
{
initialize();
}
CompSpace::~CompSpace()
{
finalize();
}
void CompSpace::initialize()
{
LP_sp_nBlock = 0;
SDP_sp_nBlock = 0;
LP_sp_index = NULL;
SDP_sp_index = NULL;
LP_sp_block = NULL;
SDP_sp_block = NULL;
NNZ = 0;
lowerNNZ = 0;
}
void CompSpace::initialize(int LP_sp_nBlock,
int SDP_sp_nBlock)
{
initialize();
this->LP_sp_nBlock = LP_sp_nBlock;
this->SDP_sp_nBlock = SDP_sp_nBlock;
if (LP_sp_nBlock > 0) {
NewArray(this->LP_sp_index, int, LP_sp_nBlock);
NewArray(this->LP_sp_block, double, LP_sp_nBlock);
}
if (SDP_sp_nBlock > 0) {
NewArray(this->SDP_sp_index, int, SDP_sp_nBlock);
NewArray(this->SDP_sp_block, CompMatrix, SDP_sp_nBlock);
}
}
void CompSpace::finalize()
{
for (int index = 0; index < SDP_sp_nBlock; ++index) {
SDP_sp_block[index].finalize();
}
DeleteArray(LP_sp_index);
DeleteArray(SDP_sp_index);
DeleteArray(LP_sp_block);
DeleteArray(SDP_sp_block);
LP_sp_nBlock = 0;
SDP_sp_nBlock = 0;
}
void CompSpace::display(FILE* fpout, char* printFormat)
{
if (fpout == NULL) {
return;
}
// fprintf(fpout, "Display start \n");
fprintf(fpout, "== LP block== LP_sp_nBlock = %d\n", LP_sp_nBlock);
for (int index1=0; index1 < LP_sp_nBlock; ++index1) {
fprintf(fpout, "[%d,%d] = ", LP_sp_index[index1], LP_sp_index[index1]);
fprintf(fpout, printFormat, LP_sp_block[index1]);
fprintf(fpout, "\n");
}
fprintf(fpout, "==SDP block== SDP_sp_nBlock = %d\n", SDP_sp_nBlock);
for (int index1=0; index1 < SDP_sp_nBlock; ++index1) {
fprintf(fpout, "-- %d-th(%d-th in full) block --\n",
index1, SDP_sp_index[index1]);
SDP_sp_block[index1].display(fpout, printFormat);
}
// fprintf(fpout, "Display end \n");
}
void CompSpace::initializeInputVector()
{
for (int index=0; index < SDP_sp_nBlock; ++index) {
SDP_sp_block[index].initializeInputVector();
}
}
void CompSpace::setElement_LP(int i, double v)
{
int index = 0;
for (index=0; index < LP_sp_nBlock; ++index) {
if (i == LP_sp_index[index]) {
break;
}
}
if (index == LP_sp_nBlock) {
rError("Out of LP_sp_nBlock :: code bug");
}
LP_sp_block[index] = v;
}
void CompSpace::setElement_SDP(int l, int i, int j, double v)
{
int index1 = 0;
for (index1=0; index1 < SDP_sp_nBlock; ++index1) {
if (l == SDP_sp_index[index1]) {
break;
}
}
if (index1 == SDP_sp_nBlock) {
rError("Out of SDP_sp_nBlock :: code bug");
}
SDP_sp_block[index1].setElement(i,j,v);
}
void CompSpace::sortInputVector()
{
for (int l=0; l < SDP_sp_nBlock; ++l) {
SDP_sp_block[l].sortInputVector();
}
}
void CompSpace::makeInternalStructure()
{
NNZ = LP_sp_nBlock;
lowerNNZ = LP_sp_nBlock;
for (int l=0; l < SDP_sp_nBlock; ++l) {
SDP_sp_block[l].makeInternalStructure();
NNZ += SDP_sp_block[l].NNZ;
lowerNNZ += SDP_sp_block[l].lowerNNZ;
}
}
void CompSpace::checkInputDataStructure(int& l, int& i, int& j,
double& v1, double& v2)
{
for (l=0; l<SDP_sp_nBlock; ++l) {
SDP_sp_block[l].checkInputDataStructure(i,j,v1,v2);
if (i >=0) {
// found error
l = SDP_sp_index[l];
return;
}
}
l = -100; // to indicate correctness, l is set to minus
}
void CompSpace::assignAgg(CholmodSpace& Aggregate)
{
for (int l=0; l<SDP_sp_nBlock; ++l) {
SDP_sp_block[l].assignAgg(Aggregate.SDP_block[l]);
}
}
void CompSpace::assignBlockIndex(OrderingSpace& order)
{
for (int l=0; l<SDP_sp_nBlock; ++l) {
SDP_sp_block[l].assignBlockIndex(order.SDP_block[SDP_sp_index[l]]);
}
}
CliqueMatrix::CliqueMatrix()
{
initialize();
}
CliqueMatrix::~CliqueMatrix()
{
finalize();
}
void CliqueMatrix::initialize()
{
nBlock = 0;
blockStruct = NULL;
ele = NULL;
}
void CliqueMatrix::initialize(int nBlock, int* blockStruct)
{
this->nBlock = nBlock;
NewArray(this->blockStruct, int, nBlock);
NewArray(ele, DenseMatrix, nBlock);
for (int index1=0; index1 < nBlock; ++index1) {
this->blockStruct[index1] = blockStruct[index1];
ele[index1].initialize(blockStruct[index1], blockStruct[index1]);
}
}
void CliqueMatrix::finalize()
{
if (nBlock > 0) {
DeleteArray(blockStruct);
for (int index = 0; index < nBlock; ++index) {
ele[index].finalize();
}
DeleteArray(ele);
}
}
void CliqueMatrix::display(FILE* fpout, char* printFormat)
{
if (fpout == NULL) {
return;
}
fprintf(fpout, "CliqueMatrix::display nBlock = %d\n", nBlock);
for (int index = 0; index < nBlock; ++index) {
fprintf(fpout, "%d-th block\n", index);
ele[index].display(fpout, printFormat);
}
fprintf(fpout, "CliqueMatrix::display end \n", nBlock);
}
void CliqueMatrix::setZero()
{
for (int index = 0; index < nBlock; ++index) {
ele[index].setZero();
}
}
void CliqueMatrix::setIdentity(double scalar)
{
for (int index1 = 0; index1 < nBlock; ++index1) {
ele[index1].setIdentity(scalar);
}
}
CliqueSpace::CliqueSpace()
{
initialize();
}
CliqueSpace::~CliqueSpace()
{
finalize();
}
void CliqueSpace::initialize()
{
LP_nBlock = 0;
SDP_nBlock = 0;
LP_block = NULL;
SDP_block = NULL;
}
void CliqueSpace::initialize(BlockStruct& bs,
OrderingSpace& order)
{
int LP_nBlock = bs.LP_nBlock;
int SDP_nBlock = bs.SDP_nBlock;
this->LP_nBlock = LP_nBlock;
this->SDP_nBlock = SDP_nBlock;
NewArray(LP_block, double, LP_nBlock);
NewArray(SDP_block, CliqueMatrix, SDP_nBlock);
for (int l=0; l<SDP_nBlock; ++l) {
OrderingMatrix& orderMatrix = order.SDP_block[l];
this->SDP_block[l].initialize(orderMatrix.nClique,
orderMatrix.cliqueSize);
}
}
void CliqueSpace::finalize()
{
if (LP_nBlock > 0) {
DeleteArray(LP_block);
LP_nBlock = 0;
}
if (SDP_nBlock > 0) {
for (int index = 0; index < SDP_nBlock; ++index) {
SDP_block[index].finalize();
}
DeleteArray(SDP_block);
SDP_nBlock = 0;
}
}
void CliqueSpace::display(FILE* fpout, char* printFormat)
{
if (fpout == NULL) {
return;
}
fprintf(fpout, "== LP Part, LP_nBlock = %d ==\n", LP_nBlock);
for (int index=0; index < LP_nBlock; ++index) {
fprintf(fpout, printFormat, LP_block[index]);
}
fprintf(fpout, "== SDP Part, SDP_nBlock = %d ==\n", SDP_nBlock);
for (int index=0; index < SDP_nBlock; ++index) {
SDP_block[index].display(fpout, printFormat);
}
}
void CliqueSpace::setZero()
{
for (int l=0; l<LP_nBlock; ++l) {
LP_block[l] = 0.0;
}
for (int l=0; l<SDP_nBlock; ++l) {
SDP_block[l].setZero();
}
}
void CliqueSpace::setIdentity(double scalar)
{
for (int l=0; l<LP_nBlock; ++l) {
LP_block[l] = scalar;
}
for (int l=0; l<SDP_nBlock; ++l) {
SDP_block[l].setIdentity(scalar);
}
}
OrderingMatrix::OrderingMatrix()
{
initialize();
}
OrderingMatrix::~OrderingMatrix()
{
finalize();
}
void OrderingMatrix::initialize()
{
nClique = 0;
cliqueSize = NULL;
cliqueIndex = NULL;
nDim = 0;
Perm = NULL;
ReversePerm = NULL;
dXtNonzeros = NULL;
dXtIndex = NULL;
dXtClique = NULL;
dXtBlock = NULL;
}
void OrderingMatrix::initialize(int nDim)
{
this->nDim = nDim;
}
void OrderingMatrix::finalize()
{
if (nClique > 0) {
DeleteArray(cliqueSize);
for (int index1 = 0; index1<nClique; ++index1) {
DeleteArray(cliqueIndex[index1]);
}
DeleteArray(cliqueIndex);
nClique = 0;
}
// Perm is alias of L->Perm, do not delete Perm here
DeleteArray(ReversePerm);
if (dXtNonzeros != NULL) {
for (int index1 = 0; index1 < nDim; ++index1) {
DeleteArray(dXtIndex[index1]);
DeleteArray(dXtClique[index1]);
DeleteArray(dXtBlock[index1]);
}
DeleteArray(dXtIndex);
DeleteArray(dXtClique);
DeleteArray(dXtBlock);
DeleteArray(dXtNonzeros);
}
}
void OrderingMatrix::getIndex(int i, int j, int& blockNumber, int& blockIndex)
{
// A(i,j) = APerm(iPerm,jPerm)
int iPerm = ReversePerm[i];
int jPerm = ReversePerm[j];
// Find the clique which has both iPerm & jPerm
// If this fails, it means a bug.
// Find iPerm & jPerm from the last clique to the first clique
// The last clique has more elements, so it should be
// accessed as many time as possible.
// Lower-triangular, that is, iPerm >= jPerm
if (iPerm < jPerm) {
int tmpPerm = iPerm;
iPerm = jPerm;
jPerm = tmpPerm;
}
int iIndex = -1; // dummy initialize
int jIndex = -1; // dummy initialize
int cIndex = nClique-1;
for ( /* nothing */ ; cIndex >=0 ; cIndex--) {
const int length = cliqueSize[cIndex];
int index1 = 0;
// find jPerm
for (/* nothing */; index1 < length; ++ index1) {
if (cliqueIndex[cIndex][index1] == jPerm) {
break;
}
}
jIndex = index1;
for (/* nothing */; index1 < length; ++ index1) {
if (cliqueIndex[cIndex][index1] == iPerm) {
break;
}
}
iIndex = index1;
if (jIndex < length && iIndex < length) {
// found both iPerm & jPerm
break;
}
}
if (cIndex < 0) {
rMessage("Ordering display"); display();
rMessage("i = " << i << " : j = " << j);
rError("Code bug here.");
}
blockNumber = cIndex;
blockIndex = iIndex + jIndex*cliqueSize[cIndex];
}
void OrderingMatrix::extractCliques(CholmodMatrix& C)
{
if (nDim == 0) {
rError("OrderingMatrix is not initialized");
}
cholmod_factor* L = C.Lz;
// L is already set by analyze();
// This function will initialize the structure of OrderingMatrix
nClique = L->nsuper;
// rMessage("nClique = " << nClique);
NewArray(cliqueSize, int, nClique);
NewArray(cliqueIndex, int*, nClique);
int* super = (int*) (L->super);
for (int s = 0; s < nClique; ++s) {
int start_column = super[s];
int end_column = super[s+1];
const int psi = ((int*)L->pi)[s];
const int psiend = ((int*)L->pi)[s+1];
const int nsrow = psiend-psi;
cliqueSize[s] = nsrow;
#if 0
rMessage("clique["<<s<<"] = "
<< "column[" << start_column << ":" << end_column << "] "
<< "row[" << psi << ":" << psiend << "]");
#endif
NewArray(cliqueIndex[s], int, nsrow);
for (int index_i = 0; index_i < nsrow; ++index_i) {
int i = ((int*)L->s)[psi+index_i];
cliqueIndex[s][index_i] = i;
}
}
Perm = (int*) L->Perm;
NewArray(ReversePerm, int, L->n);
for (size_t index1 = 0; index1 < L->n; ++index1) {
ReversePerm[Perm[index1]] = index1;
}
vector<OrderingMatrix::ISB*>* tmpVector;
NewArray(tmpVector, vector<OrderingMatrix::ISB*>, nDim);
for (int s = 0; s < nClique; ++s) {
const int length = cliqueSize[s];
for (int j_index = 0; j_index < length; ++j_index) {
const int j = Perm[cliqueIndex[s][j_index]];
// since dX~tilde is not symmetric,
// we have to add both lower and upper triangular information
for (int i_index = 0; i_index < length; ++i_index) {
OrderingMatrix::ISB* tmpISB;
NewArray(tmpISB, OrderingMatrix::ISB, 1);
const int i = Perm[cliqueIndex[s][i_index]];
tmpISB[0].i = i;
tmpISB[0].s = s;
tmpISB[0].b = i_index + j_index*length;
tmpVector[j].push_back(tmpISB);
}
}
}
NewArray(dXtNonzeros, int, nDim);
NewArray(dXtIndex, int*, nDim);
NewArray(dXtClique, int*, nDim);
NewArray(dXtBlock, int*, nDim);
for (int j=0; j<nDim; ++j) {
sort(tmpVector[j].begin(), tmpVector[j].end(),
OrderingMatrix::compareISB);
dXtNonzeros[j] = tmpVector[j].size();
const int length = dXtNonzeros[j];
NewArray(dXtIndex[j], int, length);
NewArray(dXtClique[j], int, length);
NewArray(dXtBlock[j], int, length);
for (int index=0; index<length; ++index) {
OrderingMatrix::ISB* tmpISB = tmpVector[j].at(index);
dXtIndex [j][index] = tmpISB->i;
dXtClique[j][index] = tmpISB->s;
dXtBlock [j][index] = tmpISB->b;
DeleteArray(tmpISB);
}
}
DeleteArray(tmpVector);
}
void OrderingMatrix::displayDxIndex(FILE* fpout, char* printFormat)
{
if (dXtNonzeros == NULL) {
fprintf(fpout, "dXtNonzeros is not set yet\n");
}
else {
for (int k=0; k<nDim; ++k) {
for (int index1 = 0; index1 < dXtNonzeros[k]; ++index1) {
fprintf(fpout, "[dX~]_{%d,%d} => ", dXtIndex[k][index1], k);
fprintf(fpout, "cl{%d}(%d)\n", dXtClique[k][index1],
dXtBlock[k][index1]);
}
}
}
}
void OrderingMatrix::display(FILE* fpout, char* printFormat)
{
if (fpout == NULL) {
return;
}
if (nClique > 0) {
fprintf(fpout, "nClique = %d\n", nClique);
fprintf(fpout, "cliqueSize = ");
for (int s=0; s<nClique; ++s) {
fprintf(fpout, "%d ", cliqueSize[s]);
}
fprintf(fpout, "\n");
for (int s=0; s<nClique; ++s) {
fprintf(fpout, "clique[%d] = ", s);
for (int i=0; i<cliqueSize[s]; ++i) {
fprintf(fpout, "%d ", cliqueIndex[s][i]);
}
fprintf(fpout, "\n");
}
}
if (Perm == NULL || ReversePerm == NULL) {
fprintf(fpout, "Perm & ReversePerm is not set yet\n");
}
else {
fprintf(fpout, "nDim = %d\n", nDim);
fprintf(fpout, " Perm = ");
for (int j=0; j<nDim; ++j) {
fprintf(fpout, "%d ", Perm[j]);
}
fprintf(fpout, "\n");
fprintf(fpout, "ReversePerm = ");
for (int j=0; j<nDim; ++j) {
fprintf(fpout, "%d ", ReversePerm[j]);
}
fprintf(fpout, "\n");
}
}
void OrderingMatrix::displayStatistics(FILE* fpout, CholmodMatrix& cholmodMatrix)
{
switch(cholmodMatrix.common.selected) {
case 0:
fprintf(fpout, "user-provided ordering (cholmod_analyze_p only)");
break;
case 1:
fprintf(fpout, "AMD (for both A and A*A')");
break;
case 2:
fprintf(fpout, "METIS");
break;
case 3:
fprintf(fpout, "CHOLMOD's nested dissection (NESDIS), default parameters");
break;
case 4:
fprintf(fpout, "natural");
break;
case 5:
fprintf(fpout, "NESDIS with nd_small = 20000");
break;
case 6:
fprintf(fpout, "NESDIS with nd_small = 4, no constrained minimum degree");
break;
case 7:
fprintf(fpout, "NESDIS with no dense node removal");
break;
case 8:
fprintf(fpout, "AMD for A, COLAMD for A*A'");
break;
default:
fprintf(fpout, "Not selected");
}
fprintf(fpout, "\n");
int NNZ_Z = cholmodMatrix.NNZ_Z;
int NNZ_L = cholmodMatrix.NNZ_Z;
int NNZ_A = NNZ_L - NNZ_Z;
int nDim = cholmodMatrix.nDim;
int full = nDim*(nDim+1)/2;
double perZ = (double) NNZ_Z / (double) (full) * 100.0;
double perL = (double) NNZ_Z / (double) (full) * 100.0;
double perA = (double) NNZ_A / (double) (full) * 100.0;
fprintf(fpout, "NNZ_Z = %d (%.3e%%), NNZ_L = %d (%.3e%%), add = %d (%.3e%%), full = %d, nDim = %d\n",
NNZ_Z, perZ, NNZ_L, perL, NNZ_A, perA, full, nDim);
fprintf(fpout, "nClique = %d : ", nClique);
#if 0
fprintf(fpout, "cliqueSize = ");
for (int s=0; s<nClique-1; ++s) {
fprintf(fpout, "%d, ", cliqueSize[s]);
}
fprintf(fpout, "%d\n", cliqueSize[nClique-1]);
#endif
int sumClique = 0;
int maxClique = 0;
for (int s=0; s<nClique; ++s) {
sumClique += cliqueSize[s];
if (cliqueSize[s] > maxClique) {
maxClique = cliqueSize[s];
}
}
fprintf(fpout, " sum = %d, ave = %.2f, max = %d\n",
sumClique, (double) sumClique / (double) nClique, maxClique);
}
bool OrderingMatrix::compareISB(OrderingMatrix::ISB* a, OrderingMatrix::ISB* b)
{
if (a->i < b->i) {
return true;
}
if (a->i > b->i) {
return false;
}
if (a->s < b->s) {
return true;
}
if (a->s > b->s) {
return false;
}
if (a->b < b->b) {
return true;
}
if (a->b > b->b) {
return false;
}
return false; // a==b
}
OrderingSpace::OrderingSpace()
{
initialize();
}
OrderingSpace::~OrderingSpace()
{
finalize();
}
void OrderingSpace::initialize()
{
SDP_nBlock = 0;
SDP_block = NULL;
// Memory assignment will be done by
// extractCliques()
}
void OrderingSpace::initialize(int SDP_nBlock, int* SDP_blockStruct)
{
this->SDP_nBlock = SDP_nBlock;
if (SDP_nBlock > 0 ) {
NewArray(SDP_block, OrderingMatrix, SDP_nBlock);
for (int l = 0; l < SDP_nBlock; ++l) {
SDP_block[l].initialize(SDP_blockStruct[l]);
}
}
}
void OrderingSpace::finalize()
{
if (SDP_nBlock > 0 ) {
for (int l = 0; l < SDP_nBlock; ++l) {
SDP_block[l].finalize();
}
DeleteArray(SDP_block);
SDP_nBlock = 0;
}
}
void OrderingSpace::display(FILE* fpout, char* printFormat)
{
if (fpout == NULL) {
return;
}
if (SDP_nBlock > 0) {
for (int index1 = 0; index1 < SDP_nBlock; ++index1) {
fprintf(fpout, "Block = %d\n", index1);
SDP_block[index1].display(fpout, printFormat);
}
}
}
void OrderingSpace::displayStatistics(FILE* fpout, CholmodSpace& cholmodSpace)
{
if (fpout == NULL) {
return;
}
if (SDP_nBlock > 0) {
for (int index1 = 0; index1 < SDP_nBlock; ++index1) {
fprintf(fpout, "[SDP %d-th Block] : order = ", index1);
SDP_block[index1].displayStatistics(fpout,
cholmodSpace.SDP_block[index1]);
}
}
}
void OrderingSpace::displayDxIndex(FILE* fpout, char* printFormat)
{
if (fpout == NULL) {
return;
}
if (SDP_nBlock > 0) {
for (int index1 = 0; index1 < SDP_nBlock; ++index1) {
fprintf(fpout, "Block = %d\n", index1);
SDP_block[index1].displayDxIndex(fpout, printFormat);
}
}
}
void OrderingSpace::extractCliques(CholmodSpace& C)
{
for (int l=0; l < SDP_nBlock; ++l) {
SDP_block[l].extractCliques(C.SDP_block[l]);
}
}
CholmodMatrix::CholmodMatrix()
{
initialize();
}
CholmodMatrix::~CholmodMatrix()
{
finalize();
}
void CholmodMatrix::initialize()
{
nDim = 0; // nDim will be set by extractCliques
Z = NULL;
Lz = NULL;
Lx = NULL;
x_x = NULL;
x_z = NULL;
b_x = NULL;
b_z = NULL;
cholmod_start(&common);
common.supernodal = CHOLMOD_SUPERNODAL;
common.final_super = 1;
common.nrelax[0] = 4; // default 4
common.nrelax[1] = 16; // default 16
common.nrelax[2] = 48; // default 48
NNZ_Z = 0;
NNZ_L = 0;
Z_blockNumber = NULL;
Z_blockIndex = NULL;
}
void CholmodMatrix::finalize()
{
nDim = 0;
if (Z != NULL) {
cholmod_free_sparse(&Z,&common);
Z = NULL;
}
if (Lz != NULL) {
cholmod_free_factor(&Lz,&common);
Lz = NULL;
}
if (Lx != NULL) {
cholmod_free_factor(&Lx,&common);
Lx = NULL;
}
if (x_x != NULL) {
cholmod_free_dense(&x_x,&common);
x_x = NULL;
}
if (x_z != NULL) {
cholmod_free_dense(&x_z,&common);
x_z = NULL;
}
if (b_x != NULL) {
cholmod_free_dense(&b_x,&common);
b_x = NULL;
}
if (b_z != NULL) {
cholmod_free_dense(&b_z,&common);
b_z = NULL;
}
if (dZ != NULL) {
cholmod_free_sparse(&dZ,&common);
dZ = NULL;
}
if (rD != NULL) {
cholmod_free_sparse(&rD,&common);
rD = NULL;
}
cholmod_finish(&common);
DeleteArray(Z_blockNumber);
DeleteArray(Z_blockIndex);
}
void CholmodMatrix::display(FILE* fpout, char* printFormat)
{
if (fpout == NULL) {
return;
}
if (Z == NULL) {
rMessage("Each matrix is not set yet.");
return;
}
fprintf(fpout, "CholmodMatrix::display =start=============\n");
fprintf(fpout, "Z = \n");
display_sparse(Z, fpout, printFormat);
fprintf(fpout, "dZ = \n");
display_sparse(dZ, fpout, printFormat);
fprintf(fpout, "rD = \n");
display_sparse(rD, fpout, printFormat);
fprintf(fpout, "Lz = \n");
display_factor(Lz, fpout, printFormat);
fprintf(fpout, "Lx = \n");
display_factor(Lx, fpout, printFormat);
fprintf(fpout, "clique_xMat = \n");
clique_xMat.display(fpout, printFormat);
fprintf(fpout, "clique_choleskyX = \n");
clique_choleskyX.display(fpout, printFormat);
fprintf(fpout, "clique_invCholeskyX = \n");
clique_invCholeskyX.display(fpout, printFormat);
fprintf(fpout, "clique_dX = \n");
clique_dX.display(fpout, printFormat);
#if 0
fprintf(fpout, "b_z = \n");
display_dense(b_z, fpout, printFormat);
if (x_z == NULL) {
rMessage("x_z is not set yet.");
}
else {
fprintf(fpout, "x_z = \n");
display_dense(x_z, fpout, printFormat);
}
fprintf(fpout, "b_x = \n");
display_dense(b_x, fpout, printFormat);
if (x_x == NULL) {
rMessage("x_x is not set yet.");
}
else {
fprintf(fpout, "x_x = \n");
display_dense(x_x, fpout, printFormat);
}
#endif
fprintf(fpout, "CholmodMatrix::display = end =============\n");
}
void CholmodMatrix::display_sparse(cholmod_sparse* A,
FILE* fpout, char* printFormat)
{
fprintf(fpout, "NNZ = %d\n", A->nzmax);
const int ncol = (int) A->ncol;
for (int j=0; j < ncol; ++j) {
const int start_row = ((int*)A->p)[j];
const int end_row = ((int*)A->p)[j+1];
for (int i_index = start_row; i_index < end_row; ++i_index) {
const int i = (( int*)A->i)[i_index];
const double value = ((double*)A->x)[i_index];
fprintf(fpout, "%d,%d,",i,j);
fprintf(fpout, printFormat, value);
fprintf(fpout, "\n");
}
}
}
void CholmodMatrix::display_factor(cholmod_factor* L,
FILE* fpout, char* printFormat)
{
const int nsuper = L->nsuper;
const int* super = (int*) L->super;
const int* Ls = (int*) L->s;
const int* Lpi = (int*) L->pi;
const int* Lpx = (int*) L->px;
const double* Lx = (double*) L->x;
const int xtype = L->xtype;
fprintf(fpout, "noOfSupernode = %d\n", nsuper);
for (int s=0; s<nsuper; ++s) {
const int start_column = super[s];
const int end_column = super[s+1];
fprintf(fpout, "=== supernode %d [%d:%d] ===\n",
s, start_column, end_column);
const int psi = Lpi[s];
const int psiend = Lpi[s+1];
const int nsrow = psiend - psi;
const int nscol = end_column - start_column;
const int psx = Lpx[s];
const int psxend = Lpx[s+1];
fprintf(fpout,
"psi = %d, psiend = %d, nsrow = %d, nscol = %d, "
"psx = %d, psxend = %d\n",
psi, psiend, nsrow, nscol, psx, psxend);
if (xtype != CHOLMOD_REAL) {
rMessage("xtype is not assigned yet.");
}
else {
for (int j_index = 0; j_index < nscol; ++j_index) {
const int j = start_column + j_index;
for (int i_index = 0; i_index < nsrow; ++i_index) {
const int i = Ls[psi + i_index];
const double value = Lx[psx + i_index + nsrow * j_index];
fprintf(fpout, "%d,%d,", i,j);
fprintf(fpout, printFormat, value);
fprintf(fpout, "\n");
}
}
}
}
}
void CholmodMatrix::display_dense(cholmod_dense* X,
FILE* fpout, char* printFormat)
{
const int nrow = (int) X->nrow;
const int ncol = (int) X->ncol;
const double* x = (double*) X->x;
fprintf(fpout, "[\n");
for (int i=0; i<nrow; ++i) {
for (int j=0; j<ncol-1; ++j) {
fprintf(fpout, printFormat, x[i+j*nrow]);
fprintf(fpout, ", ");
}
fprintf(fpout, printFormat, x[i+(ncol-1)*nrow]);
fprintf(fpout, ";\n");
}
fprintf(fpout,"]\n");
}
void CholmodMatrix::analyze()
{
// Z is already set by CholmodSpace
Lz = cholmod_analyze(Z, &common);
/*
int cholmod_change_factor(int to_xtype, int to_ll, int to_super,
int to_packed, int to_monotonic, cholmod_factor *L,
cholmod_common *Common) ;
*/
cholmod_change_factor(CHOLMOD_REAL, TRUE, TRUE, TRUE, TRUE, Lz, &common);
NNZ_L = common.lnz;
Lx = cholmod_copy_factor(Lz, &common);
cholmod_change_factor(CHOLMOD_REAL, TRUE, TRUE, TRUE, TRUE, Lx, &common);
dZ = cholmod_copy_sparse(Z, &common);
rD = cholmod_copy_sparse(Z, &common);
}
void CholmodMatrix::solveByZ()
{
if (x_z!=NULL) {
cholmod_free_dense(&x_z,&common);
// x is automatically allocated by cholmod_solve
}
cholmod_dense* b2 = cholmod_solve(CHOLMOD_P, Lz, b_z, &common);
cholmod_dense* x_z2 = cholmod_solve(CHOLMOD_LDLt, Lz, b2, &common);
x_z = cholmod_solve(CHOLMOD_Pt, Lz, x_z2, &common);
#if 0
rMessage("b_z = "); display_dense(b_z);
rMessage("b2 = "); display_dense(b2);
rMessage("x_z2 = "); display_dense(x_z2);
rMessage("x_z = "); display_dense(x_z);
#endif
cholmod_free_dense(&b2,&common);
cholmod_free_dense(&x_z2,&common);
#if 0
// This part is to check the relation between Perm and CHOLMOD_P
int n = Lz->n;
double* b_z_ele = (double*) b_z->x;
for (int i=0; i<n; ++i) {
b_z_ele[i] = i;
}
cholmod_dense* b3 = cholmod_solve(CHOLMOD_P, Lz, b_z, &common);
rMessage("b3 = "); display_dense(b3);
cholmod_free_dense(&b3,&common);
#endif
}
void CholmodMatrix::solveByX()
{
if (x_x!=NULL) {
cholmod_free_dense(&x_x,&common);
// x is automatically allocated by cholmod_solve
}
// x_x = cholmod_solve(CHOLMOD_LDLt, Lx, b_x, &common);
cholmod_dense* b_x2 = cholmod_solve(CHOLMOD_P, Lx, b_x, &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);
x_x = cholmod_solve(CHOLMOD_Pt, Lx, x_x2, &common);
#if 0
rMessage("b_x = "); display_dense(b_x);
rMessage("b_x2 = "); display_dense(b_x2);
rMessage("x_x3 = "); display_dense(x_x3);
rMessage("x_x2 = "); display_dense(x_x2);
rMessage("x_x = "); display_dense(x_x);
#endif
cholmod_free_dense(&b_x2,&common);
cholmod_free_dense(&x_x3,&common);
cholmod_free_dense(&x_x2,&common);
}
void CholmodMatrix::assignBlockIndex(OrderingMatrix& order)
{
NewArray(Z_blockNumber, int, NNZ_Z);
NewArray(Z_blockIndex, int, NNZ_Z);
for (int j = 0; j < (int) Z->ncol; ++j) {
const int row_start = ((int*) Z->p)[j];
const int row_end = ((int*) Z->p)[j+1];
for (int i_index = row_start; i_index < row_end; ++i_index) {
const int i = ((int*)Z->i)[i_index];
order.getIndex(i,j, Z_blockNumber[i_index], Z_blockIndex[i_index]);
}
}
}
void CholmodMatrix::setZero_sparse(cholmod_sparse* A)
{
const int length = A->nzmax;
for (int index1=0;index1 < length; ++index1) {
((double*)(A->x))[index1] = 0.0;
}
}
void CholmodMatrix::setZzero()
{
setZero_sparse(Z);
}
void CholmodMatrix::setZIdentity(double scalar)
{
for (int index1=0; index1 < NNZ_Z; ++index1) {
((double*)(Z->x))[index1] = 0.0;
}
const int ncol = Z->ncol;
for (int j=0; j < ncol; ++j) {
const int start_row = ((int*)Z->p)[j];
const int i = ((int*)Z->i)[start_row];
if (i != j) { // First element should be diagonal
rMessage("Diagonal elements not found in (" << i
<< "," << j << ").");
rError("code bug");
}
((double*)(Z->x))[start_row] = scalar;
}
}
void CholmodMatrix::setXIdentity(double scalar)
{
clique_xMat.setIdentity(scalar);
}
void CholmodMatrix::setB_Zzero()
{
for (int index1=0;index1 < nDim; ++index1) {
((double*)(b_z->x))[index1] = 0.0;
}
}
void CholmodMatrix::setB_Xzero()
{
for (int index1=0;index1 < nDim; ++index1) {
((double*)(b_x->x))[index1] = 0.0;
}
}
void CholmodMatrix::setDxZero()
{
clique_dX.setZero();
}
void CholmodMatrix::initializeClique(OrderingMatrix& order)
{
clique_dX.initialize(order.nClique, order.cliqueSize);
clique_xMat.initialize(order.nClique, order.cliqueSize);
clique_choleskyX.initialize(order.nClique, order.cliqueSize);
clique_invCholeskyX.initialize(order.nClique, order.cliqueSize);
}
bool CholmodMatrix::getCholesky(OrderingMatrix& order)
{
cholmod_factorize(Z, Lz, &common);
#if 0
rMessage("Z before Cholesky = "); CholmodMatrix::display_sparse(Z);
rMessage("Lz after Cholesky = "); CholmodMatrix::display_factor(Lz);
#endif
bool total_judge = SDPA_SUCCESS;
for (int l = 0; l<clique_xMat.nBlock; ++l) {
bool judge = SDPA_SUCCESS;
DenseMatrix& target1 = clique_xMat.ele[l];
// reverse the order
// note Cholesky should be, not X=LL^T, but X^{-1} = LL^T
const int length = target1.nRow * target1.nCol;
for (int ind1 = 0; ind1 < length/2; ++ind1) {
double dtmp = target1.de_ele[ind1];
target1.de_ele[ind1] = target1.de_ele[length-1 - ind1];
target1.de_ele[length-1 - ind1] = dtmp;
}
judge = Lal::getCholesky(clique_choleskyX.ele[l], clique_xMat.ele[l]);
if (judge == SDPA_FAILURE) {
return SDPA_FAILURE;
}
for (int ind1 = 0; ind1 < length/2; ++ind1) {
double dtmp = target1.de_ele[ind1];
target1.de_ele[ind1] = target1.de_ele[length-1 - ind1];
target1.de_ele[length-1 - ind1] = dtmp;
}
Lal::getInvLowTriangularMatrix(clique_invCholeskyX.ele[l],
clique_choleskyX.ele[l]);
DenseMatrix& target2 = clique_invCholeskyX.ele[l];
for (int ind1 = 0; ind1 < length/2; ++ind1) {
double dtmp = target2.de_ele[ind1];
target2.de_ele[ind1] = target2.de_ele[length-1 - ind1];
target2.de_ele[length-1 - ind1] = dtmp;
}
// transpose
const int nRow = target2.nRow;
const int nCol = target2.nCol;
for (int i=0; i<nRow; ++i) {
for (int j=i; j<nCol; ++j) {
double dtmp = target2.de_ele[i+j*nRow];
target2.de_ele[i+j*nRow] = target2.de_ele[j+i*nRow];
target2.de_ele[j+i*nRow] = dtmp;
}
}
}
// copy from invCholeskyX to Lx
int* Ls = (int*) Lx->s;
int* Lpi = (int*) Lx->pi;
int* Lpx = (int*) Lx->px;
double* Lxx = (double*) Lx->x;
int* super = (int*) Lx->super;
int nsuper = (int) Lx->nsuper;
for (int s=0; s<nsuper; ++s) {
const int start_column = super[s];
const int end_column = super[s+1];
const int nscol = end_column - start_column;
DenseMatrix& target = clique_invCholeskyX.ele[s];
if (nscol > target.nCol) {
rError("coding bug");
}
const int start_row = Lpi[s];
const int end_row = Lpi[s+1];
const int nsrow = end_row - start_row;
int length = nsrow * nscol;
double* target_address = &Lxx[Lpx[s]];
dcopy_fc(&length, target.de_ele, &IONE, target_address, &IONE);
}
#if 0
rMessage("clique_xMat = "); clique_xMat.display();
rMessage("clique_choleskyX = "); clique_choleskyX.display();
rMessage("clique_invCholeskyX = "); clique_invCholeskyX.display();
rMessage("Lx after Cholesky = "); CholmodMatrix::display_factor(Lx);
#endif
return SDPA_SUCCESS;
}
CholmodSpace::CholmodSpace()
{
initialize();
}
CholmodSpace::~CholmodSpace()
{
finalize();
}
void CholmodSpace::initialize()
{
LP_nBlock = 0;
LP_Z = NULL;
LP_invZ = NULL;
LP_dZ = NULL;
LP_X = NULL;
LP_invX = NULL;
LP_dX = NULL;
LP_rD = NULL;
SDP_nBlock = 0;
}
void CholmodSpace::finalize()
{
DeleteArray(LP_Z);
DeleteArray(LP_invZ);
DeleteArray(LP_dZ);
DeleteArray(LP_X);
DeleteArray(LP_invX);
DeleteArray(LP_dX);
DeleteArray(LP_rD);
if (SDP_nBlock > 0) {
for (int index = 0; index<SDP_nBlock; ++index) {
SDP_block[index].finalize();
}
DeleteArray(SDP_block);
SDP_nBlock = 0;
}
}
void CholmodSpace::initialize(int LP_nBlock, int SDP_nBlock)
{
this->LP_nBlock = LP_nBlock;
this->SDP_nBlock = SDP_nBlock;
NewArray(LP_Z, double, LP_nBlock);
NewArray(LP_invZ, double, LP_nBlock);
NewArray(LP_dZ, double, LP_nBlock);
NewArray(LP_X, double, LP_nBlock);
NewArray(LP_invX, double, LP_nBlock);
NewArray(LP_dX, double, LP_nBlock);
NewArray(LP_rD, double, LP_nBlock);
NewArray(SDP_block, CholmodMatrix, SDP_nBlock);
// nClique is NOT initialized now
}
void CholmodSpace::makeAggregate(int m, int SDP_nBlock, int* SDP_blockStruct,
CompSpace& C, CompSpace* A)
{
vector<int>** tmpAggregate;
// tmpAggregate[l][j] contains row numbers (i) in vector
NewArray(tmpAggregate, vector<int>*, SDP_nBlock);
for (int l=0; l<SDP_nBlock; ++l) {
NewArray(tmpAggregate[l], vector<int>, SDP_blockStruct[l]);
// diagonal elements should be added anytime
for (int j=0; j<SDP_blockStruct[l]; ++j) {
tmpAggregate[l][j].push_back(j);
}
}
for (int k=0; k<=m; ++k) {
CompSpace* targetSpace = NULL;
if (k<m) {
targetSpace = &A[k];
}
else {
targetSpace = &C;
}
for (int l_index=0; l_index<targetSpace->SDP_sp_nBlock; ++l_index) {
const int l = targetSpace->SDP_sp_index[l_index];
CompMatrix& target = targetSpace->SDP_sp_block[l_index];
for (int j_index=0; j_index < target.nzColumn; ++j_index) {
const int j = target.column_index[j_index];
// only lower triangular part
const int row_start = target.diag_index[j_index];
const int row_end = target.column_start[j_index+1];
if (row_start < 0) {
continue;
}
for (int i_index = row_start; i_index < row_end; ++i_index) {
tmpAggregate[l][j].push_back(target.row_index[i_index]);
}
}
}
}
for (int l=0; l<SDP_nBlock; ++l) {
int NNZ_tmp = 0; // count memory space
for (int j=0; j<SDP_blockStruct[l]; ++j) {
sort(tmpAggregate[l][j].begin(), tmpAggregate[l][j].end());
#if 0
vector<int>& vec = tmpAggregate[l][j];
for (int i=0; i<vec.size(); ++i) {
printf("l = %d, j = %d, i= %d\n", l,j,vec[i]);
}
#endif
const int length = tmpAggregate[l][j].size();
int old_index = -1;
for (int index = 0; index < length; ++index) {
if (old_index != tmpAggregate[l][j][index]) {
NNZ_tmp++;
old_index = tmpAggregate[l][j][index];
}
}
}
// rMessage("l = " << l << " : NNZ_tmp = " << NNZ_tmp);
/* cholmod_sparse *cholmod_allocate_sparse
(size_t nrow, size_t ncol, size_t nzmax, int sorted, int packed,
int stype, int xtype, cholmod_common *Common) ;
*/
SDP_block[l].nDim = SDP_blockStruct[l];
SDP_block[l].NNZ_Z = NNZ_tmp;
// parameters can be found in CHOLMOD/Check/cholmod_read.c
// stype = -1 means this matrix contains only lower triangular
SDP_block[l].Z = cholmod_allocate_sparse(SDP_blockStruct[l],
SDP_blockStruct[l],
NNZ_tmp, TRUE, TRUE,
-1, CHOLMOD_REAL,
&SDP_block[l].common);
SDP_block[l].b_x = cholmod_allocate_dense(SDP_blockStruct[l],1,
SDP_blockStruct[l], CHOLMOD_REAL,
&SDP_block[l].common);
SDP_block[l].b_z = cholmod_allocate_dense(SDP_blockStruct[l],1,
SDP_blockStruct[l], CHOLMOD_REAL,
&SDP_block[l].common);
// SDP_block[l].x should not be allocated,
// it will be allocated every time by cholmod_solve
cholmod_sparse* Zl = SDP_block[l].Z;
// Todo: Set SDP_A[l].i,j,values;
int index_nnz = 0;
for (int j=0; j<SDP_blockStruct[l]; ++j) {
((int*)Zl->p)[j] = index_nnz;
const int length = tmpAggregate[l][j].size();
int old_index = -1;
for (int index = 0; index < length; ++index) {
if (old_index != tmpAggregate[l][j][index]) {
((int*)Zl->i)[index_nnz] = tmpAggregate[l][j][index];
old_index = tmpAggregate[l][j][index];
index_nnz++;
}
}
}
((int*)Zl->p)[SDP_blockStruct[l]] = index_nnz;
// rMessage("After Agg : Z["<<l<<"] = "); CholmodMatrix::display_sparse(Zl);
// this index_nnz must be equal to NNZ_tmp
}
for (int l=0; l<SDP_nBlock; ++l) {
DeleteArray(tmpAggregate[l]);
}
DeleteArray(tmpAggregate);
}
void CholmodSpace::assignBlockIndex(OrderingSpace& order)
{
for (int l=0; l<SDP_nBlock; ++l) {
SDP_block[l].assignBlockIndex(order.SDP_block[l]);
}
}
void CholmodSpace::setZzero()
{
for (int l=0; l<LP_nBlock; ++l) {
LP_Z[l] = 0.0;
}
for (int l=0; l<SDP_nBlock; ++l) {
SDP_block[l].setZzero();
}
}
void CholmodSpace::setZIdentity(double scalar)
{
for (int l=0; l<LP_nBlock; ++l) {
LP_Z[l] = scalar;
}
for (int l=0; l<SDP_nBlock; ++l) {
SDP_block[l].setZIdentity(scalar);
}
}
void CholmodSpace::setXIdentity(double scalar)
{
for (int l=0; l<LP_nBlock; ++l) {
LP_X[l] = scalar;
}
for (int l=0; l<SDP_nBlock; ++l) {
SDP_block[l].setXIdentity(scalar);
}
}
void CholmodSpace::display(FILE* fpout, char* printFormat)
{
if (LP_nBlock > 0) {
fprintf(fpout, "LP_Z = \n");
for (int l=0; l < LP_nBlock; ++l) {
fprintf(fpout, printFormat, LP_Z[l]);
fprintf(fpout, " ");
}
fprintf(fpout, "\n");
fprintf(fpout, "LP_invZ = \n");
for (int l=0; l < LP_nBlock; ++l) {
fprintf(fpout, printFormat, LP_invZ[l]);
fprintf(fpout, " ");
}
fprintf(fpout, "\n");
fprintf(fpout, "LP_X = \n");
for (int l=0; l < LP_nBlock; ++l) {
fprintf(fpout, printFormat, LP_X[l]);
fprintf(fpout, " ");
}
fprintf(fpout, "\n");
fprintf(fpout, "LP_invX = \n");
for (int l=0; l < LP_nBlock; ++l) {
fprintf(fpout, printFormat, LP_invX[l]);
fprintf(fpout, " ");
}
fprintf(fpout, "\n");
fprintf(fpout, "LP_rD = \n");
for (int l=0; l < LP_nBlock; ++l) {
fprintf(fpout, printFormat, LP_rD[l]);
fprintf(fpout, " ");
}
fprintf(fpout, "\n");
}
if (SDP_nBlock > 0) {
for (int l = 0; l<SDP_nBlock; ++l) {
fprintf(fpout, "SDP_block[%d] = \n", l);
SDP_block[l].display(fpout, printFormat);
}
}
fprintf(fpout, "y = \n");
yVec.display(fpout, printFormat);
fprintf(fpout, "dy = \n");
dyVec.display(fpout, printFormat);
fprintf(fpout, "rp = \n");
rp.display(fpout, printFormat);
fprintf(fpout, "\n");
}
void CholmodSpace::analyze()
{
for (int l=0; l<SDP_nBlock; ++l) {
SDP_block[l].analyze();
}
}
void CholmodSpace::initializeClique(int m, OrderingSpace& order)
{
yVec.initialize();
yVec.initialize(m);
dyVec.initialize();
dyVec.initialize(m);
rp.initialize();
rp.initialize(m);
for (int l=0; l<SDP_nBlock; ++l) {
SDP_block[l].initializeClique(order.SDP_block[l]);
}
}
void CholmodSpace::getInnerProductAX(double& ret,
CompSpace& A, OrderingSpace& order)
{
ret = 0.0;
for (int l_index = 0; l_index< A.LP_sp_nBlock; ++l_index) {
const double Avalue = A.LP_sp_block[l_index];
const int l = A.LP_sp_index[l_index];
const double Xvalue = LP_X[l];
ret += Avalue*Xvalue;
}
for (int l_index = 0; l_index< A.SDP_sp_nBlock; ++l_index) {
double tmpret = 0.0;
const int l = A.SDP_sp_index[l_index];
Lal::getInnerProduct(tmpret, A.SDP_sp_block[l_index],
SDP_block[l].clique_xMat, order.SDP_block[l]);
ret += tmpret;
}
}
void CholmodSpace::getInnerProductAdX(double& ret,
CompSpace& A, OrderingSpace& order)
{
ret = 0.0;
for (int l_index = 0; l_index< A.LP_sp_nBlock; ++l_index) {
const double Avalue = A.LP_sp_block[l_index];
const int l = A.LP_sp_index[l_index];
const double Xvalue = LP_dX[l];
ret += Avalue*Xvalue;
}
for (int l_index = 0; l_index< A.SDP_sp_nBlock; ++l_index) {
double tmpret = 0.0;
const int l = A.SDP_sp_index[l_index];
Lal::getInnerProduct(tmpret, A.SDP_sp_block[l_index],
SDP_block[l].clique_dX, order.SDP_block[l]);
ret += tmpret;
}
}
void CholmodSpace::computeResiduals(InputData& inputData, OrderingSpace& order)
{
CompSpace& C = inputData.C;
CompSpace* A = inputData.A;
Vector& b = inputData.b;
int m = inputData.b.nDim;
for (int k=0; k<m; ++k) {
double ip = 0.0; // dummy initialize
getInnerProductAX(ip, A[k], order);
rp.ele[k] = b.ele[k] - ip;
#if 0
rMessage("ip = " << ip);
rMessage("A["<< k << "] = ");
A[k].display();
rMessage("clique_xMat = ");
SDP_block[0].clique_xMat.display();
rMessage(" b["<< k << "] = " << b.ele[k]);
rMessage("rp[" << k << "] = " << rp.ele[k]);
#endif
}
// rMessage(" C = " ); C.display();
// rD = - Z + C - A^T*y
for (int l=0; l<LP_nBlock; ++l) {
LP_rD[l] = -LP_Z[l];
}
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];
LP_rD[l] += value;
}
for (int k=0; k<m; ++k) {
const double yk = yVec.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];
LP_rD[l] -= value* yk;
}
}
for (int l=0; l<SDP_nBlock; ++l) {
cholmod_sparse* rD = SDP_block[l].rD;
cholmod_sparse* Z = SDP_block[l].Z;
const int length = Z->nzmax;
for (int index1 = 0; index1 < length; ++index1) {
((double*)(rD->x))[index1] = -((double*)(Z->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 = SDP_block[l].rD;
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 = yVec.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 = SDP_block[l].rD;
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;
}
}
}
}
}
bool CholmodSpace::getCholesky(OrderingSpace& order)
{
for (int l=0; l<LP_nBlock; ++l) {
LP_invZ[l] = 1.0 / LP_Z[l];
}
for (int l=0; l<LP_nBlock; ++l) {
LP_invX[l] = 1.0 / LP_X[l];
}
bool total_judge = SDPA_SUCCESS;
for (int l=0; l<SDP_nBlock; ++l) {
bool judge = SDP_block[l].getCholesky(order.SDP_block[l]);
if (judge == SDPA_FAILURE) {
rMessage("FAILED Cholesky factorization in " << l
<< " th block ");
total_judge = SDPA_FAILURE;
break;
}
}
return total_judge;
}
} // end of namespace 'sdpa'