SparseMatrix.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;
import org.mklab.sdpj.gpack.atlas.ATLAS;
/**
* Class <code>SparseMatrix</code> defined a data structure of a sparse matrix.
* <br>疎行列を表すクラスです。
*
* @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 SparseMatrix<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 rowSize;
/** 列数 */
private int columnSize;
/** 疎・密・対角の種類 */
private SparseDenseDiagonal sparseOrDenseOrDiagonal;
/** 非零の成分の個数 */
private int nonZeroNumber;
/** currently stored */
public int nonZeroCount;
/** use for calculation of F1,F2,F3 */
public int nonZeroEffect;
/** 密行列の成分 */
public RS[] denseElements;
/** 疎行列の成分の行番号 */
public int[] rowIndex;
/** 疎行列の成分の列番号 */
public int[] columnIndex;
/** 疎行列の成分 */
public RS[] sparseElements;
/** 対角行列の成分 */
public RS[] diagonalElements;
/**
* 新しく生成された{@link SparseMatrix}オブジェクトを初期化します。
*/
public SparseMatrix() {
this.rowSize = 0;
this.columnSize = 0;
this.sparseOrDenseOrDiagonal = SparseDenseDiagonal.SPARSE;
this.nonZeroNumber = 0;
this.nonZeroCount = 0;
this.nonZeroEffect = 0;
}
/**
* 新しく生成された<code>SparseMatrix</code>オブジェクトを初期化します。
*
* @param rowSize 行数
* @param columnSize 列数
* @param sparseOrDenseOrDiagonal 疎・密・対角の種類
* @param nonZeroNumber 非零の成分の個数
* @param unit unit
*/
public SparseMatrix(int rowSize, int columnSize, SparseDenseDiagonal sparseOrDenseOrDiagonal, int nonZeroNumber, RS unit) {
if (rowSize < 0 || columnSize < 0) {
throw new RuntimeException("Dimensions are nonpositive"); //$NON-NLS-1$
}
this.rowSize = rowSize;
this.columnSize = columnSize;
this.sparseOrDenseOrDiagonal = sparseOrDenseOrDiagonal;
//final RS unit = Tools.getUnitNumber();
switch (sparseOrDenseOrDiagonal) {
case SPARSE:
this.nonZeroNumber = nonZeroNumber;
this.nonZeroCount = 0;
this.nonZeroEffect = 0;
this.rowIndex = new int[nonZeroNumber];
this.columnIndex = new int[nonZeroNumber];
this.sparseElements = unit.createArray(nonZeroNumber);
break;
case DENSE:
int length = rowSize * columnSize;
this.nonZeroNumber = length;
this.nonZeroCount = length;
this.nonZeroEffect = length;
this.denseElements = unit.createArray(nonZeroNumber);
ATLAS.setValue(length, unit.createZero(), this.denseElements, 1);
break;
case DIAGONAL:
if (rowSize != columnSize) {
throw new RuntimeException("SparseMatrix:: Diagonal must be Square matrix"); //$NON-NLS-1$
}
this.nonZeroNumber = columnSize;
this.nonZeroCount = columnSize;
this.nonZeroEffect = columnSize;
this.diagonalElements = unit.createArray(this.nonZeroNumber);
ATLAS.setValue(columnSize, unit.createZero(), this.diagonalElements, 1);
break;
default:
throw new IllegalArgumentException();
}
}
/**
* This method is an override method of <code>toString</code>, for more details,
* refer to <code>toString</code> of <code>java</code>
* @see java.lang.Object#toString()
*
*/
@Override
public String toString() {
StringBuffer buff = new StringBuffer();
switch (getSparseOrDenseOrDiagonal()) {
case SPARSE:
buff.append("{"); //$NON-NLS-1$
for (int k = 0; k < this.nonZeroCount; ++k) {
int i = this.rowIndex[k];
int j = this.columnIndex[k];
RS value = this.sparseElements[k];
buff.append("val[" + i + "," + j + "] = " + value.toString() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
buff.append("}\n"); //$NON-NLS-1$
break;
case DENSE:
buff.append("{\n"); //$NON-NLS-1$
for (int i = 0; i < this.rowSize - 1; ++i) {
if (i == 0) {
buff.append(" "); //$NON-NLS-1$
} else {
buff.append(" "); //$NON-NLS-1$
}
buff.append("{"); //$NON-NLS-1$
for (int j = 0; j < this.columnSize - 1; ++j) {
buff.append(this.denseElements[i + this.columnSize * j] + ","); //$NON-NLS-1$
}
buff.append(this.denseElements[i + this.columnSize * (getColumnSize() - 1)] + " },\n"); //$NON-NLS-1$
}
if (this.rowSize > 1) {
buff.append(" {"); //$NON-NLS-1$
}
for (int j = 0; j < this.columnSize - 1; ++j) {
buff.append(this.denseElements[(this.rowSize - 1) + this.columnSize * j] + ","); //$NON-NLS-1$
}
buff.append(this.denseElements[(this.rowSize - 1) + this.columnSize * (getColumnSize() - 1)] + " }"); //$NON-NLS-1$
if (this.rowSize > 1) {
buff.append(" }\n"); //$NON-NLS-1$
} else {
buff.append("\n"); //$NON-NLS-1$
}
break;
case DIAGONAL:
buff.append("{"); //$NON-NLS-1$
for (int j = 0; j < this.columnSize - 1; ++j) {
buff.append(this.diagonalElements[j] + ","); //$NON-NLS-1$
}
if (getColumnSize() > 0) {
buff.append(this.diagonalElements[getColumnSize() - 1] + ","); //$NON-NLS-1$
}
buff.append("}\n"); //$NON-NLS-1$
break;
}
return buff.toString();
}
/**
* 密行列に変更します。
*
* @param forceChange 強制的に変更するならばtrue
*/
public void changeToDense(boolean forceChange) {
if (isSparce() == false) {
return;
}
if (forceChange == false && this.nonZeroCount < (this.rowSize * this.columnSize) * 0.20) {
// if the number of elements are less than 20 percent, we don't change to Dense.
return;
}
RS unit = getSparseElement(0).createUnit();
this.sparseOrDenseOrDiagonal = SparseDenseDiagonal.DENSE;
int length = this.rowSize * this.columnSize;
this.denseElements = unit.createArray(length);
ATLAS.setValue(length, unit.createZero(), this.denseElements, 1);
for (int k = 0; k < this.nonZeroCount; ++k) {
final int i = this.rowIndex[k];
final int j = this.columnIndex[k];
final RS value = this.sparseElements[k];
if (i == j) {
this.denseElements[i + this.columnSize * j] = value;
} else {
this.denseElements[i + this.columnSize * j] = value;
this.denseElements[j + this.columnSize * i] = value;
}
}
this.nonZeroCount = length;
this.nonZeroEffect = length;
this.nonZeroNumber = length;
if (this.rowIndex != null) {
this.rowIndex = null;
}
if (this.columnIndex != null) {
this.columnIndex = null;
}
if (this.sparseElements != null) {
this.sparseElements = null;
}
}
/**
* 疎・密・対角の種類を返します。
*
* @return 疎・密・対角の種類
*/
public SparseDenseDiagonal getSparseOrDenseOrDiagonal() {
return this.sparseOrDenseOrDiagonal;
}
/**
* 行数を返します。
*
* @return 行数
*/
public int getRowSize() {
return this.rowSize;
}
/**
* 列数を返します。
*
* @return 列数
*/
public int getColumnSize() {
return this.columnSize;
}
/**
* Return a nonzero number.
*
* @return a nonzero number.
*/
public int getNonZeroNumber() {
return this.nonZeroNumber;
}
/**
* 疎行列であるか判別します。
*
* @return 疎行列ならばtrue、そうでなければfalse
*/
public boolean isSparce() {
return this.sparseOrDenseOrDiagonal == SparseDenseDiagonal.SPARSE;
}
/**
* 密行列であるか判別します。
*
* @return 密行列ならばtrue、そうでなければfalse
*/
public boolean isDense() {
return this.sparseOrDenseOrDiagonal == SparseDenseDiagonal.DENSE;
}
/**
* 対角行列であるか判別します。
*
* @return 対角行列ならばtrue、そうでなければfalse
*/
public boolean isDiagonal() {
return this.sparseOrDenseOrDiagonal == SparseDenseDiagonal.DIAGONAL;
}
/**
* 密行列の成分を返します。
*
* @param index 指数
* @return 密行列の成分
*/
public RS getDenseElement(int index) {
return this.denseElements[index];
}
/**
* 疎行列の成分を返します。
*
* @param index 指数
* @return 疎行列の成分
*/
public RS getSparseElement(int index) {
return this.sparseElements[index];
}
/**
* 対角行列の成分を返します。
*
* @param index 指数
* @return 対角行列の成分
*/
public RS getDiagonalElement(int index) {
return this.diagonalElements[index];
}
/**
* 成分の単位を返します。
*
* @return 成分の単位
*/
public RS getElementUnit() {
if (isDense()) {
return getDenseElement(0).createUnit();
}
if (isDiagonal()) {
return getDiagonalElement(0).createUnit();
}
if (isSparce()) {
return getSparseElement(0).createUnit();
}
throw new RuntimeException("Inappropariate matrix type"); //$NON-NLS-1$
}
/**
* Returns a copy of instance of class <code>SparseMatrix</code>
*
* @return a copy of instance of class <code>SparseMatrix</code>
*/
public SparseMatrix<RS,RM,CS,CM> createClone() {
SparseMatrix<RS,RM,CS,CM> inst = new SparseMatrix<>();
inst.rowSize = this.rowSize;
inst.columnSize = this.columnSize;
inst.sparseOrDenseOrDiagonal = this.sparseOrDenseOrDiagonal == null ? null : this.sparseOrDenseOrDiagonal;
inst.nonZeroNumber = this.nonZeroNumber;
inst.nonZeroCount = this.nonZeroCount;
inst.nonZeroEffect = this.nonZeroEffect;
if (this.denseElements != null) {
inst.denseElements = this.denseElements[0].createArray(this.denseElements.length);
System.arraycopy(this.denseElements, 0, inst.denseElements, 0, this.denseElements.length);
//inst.denseElements = GridUtil.clone(this.denseElements);
} else {
inst.denseElements = null;
}
if (this.rowIndex != null) {
inst.rowIndex = new int[this.rowIndex.length];
for (int i = 0; i < this.rowIndex.length; i++) {
inst.rowIndex[i] = this.rowIndex[i];
}
} else {
inst.rowIndex = null;
}
if (this.columnIndex != null) {
inst.columnIndex = new int[this.columnIndex.length];
for (int i = 0; i < this.columnIndex.length; i++) {
inst.columnIndex[i] = this.columnIndex[i];
}
} else {
inst.columnIndex = null;
}
if (this.sparseElements != null) {
inst.sparseElements = this.sparseElements[0].createArray(this.sparseElements.length);
System.arraycopy(this.sparseElements, 0, inst.sparseElements, 0, this.sparseElements.length);
//inst.sparseElements = GridUtil.clone(this.sparseElements);
} else {
inst.sparseElements = null;
}
if (this.diagonalElements != null) {
inst.diagonalElements = this.diagonalElements[0].createArray(this.diagonalElements.length);
System.arraycopy(this.diagonalElements, 0, inst.diagonalElements, 0, this.diagonalElements.length);
//inst.diagonalElements = GridUtil.clone(this.diagonalElements);
} else {
inst.diagonalElements = null;
}
return inst;
}
}