BlockDenseMatrix.java
package org.mklab.sdpj.datastructure;
import java.io.PrintStream;
import java.util.Arrays;
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 BlockDenseMatrix<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 DenseMatrix<RS,RM,CS,CM>[] blocks;
/** */
private RS unit;
/**
* 新しく生成された{@link BlockDenseMatrix}オブジェクトを初期化します。
* @param unit unit
*/
public BlockDenseMatrix(RS unit) {
this.unit = unit;
this.blockSize = 0;
this.blockStruct = null;
this.blocks = null;
}
/**
* 新しく生成された{@link BlockDenseMatrix}オブジェクトを初期化します。
*
* @param blockSize ブロック数
* @param blockStruct ブロック構造
* @param unit unit
*/
public BlockDenseMatrix(int blockSize, int[] blockStruct, RS unit) {
this.unit = unit;
this.initialize(blockSize, blockStruct);
}
/**
* Returns unit.
*
* @return unit
*/
public RS getUnit() {
return this.unit;
}
/**
* 初期化します。
*
* @param blockSize1 ブロック数
* @param blockStruct1 ブロック構造
*/
public void initialize(int blockSize1, int[] blockStruct1) {
this.blockSize = blockSize1;
if (blockSize1 < 0) {
throw new RuntimeException("BlockDenseMatrix::nBlock is nonpositive"); //$NON-NLS-1$
}
this.blockStruct = new int[blockSize1];
for (int i = 0; i < this.blockSize; i++) {
this.blockStruct[i] = blockStruct1[i];
}
this.blocks = new DenseMatrix[blockSize1];
for (int i = 0; i < blockSize1; i++) {
int size = blockStruct1[i];
if (size > 0) {
this.blocks[i] = new DenseMatrix<>(size, size, DenseDiagonal.DENSE, this.unit);
} else {
size = (-size);
this.blocks[i] = new DenseMatrix<>(size, size, DenseDiagonal.DIAGONAL, this.unit);
}
}
}
/**
* This function is to compute the condition number, minimum singular, and
* maximum singular value of matrix.
*
* @param out Print result of condition number
* @param min Print minimum singular value of matrix
* @param max Print maximum singular value of matrix
*/
public void getCondtionNumber(PrintStream out, PrintStream min, PrintStream max) {
//RS unit = Tools.getUnitNumber();
int rowSize = getRowSize();
int columnSize = getColumnSize();
RS zero = this.unit.createZero();
RS[][] data = this.unit.createArray(rowSize, columnSize);
for (int i = 0; i < rowSize; ++i) {
for (int j = 0; j < columnSize; ++j) {
data[i][j] = zero;
}
}
int shift = 0;
for (int k = 0; k < this.blockSize; ++k) {
if (k > 0) {
shift += this.blocks[k - 1].getColumnSize();
}
DenseMatrix<RS,RM,CS,CM> matrix = this.blocks[k];
int rowNumber = matrix.getRowSize();
int columnNumber = matrix.getColumnSize();
switch (matrix.getDenseOrDiagonal()) {
case DENSE:
for (int i = 0; i < rowNumber; ++i) {
for (int j = 0; j < columnNumber; ++j) {
data[i + shift][j + shift] = matrix.denseElements[i + columnNumber * j];
}
}
break;
case DIAGONAL:
for (int j = 0; j < columnNumber; ++j) {
data[j + shift][j + shift] = matrix.diagonalElements[j];
}
break;
default:
throw new UnsupportedOperationException();
}
}
//NumericalMatrix<RS> matrix = new BaseNumericalMatrix<>(columnSize, columnSize, data);
RM matrix = data[0][0].createGrid(data);
out.printf("%s\n", matrix.conditionNumber().toString("%4.3e")); //$NON-NLS-1$ //$NON-NLS-2$
min.printf("%s \n", matrix.minSingularValue().toString("%4.2e")); //$NON-NLS-1$ //$NON-NLS-2$
max.printf("%s \n", matrix.maxSingularValue().toString("%4.2e")); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* 出力します。
*
* @param out 出力先
*/
@SuppressWarnings("boxing")
public void display(PrintStream out) {
out.print("{\n"); //$NON-NLS-1$
for (int k = 0; k < this.blockSize; ++k) {
DenseMatrix<RS,RM,CS,CM> matrix = this.blocks[k];
int rowSize = matrix.getRowSize();
int columnSize = matrix.getColumnSize();
switch (matrix.getDenseOrDiagonal()) {
case DENSE:
out.print("{"); //$NON-NLS-1$
for (int i = 0; i < rowSize - 1; ++i) {
if (i != 0) {
out.print(" "); //$NON-NLS-1$
}
out.print(" "); //$NON-NLS-1$
out.print("{ "); //$NON-NLS-1$
for (int j = 0; j < columnSize - 1; ++j) {
out.printf("%s, ", matrix.denseElements[i + columnSize * j].toString("%+4.16e")); //$NON-NLS-1$ //$NON-NLS-2$
}
out.printf("%s },\n", matrix.denseElements[i + columnSize * (columnSize - 1)].toString("%+4.16e")); //$NON-NLS-1$ //$NON-NLS-2$
}
if (rowSize > 1) {
out.print(" { "); //$NON-NLS-1$
}
for (int j = 0; j < columnSize - 1; ++j) {
out.printf("%s, ", matrix.denseElements[(rowSize - 1) + columnSize * j].toString("%+4.16e")); //$NON-NLS-1$ //$NON-NLS-2$
}
out.printf("%s }", matrix.denseElements[(rowSize - 1) + columnSize * (columnSize - 1)].toString("%+4.16e")); //$NON-NLS-1$ //$NON-NLS-2$
if (rowSize > 1) {
out.print(" }"); //$NON-NLS-1$
}
out.print("\n"); //$NON-NLS-1$
break;
case DIAGONAL:
out.print("{"); //$NON-NLS-1$
for (int j = 0; j < columnSize - 1; ++j) {
out.printf("%+4.6e, ", Double.parseDouble(matrix.diagonalElements[j].toString())); //$NON-NLS-1$
}
if (columnSize > 0) {
out.printf("%+4.6e }\n", Double.parseDouble(matrix.diagonalElements[columnSize - 1].toString())); //$NON-NLS-1$
}
break;
default:
throw new UnsupportedOperationException();
}
}
out.print("} \n"); //$NON-NLS-1$
}
/**
* Matlab形式で出力します。
*
* @param out 出力先
*/
public void displayAsMatlabFormat(PrintStream out) {
out.print("[\n"); //$NON-NLS-1$
for (int k = 0; k < this.blockSize; ++k) {
DenseMatrix<RS,RM,CS,CM> matrix = this.blocks[k];
int rowSize = matrix.getRowSize();
int columnSize = matrix.getColumnSize();
switch (matrix.getDenseOrDiagonal()) {
case DENSE:
for (int i = 0; i < rowSize - 1; ++i) {
for (int j = 0; j < columnSize - 1; ++j) {
out.printf("%s;\n", matrix.denseElements[i + columnSize * j].toString("%+4.16e")); //$NON-NLS-1$ //$NON-NLS-2$
}
out.printf("%s;\n", matrix.denseElements[i + columnSize * (columnSize - 1)].toString("%+4.16e")); //$NON-NLS-1$ //$NON-NLS-2$
}
for (int j = 0; j < columnSize - 1; ++j) {
out.printf("%s;\n", matrix.denseElements[(rowSize - 1) + columnSize * j].toString("%+4.16e")); //$NON-NLS-1$ //$NON-NLS-2$
}
out.printf("%s;\n", matrix.denseElements[(rowSize - 1) + columnSize * (columnSize - 1)].toString("%+4.16e")); //$NON-NLS-1$ //$NON-NLS-2$
break;
case DIAGONAL:
for (int j = 0; j < columnSize - 1; ++j) {
out.printf("%s;\n", matrix.diagonalElements[j].toString("%+4.16e")); //$NON-NLS-1$ //$NON-NLS-2$
}
if (columnSize > 0) {
out.printf("%s;\n", matrix.diagonalElements[columnSize - 1].toString("%+4.16e")); //$NON-NLS-1$ //$NON-NLS-2$
}
break;
default:
throw new UnsupportedOperationException();
}
}
out.print("];\n\n"); //$NON-NLS-1$
}
/**
* @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(this.blocks[i].toString());
}
buff.append("} \n"); //$NON-NLS-1$
return buff.toString();
}
/**
* コピーします。
*
* @param source コピー元
*/
public void copyFrom(BlockDenseMatrix<RS,RM,CS,CM> source) {
if (source.blockSize < 0) {
throw new RuntimeException("rBlockDenseMatix:: nBlock is nonpositive"); //$NON-NLS-1$
}
this.blockSize = source.blockSize;
this.blockStruct = new int[source.blockSize];
for (int i = 0; i < source.blockSize; i++) {
this.blockStruct[i] = source.blockStruct[i];
}
this.blocks = new DenseMatrix[source.blockSize];
for (int i = 0; i < source.blockSize; i++) {
this.blocks[i] = source.blocks[i].createClone();
}
}
/**
* ゼロ行列に設定します。
*/
public void setZero() {
for (int i = 0; i < this.blockSize; i++) {
this.blocks[i].setZero();
}
}
/**
* 単位行列に設定します。
*
* @param unit 単位
*/
public void setIdentity(RS unit) {
for (int i = 0; i < this.blockSize; i++) {
this.blocks[i].setIdentity(unit);
}
}
/**
* ブロック数を返します。
*
* @return ブロック数
*/
public int getBlockSize() {
return this.blockSize;
}
/**
* ブロックの構造を返します。
*
* @param index 指数
* @return ブロックの構造
*/
public int getBlockStruct(final int index) {
return this.blockStruct[index];
}
/**
* ブロックの構造を返します。
*
* @return ブロックの構造
*/
public int[] getBlockStructs() {
return Arrays.copyOf(this.blockStruct, this.blockSize);
}
/**
* ブロック成分を返します。
*
* @param index 指数
* @return ブロック成分
*/
public DenseMatrix<RS,RM,CS,CM> getBlock(int index) {
return this.blocks[index];
}
/**
* ブロック成分を設定します。
*
* @param index 指数
* @param block ブロック成分
*/
public void setBlock(int index, DenseMatrix<RS,RM,CS,CM> block) {
this.blocks[index] = block;
}
/**
* 成分の単位を返します。
*
* @return 成分の単位
*/
public RS getElementUnit() {
return this.blocks[0].getElementUnit();
}
/**
* Returns a copy of instance of class <code>BlockDenseMatrix</code>.
*
* @return a copy of instance
*/
public BlockDenseMatrix<RS,RM,CS,CM> createClone() {
BlockDenseMatrix<RS,RM,CS,CM> inst = new BlockDenseMatrix<>(this.unit);
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 DenseMatrix[this.blocks.length];
for (int i = 0; i < this.blocks.length; i++) {
inst.blocks[i] = this.blocks[i] == null ? null : (DenseMatrix<RS,RM,CS,CM>)this.blocks[i].createClone();
}
} else {
inst.blocks = null;
}
return inst;
}
/**
* 行数を返します。
*
* @return 行数
*/
public int getRowSize() {
int rowSize = 0;
for (DenseMatrix<RS,RM,CS,CM> matrix : this.blocks) {
rowSize += matrix.getRowSize();
}
return rowSize;
}
/**
* 列数を返します。
*
* @return 列数
*/
public int getColumnSize() {
int columnSize = 0;
for (DenseMatrix<RS,RM,CS,CM> matrix : this.blocks) {
columnSize += matrix.getColumnSize();
}
return columnSize;
}
/**
* Return an array of elements.
*
* @return array of elements
*/
public RS[][] getArrayOfElements() {
final int rowSize = getRowSize();
final int columnSize = getColumnSize();
//final RS unit = getElementUnit();
final RS[][] data = this.unit.createArray(rowSize, columnSize);
RS zero = this.unit.createZero();
for (int i = 0; i < rowSize; i++) {
for (int j = 0; j < columnSize; j++) {
data[i][j] = zero;
}
}
int shift = 0;
for (int k = 0; k < this.blockSize; ++k) {
if (k > 0) {
shift += getBlock(k - 1).getColumnSize();
}
final DenseMatrix<RS,RM,CS,CM> matrix = getBlock(k);
final int rowNumber = matrix.getRowSize();
final int columnNumber = matrix.getColumnSize();
switch (matrix.getDenseOrDiagonal()) {
case DENSE:
for (int i = 0; i < rowNumber; ++i) {
for (int j = 0; j < columnNumber; ++j) {
data[i + shift][j + shift] = matrix.denseElements[i + columnNumber * j];
}
}
break;
case DIAGONAL:
for (int j = 0; j < columnNumber; ++j) {
data[j + shift][j + shift] = matrix.diagonalElements[j];
}
break;
default:
throw new UnsupportedOperationException();
}
}
return data;
}
/**
* Set elements
*
* @param a matrix
*/
public void setElements(RM a) {
if (getRowSize() != a.getRowSize() || getColumnSize() != a.getColumnSize()) {
throw new IllegalArgumentException();
}
int shift = 0;
for (int k = 0; k < getBlockSize(); ++k) {
if (k > 0) {
shift += getBlock(k - 1).getColumnSize();
}
DenseMatrix<RS,RM,CS,CM> matrix = getBlock(k);
int rowSize = matrix.getRowSize();
int columnSize = matrix.getColumnSize();
switch (matrix.getDenseOrDiagonal()) {
case DENSE:
for (int i = 0; i < rowSize; ++i) {
for (int j = 0; j < columnSize; ++j) {
matrix.denseElements[i + columnSize * j] = a.getElement(i + shift + 1, j + shift + 1);
}
}
break;
case DIAGONAL:
for (int i = 0; i < columnSize; ++i) {
matrix.diagonalElements[i] = a.getElement(i + shift, i + shift);
}
break;
default:
throw new UnsupportedOperationException();
}
}
}
}