BlockSparseMatrix.java
package org.mklab.sdpj.datastructure;
import org.mklab.nfc.matrix.ComplexNumericalMatrix;
import org.mklab.nfc.matrix.RealNumericalMatrix;
import org.mklab.nfc.scalar.ComplexNumericalScalar;
import org.mklab.nfc.scalar.RealNumericalScalar;
/**
* ブロック疎行列を表すクラスです。
*
* @author takafumi
* @param <RS> type of real scalar
* @param <RM> type of real matrix
* @param <CS> type of complex scalar
* @param <CM> type of complex Matrix
*/
public class BlockSparseMatrix<RS extends RealNumericalScalar<RS, RM, CS, CM>, RM extends RealNumericalMatrix<RS, RM, CS, CM>, CS extends ComplexNumericalScalar<RS, RM, CS, CM>, CM extends ComplexNumericalMatrix<RS, RM, CS, CM>> {
/** ブロック数 */
private int blockSize;
/** ブロック構造 */
private int[] blockStruct;
/** 成分 */
private SparseMatrix<RS,RM,CS,CM>[] blocks;
/**
* 新しく生成された{@link BlockSparseMatrix}オブジェクトを初期化します。
*/
public BlockSparseMatrix() {
this.blockSize = 0;
this.blockStruct = null;
this.blocks = null;
}
/**
* 新しく生成された{@link BlockSparseMatrix}オブジェクトを初期化します。
*
* @param blockSize ブロックの数
* @param blockStruct ブロックの構造
*/
public BlockSparseMatrix(int blockSize, int[] blockStruct) {
if (blockSize < 0) {
throw new RuntimeException("rBlockSparseMatrix:: nBlock is nonpositive"); //$NON-NLS-1$
}
this.blockSize = blockSize;
this.blockStruct = new int[blockSize];
for (int i = 0; i < blockSize; i++) {
this.blockStruct[i] = blockStruct[i];
}
this.blocks = new SparseMatrix[blockSize];
for (int i = 0; i < this.blockSize; i++) {
this.blocks[i] = new SparseMatrix<>();
}
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuffer buff = new StringBuffer();
buff.append("{\n"); //$NON-NLS-1$
for (int i = 0; i < this.blockSize; i++) {
buff.append("nonZeroCount:" + this.blocks[i].nonZeroCount + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
buff.append("nonZeroEffect:" + this.blocks[i].nonZeroEffect + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
buff.append("nonZeroNumber:" + this.blocks[i].getNonZeroNumber() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
buff.append(this.blocks[i].toString());
}
buff.append("}\n"); //$NON-NLS-1$
return buff.toString();
}
/**
* Denseへ変換します。
*/
public void changeToDense() {
for (int i = 0; i < this.blockSize; i++) {
this.blocks[i].changeToDense(false);
}
}
/**
* ブロック数を返します。
*
* @return ブロック数
*/
public int getBlockSize() {
return this.blockSize;
}
/**
* ブロックの構造を返します。
*
* @param index 指数
* @return ブロックの構造
*/
public int getTargetBlockStruct(final int index) {
return this.blockStruct[index];
}
/**
* ブロックの構造を返します。
*
* @return ブロックの構造
*/
public int[] getBlockStruct(){
return this.blockStruct;
}
/**
* ブロック成分を返します。
*
* @param index 指数
* @return ブロック成分
*/
public SparseMatrix<RS,RM,CS,CM> getBlock(int index) {
return this.blocks[index];
}
/**
* ブロック成分を設定します。
*
* @param index 指数
* @param block ブロック成分
*/
public void setBlock(int index, SparseMatrix<RS,RM,CS,CM> block) {
this.blocks[index] = block;
}
/**
* 成分の単位を返します。
*
* @return 成分の単位
*/
public RS getElementUnit() {
for (SparseMatrix<RS,RM,CS,CM> matrix : this.blocks) {
if (matrix.getNonZeroNumber() != 0) {
return matrix.getElementUnit();
}
}
throw new RuntimeException("null matrix"); //$NON-NLS-1$
}
/**
* Return a copy of instance of class <code>BlockSparseMatrix</code>.
*
* @return a copy of instance of class <code>BlockSparseMatrix</code>
*/
public BlockSparseMatrix<RS,RM,CS,CM> createClone() {
BlockSparseMatrix<RS,RM,CS,CM> inst = new BlockSparseMatrix<>();
inst.blockSize = this.blockSize;
if (this.blockStruct != null) {
inst.blockStruct = new int[this.blockStruct.length];
for (int i = 0; i < this.blockStruct.length; i++) {
inst.blockStruct[i] = this.blockStruct[i];
}
} else {
inst.blockStruct = null;
}
if (this.blocks != null) {
inst.blocks = new SparseMatrix[this.blocks.length];
for (int i = 0; i < this.blocks.length; i++) {
inst.blocks[i] = this.blocks[i] == null ? null : this.blocks[i].createClone();
}
} else {
inst.blocks = null;
}
return inst;
}
/**
* Return an array of elements.
*
* @return array of elements
*/
public RS[][] getArrayOfElements() {
final RS unit = getElementUnit();
int size = 0;
for (int dimension : this.blockStruct) {
size += Math.abs(dimension);
}
final RS[][] data = unit.createArray(size, size);
RS zero = unit.createZero();
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
data[i][j] = zero;
}
}
int shift = 0;
for (int index = 0; index < this.blockStruct.length; index++) {
if (index > 0) {
shift += Math.abs(this.blockStruct[index - 1]);
}
switch (this.getBlock(index).getSparseOrDenseOrDiagonal()) {
case SPARSE:
RS[] elementsOfSparse = this.getBlock(index).sparseElements;
int[] row = this.getBlock(index).rowIndex;
int[] column = this.getBlock(index).columnIndex;
int lengthOfSparse = elementsOfSparse.length;
for (int nIndex = 0; nIndex < lengthOfSparse; nIndex++) {
int nRow = Math.abs(row[nIndex]) + shift;
int nCol = Math.abs(column[nIndex]) + shift;
data[nRow][nCol] = elementsOfSparse[nIndex];
data[nCol][nRow] = data[nRow][nCol];
}
break;
case DENSE:
RS[] elementsOfDense = this.getBlock(index).denseElements;
int lengthOfDense = elementsOfDense.length;
int nSize = this.getBlock(index).getRowSize();
for (int nIndex = 0; nIndex < lengthOfDense; nIndex++) {
data[nIndex / nSize + shift][nIndex % nSize + shift] = elementsOfDense[nIndex];
}
break;
case DIAGONAL:
RS[] elementsOfDiagonal = this.getBlock(index).diagonalElements;
int lengthOfDiagonal = elementsOfDiagonal.length;
for (int nIndex = 0; nIndex < lengthOfDiagonal; nIndex++) {
data[nIndex + shift][nIndex + shift] = elementsOfDiagonal[nIndex];
}
break;
default:
throw new UnsupportedOperationException();
}
}
return data;
}
/**
* This function is to substitute the data of class <code>BlockSparseMatrix</code> with the data of array.
* @param arrayMatrix array matrix
* @param dimensionArray dimension array
*/
public void useDataOfArray(RS[][] arrayMatrix, int dimensionArray) {
//final RS unit = getElementUnit();
int size = 0;
for (int dimension : this.blockStruct) {
size += dimension;
}
if (size != dimensionArray) {
System.err.println("Error: Dimension of array is wrong!"); //$NON-NLS-1$
System.exit(0);
}
// final RS[][] data = unit.createArray(size, size);
// RS zero = unit.createZero();
// for (int i = 0; i < size; i++) {
// for (int j = 0; j < size; j++) {
// data[i][j] = zero;
// }
// }
int shift = 0;
for (int index = 0; index < this.blockStruct.length; index++) {
if (index > 0) {
shift += this.blockStruct[index - 1];
}
switch (this.getBlock(index).getSparseOrDenseOrDiagonal()) {
case SPARSE:
RS[] elementsOfSparse = this.getBlock(index).sparseElements;
int[] row = this.getBlock(index).rowIndex;
int[] column = this.getBlock(index).columnIndex;
int lengthOfSparse = elementsOfSparse.length;
for (int nIndex = 0; nIndex < lengthOfSparse; nIndex++) {
int nRow = row[nIndex] + shift;
int nCol = column[nIndex] + shift;
// data[nRow][nCol] = elementsOfSparse[nIndex];
// data[nCol][nRow] = data[nRow][nCol];
elementsOfSparse[nIndex] = arrayMatrix[nRow][nCol].unaryMinus();
}
this.getBlock(index).sparseElements = elementsOfSparse;
break;
case DENSE:
RS[] elementsOfDense = this.getBlock(index).denseElements;
int lengthOfDense = elementsOfDense.length;
int nSize = this.getBlock(index).getRowSize();
for (int nIndex = 0; nIndex < lengthOfDense; nIndex++) {
// data[nIndex / nSize + shift][nIndex % nSize + shift] = elementsOfDense[nIndex];
elementsOfDense[nIndex] = arrayMatrix[nIndex / nSize + shift][nIndex % nSize + shift].unaryMinus();
}
this.getBlock(index).denseElements = elementsOfDense;
break;
case DIAGONAL:
RS[] elementsOfDiagonal = this.getBlock(index).diagonalElements;
int lengthOfDiagonal = elementsOfDiagonal.length;
for (int nIndex = 0; nIndex < lengthOfDiagonal; nIndex++) {
// data[nIndex + shift][nIndex + shift] = elementsOfDiagonal[nIndex];
elementsOfDiagonal[nIndex] = arrayMatrix[nIndex + shift][nIndex + shift].unaryMinus();
}
this.getBlock(index).diagonalElements = elementsOfDiagonal;
break;
default:
throw new UnsupportedOperationException();
}
}
// return data;
}
}