DoubleAdjacencyMatrixUtil.java
/*
* $Id: AdjacencyMatrixUtil.java,v 1.31 2008/07/15 15:27:15 koga Exp $
*
* Copyright (C) 2004-2005 Koga Laboratory. All rights reserved.
*
*/
package org.mklab.tool.control.system;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.mklab.nfc.matrix.DoubleMatrix;
import org.mklab.nfc.matrix.GridUtil;
import org.mklab.nfc.matx.MatxObject;
import org.mklab.tool.control.DoubleAbstractLinearSystem;
import org.mklab.tool.control.DoubleImproperLinearSystem;
import org.mklab.tool.control.system.continuous.DoubleBlockContinuousExplicitDynamicSystem;
import org.mklab.tool.control.system.continuous.DoubleContinuousLinearDynamicSystem;
import org.mklab.tool.control.system.continuous.DoubleIntegratorSystem;
import org.mklab.tool.control.system.discrete.DoubleDiscreteLinearDynamicSystem;
import org.mklab.tool.control.system.discrete.DoubleUnitDelaySystem;
import org.mklab.tool.control.system.math.DoubleConstantSystem;
import org.mklab.tool.control.system.math.DoubleUnitSystem;
/**
* {@link AdjacencyMatrix}クラスのユーティリティクラスです。
*
* @author Koga Laboratory
* @version $Revision: 1.31 $
*/
public class DoubleAdjacencyMatrixUtil {
/**
* 左上の存在する的システムの数を表すクラスです。
*
* @author koga
*/
static class NumberOfLeftUpperSystem {
/** 左側に存在するシステムの数 */
public int numberInLeft = 0;
/** 上側に存在するシステムの数 */
public int numberInUpper = 0;
}
/**
* 行の入れ替えと列の入れ替えを行います。
*
* @param matrix 操作対象の行列
* @param number1 対象(行|列)番号1
* @param number2 対象(行|列)番号2
*/
static void exchangeRowAndColumn(final DoubleSystemOperator[][] matrix, final int number1, final int number2) {
if (number1 == number2) {
return;
}
final int size = matrix.length;
// 行を入れ替える
for (int column = 0; column < size; column++) {
final DoubleSystemOperator tmp = matrix[number1][column];
matrix[number1][column] = matrix[number2][column];
matrix[number2][column] = tmp;
}
// 列を入れ替える
for (int row = 0; row < size; row++) {
final DoubleSystemOperator tmp = matrix[row][number1];
matrix[row][number1] = matrix[row][number2];
matrix[row][number2] = tmp;
}
}
/**
* 列成分に積分器(または1サンプル遅れ器)が存在するか判定します。
*
* @param matrix 隣接行列
* @param column 調べる列
* @return 列成分に積分器(または1サンプル遅れ器)が存在するならばtrue、そうでなければfalse
*/
static boolean hasIntegratorOrUnitDelayInColumn(final DoubleSystemOperator[][] matrix, final int column) {
final int rowSize = matrix.length;
for (int row = 0; row < rowSize; row++) {
DoubleSystemOperator system = matrix[row][column];
if (system instanceof DoubleIntegratorSystem) {
return true;
}
if (system instanceof DoubleUnitDelaySystem) {
return true;
}
}
return false;
}
/**
* 積分器(または1サンプル遅れ器)が存在する行番号を返します。
*
* @param matrix 隣接行列
* @param column 調べる列
* @return 積分器(または1サンプル遅れ器)が存在する行番号、積分器(または1サンプル遅れ器)が存在しない場合、-1
*/
static int findIntegratorOrUnitDelayInColumn(final DoubleSystemOperator[][] matrix, final int column) {
final int rowSize = matrix.length;
for (int row = 0; row < rowSize; row++) {
DoubleSystemOperator system = matrix[row][column];
if (system instanceof DoubleIntegratorSystem) {
return row;
}
if (system instanceof DoubleUnitDelaySystem) {
return row;
}
}
return -1;
}
/**
* 積分器(または1サンプル遅れ器)が存在する列番号を返します。
*
* @param matrix 隣接行列
* @param row 調べる行
* @return 積分器(または1サンプル遅れ器)が存在する列番号、積分器(または1サンプル遅れ器)が存在しない場合、-1
*/
static int findIntegratorOrUnitDelayInRow(final DoubleSystemOperator[][] matrix, final int row) {
final int rowSize = matrix.length;
final int columnSize = rowSize == 0 ? 0 : matrix[0].length;
for (int column = 0; column < columnSize; column++) {
DoubleSystemOperator system = matrix[row][column];
if (system instanceof DoubleIntegratorSystem) {
return column;
}
if (system instanceof DoubleUnitDelaySystem) {
return column;
}
}
return -1;
}
/**
* 行成分に積分器(または1サンプル遅れ器)が存在するか判定します。
*
* @param matrix 隣接行列
* @param row 調べる行
* @return 行成分に積分器(または1サンプル遅れ器)が存在するならばtrue、そうでなければfalse
*/
static boolean hasIntegratorOrUnitDelayInRow(final DoubleSystemOperator[][] matrix, final int row) {
final int rowSize = matrix.length;
final int columnSize = rowSize == 0 ? 0 : matrix[0].length;
for (int column = 0; column < columnSize; column++) {
DoubleSystemOperator system = matrix[row][column];
if (system instanceof DoubleIntegratorSystem) {
return true;
}
if (system instanceof DoubleUnitDelaySystem) {
return true;
}
}
return false;
}
/**
* 積分器が配置されるべき行のうち、積分器が存在しない行番号を返します。
*
* @param matrix 隣接行列
* @param numberOfIntegrator 含まれる積分器の数
* @param outputNodeSize 出力ノードの数
* @return 積分器が配置されるべき行のうち、積分器が存在しない行番号
*/
static int findRowWithoutIntegrator(final DoubleSystemOperator[][] matrix, final int numberOfIntegrator, final int outputNodeSize) {
final int rowSize = matrix.length;
for (int i = 0; i < numberOfIntegrator; i++) {
final int row = rowSize - outputNodeSize - numberOfIntegrator + i;
if (hasIntegratorOrUnitDelayInRow(matrix, row) == false) {
return row;
}
}
return -1;
}
/**
* 積分器が配置されるべき列のうち、積分器が存在しない列番号を返します。
*
* @param matrix 隣接行列
* @param numberOfIntegrator 含まれる積分器の数
* @param inputNodeSize 入力ノードの数
* @return 積分器が配置されるべき列のうち、積分器が存在しない列番号
*/
static int findColumnWithoutIntegrator(final DoubleSystemOperator[][] matrix, final int numberOfIntegrator, final int inputNodeSize) {
for (int i = 0; i < numberOfIntegrator; i++) {
final int column = inputNodeSize + i;
if (hasIntegratorOrUnitDelayInColumn(matrix, column) == false) {
return column;
}
}
return -1;
}
/**
* (<code>row</code>,<code>column</code>)成分を除く、<code>column</code>列の全ての成分が零であるか判定します。
*
* @param matrix 調べる配列
* @param row 調べる行番号
* @param column 調べる列番号
* @return (<code>row</code>,<code>column</code>)成分を除く、<code>column</code>列の全ての成分が零ならばtrue、そうでなければfalse
*/
static boolean isAllZeroInColumn(final DoubleSystemOperator[][] matrix, final int row, final int column) {
final int rowSize = matrix.length;
for (int k = 0; k < row; k++) {
if (matrix[k][column] != DoubleZeroSystem.getInstance()) {
return false;
}
}
for (int k = row + 1; k < rowSize; k++) {
if (matrix[k][column] != DoubleZeroSystem.getInstance()) {
return false;
}
}
return true;
}
/**
* <code>column</code>列の全ての成分が零又は定数システムであるか判定します。
*
* @param matrix 調べる配列
* @param column 調べる列番号
* @param onlyConstant 定数のみを縮約するならばtrue
* @return <code>column</code>列の全ての成分が零又は定数システムならばtrue、そうでなければfalse
*/
static boolean isAllConstantOrZeroInColumn(final DoubleSystemOperator[][] matrix, final int column, final boolean onlyConstant) {
final int rowSize = matrix.length;
for (int k = 0; k < rowSize; k++) {
if (matrix[k][column] != DoubleZeroSystem.getInstance()) {
if ((matrix[k][column] instanceof DoubleConstantSystem) == false) {
return false;
}
if (onlyConstant && ((DoubleConstantSystem)matrix[k][column]).isVariable()) {
return false;
}
}
}
return true;
}
/**
* (<code>row</code>,<code>column</code>)成分を除く<code>row</code>行の全ての成分が零であるか判定します。
*
* @param matrix 調べる配列
* @param row 調べる行番号
* @param column 調べる列番号
* @return (<code>row</code>,<code>column</code>)成分を除く<code>row</code>行の全ての成分が零ならばtrue、そうでなければfalse
*/
static boolean isAllZeroInRow(final DoubleSystemOperator[][] matrix, final int row, final int column) {
final int rowSize = matrix.length;
final int columnSize = rowSize == 0 ? 0 : matrix[0].length;
for (int k = 0; k < column; k++) {
if (matrix[row][k] != DoubleZeroSystem.getInstance()) {
return false;
}
}
for (int k = column + 1; k < columnSize; k++) {
if (matrix[row][k] != DoubleZeroSystem.getInstance()) {
return false;
}
}
return true;
}
/**
* 全ての行成分がゼロ、線形システム、定数システムであるか判定します。
*
* @param matrix 隣接行列
* @param row 調べる行
* @param onlyConstant 定数のみを縮約するならばtrue
* @return 全ての行成分がゼロ、線形システム、定数システムならばtrue、そうでなければfalse
*/
static boolean isAllLinearOrConstnatOrZeroInRow(final DoubleSystemOperator[][] matrix, final int row, final boolean onlyConstant) {
final int rowSize = matrix.length;
final int columnSize = rowSize == 0 ? 0 : matrix[0].length;
for (int column = 0; column < columnSize; column++) {
DoubleSystemOperator system = matrix[row][column];
if (system == DoubleZeroSystem.getInstance() || system instanceof DoubleLinearSystemOperator) {
continue;
}
if (system instanceof DoubleConstantSystem) {
if (onlyConstant == false || ((DoubleConstantSystem)system).isVariable() == false) {
continue;
}
}
return false;
}
return true;
}
/**
* <code>row</code>行の全ての成分が零又は定数システムであるか判定します。
*
* @param matrix 調べる配列
* @param row 調べる行番号
* @param onlyConstant 定数のみを縮約するならばtrue
* @return row行の全ての成分が零又は定数システムならばtrue、そうでなければfalse
*/
static boolean isAllConstantOrZeroInRow(final DoubleSystemOperator[][] matrix, final int row, final boolean onlyConstant) {
final int rowSize = matrix.length;
final int columnSize = rowSize == 0 ? 0 : matrix[0].length;
for (int column = 0; column < columnSize; column++) {
if (matrix[row][column] == DoubleZeroSystem.getInstance()) {
continue;
}
if (matrix[row][column] instanceof DoubleConstantSystem) {
if (onlyConstant == false || ((DoubleConstantSystem)matrix[row][column]).isVariable() == false) {
continue;
}
}
return false;
}
return true;
}
/**
* 全ての列成分がゼロ、線形システム、定数システムであるか判定します。
*
* @param matrix 隣接行列
* @param column 調べる列
* @return 全ての列成分がゼロ、線形システム、定数システムならばtrue、そうでなければfalse
*/
static boolean isAllLinearOrConstantOrZeroInColumn(final DoubleSystemOperator[][] matrix, final int column) {
final int rowSize = matrix.length;
for (int row = 0; row < rowSize; row++) {
DoubleSystemOperator system = matrix[row][column];
if (system == DoubleZeroSystem.getInstance() || system instanceof DoubleLinearSystemOperator || system instanceof DoubleConstantSystem) {
continue;
}
return false;
}
return true;
}
/**
* <code>column</code>列を含めて左側に存在する指定された型のシステムの数、 左上対角ブロック(0,0,<code>row</code>,<code>row</code>)に存在するを指定された型のシステムの数を調べます。
*
* @param matrix 対象となる行列
* @param row 行番号
* @param column 列番号
* @param klass クラスの型
* @return 指定された位置(<code>row</code>,<code>column</code>)を含めて左上に存在する指定された型のシステムの数
*/
static NumberOfLeftUpperSystem findSystemInLeftUpper(final DoubleSystemOperator[][] matrix, final int row, final int column, final Class<?> klass) {
final int size = matrix.length;
NumberOfLeftUpperSystem numbers = new NumberOfLeftUpperSystem();
for (int i = 0; i < size; i++) {
for (int j = 0; j <= column; j++) {
if (klass.isInstance(matrix[i][j])) {
numbers.numberInLeft++;
break;
}
}
}
for (int i = 0; i <= row; i++) {
for (int j = 0; j <= row; j++) {
if (klass.isInstance(matrix[i][j])) {
numbers.numberInUpper++;
break;
}
}
}
return numbers;
}
/**
* 指定された行と列に零(行・列)ベクトルを挿入した行列を生成します。
*
* @param matrix 隣接行列
* @param min 挿入開始行番号
* @param max 挿入終了行番号
* @return 零(行・列)ベクトルを挿入した行列
*/
public static DoubleSystemOperator[][] insertRowAndColumn(final DoubleSystemOperator[][] matrix, final int min, final int max) {
final int size = matrix.length;
final int delta = max - min + 1;
if (delta == 0) {
return matrix;
}
final int newSize = size + delta;
DoubleSystemOperator[][] newMatrix = new DoubleSystemOperator[newSize][newSize];
setZeroSystemToNullElement(newMatrix);
// left upper
GridUtil.setSubMatrix(newMatrix, 0, min - 1, 0, min - 1, getSubMatrix(matrix, 0, min - 1, 0, min - 1));
// right upper
GridUtil.setSubMatrix(newMatrix, 0, min - 1, max + 1, newSize - 1, getSubMatrix(matrix, 0, min - 1, min, size - 1));
// left lower
GridUtil.setSubMatrix(newMatrix, max + 1, newSize - 1, 0, min - 1, getSubMatrix(matrix, min, size - 1, 0, min - 1));
// right lower
GridUtil.setSubMatrix(newMatrix, max + 1, newSize - 1, max + 1, newSize - 1, getSubMatrix(matrix, min, size - 1, min, size - 1));
return newMatrix;
}
/**
* 指定された行と列に零(行・列)ベクトルを挿入した行列を生成します。
*
* @param matrix 隣接行列
* @param rowMin 挿入開始行番号
* @param rowMax 挿入終了行番号
* @param columnMin 挿入開始列番号
* @param columnMax 挿入終了列番号
* @return 零(行・列)ベクトルを挿入した行列
*/
public static DoubleSystemOperator[][] insertRowAndColumn(final DoubleSystemOperator[][] matrix, final int rowMin, final int rowMax, final int columnMin, final int columnMax) {
final DoubleSystemOperator[][] insertedRow = DoubleAdjacencyMatrixUtil.insertRow(matrix, rowMin, rowMax);
final DoubleSystemOperator[][] insertedColumn = DoubleAdjacencyMatrixUtil.insertColumn(insertedRow, columnMin, columnMax);
return insertedColumn;
}
/**
* 指定された行に零ベクトルを挿入した行列を生成します。
*
* @param matrix 隣接行列
* @param min 挿入開始行番号
* @param max 挿入終了行番号
* @return 零ベクトルを挿入した行列
*/
public static DoubleSystemOperator[][] insertRow(final DoubleSystemOperator[][] matrix, final int min, final int max) {
final int rowSize = matrix.length;
final int columnSize = matrix[0].length;
final int delta = max - min + 1;
if (delta == 0) {
return matrix;
}
final int newSize = rowSize + delta;
DoubleSystemOperator[][] newMatrix = new DoubleSystemOperator[newSize][columnSize];
setZeroSystemToNullElement(newMatrix);
// upper
GridUtil.setSubMatrix(newMatrix, 0, min - 1, 0, columnSize - 1, getSubMatrix(matrix, 0, min - 1, 0, columnSize - 1));
// lower
if (max + 1 >= rowSize) return newMatrix;
GridUtil.setSubMatrix(newMatrix, max + 1, newSize - 1, 0, columnSize - 1, getSubMatrix(matrix, min, rowSize - 1, 0, columnSize - 1));
return newMatrix;
}
/**
* 指定された列に零ベクトルを挿入した行列を生成します。
*
* @param matrix 隣接行列
* @param min 挿入開始行番号
* @param max 挿入終了行番号
* @return 零ベクトルを挿入した行列
*/
public static DoubleSystemOperator[][] insertColumn(final DoubleSystemOperator[][] matrix, final int min, final int max) {
final int rowSize = matrix.length;
final int columnSize = matrix[0].length;
final int delta = max - min + 1;
if (delta == 0) {
return matrix;
}
final int newSize = columnSize + delta;
DoubleSystemOperator[][] newMatrix = new DoubleSystemOperator[rowSize][newSize];
setZeroSystemToNullElement(newMatrix);
// left
GridUtil.setSubMatrix(newMatrix, 0, rowSize - 1, 0, min - 1, getSubMatrix(matrix, 0, rowSize - 1, 0, min - 1));
// right
GridUtil.setSubMatrix(newMatrix, 0, rowSize - 1, max + 1, newSize - 1, getSubMatrix(matrix, 0, rowSize - 1, min, columnSize - 1));
return newMatrix;
}
/**
* 部分グリッドを生成します。
*
* @param grid 対象となるグリッド
* @param rowMin 始端行の数
* @param rowMax 終端行の数
* @param columnMin 始端列の数
* @param columnMax 終端列の数
* @return 部分行列
*/
private static final DoubleSystemOperator[][] getSubMatrix(DoubleSystemOperator[][] grid, int rowMin, int rowMax, int columnMin, int columnMax) {
int subRowSize = rowMax - rowMin + 1;
int subColSize = columnMax - columnMin + 1;
DoubleSystemOperator[][] ans = GridUtil.<DoubleSystemOperator> createArray(subRowSize, subColSize, grid);
for (int i = 0; i < subRowSize; i++) {
DoubleSystemOperator[] ansi = ans[i];
DoubleSystemOperator[] gridi = grid[i + rowMin];
for (int j = 0; j < subColSize; j++) {
//ansi[j] = (SystemOperator)gridi[j + columnMin].clone();
ansi[j] = gridi[j + columnMin];
}
}
return ans;
}
/**
* 2行の成分のどちからかゼロシステムであるか、または両方が定数システムであるか判定します。
*
* @param matrix 隣接行列
* @param row1 対象行1
* @param row2 対象行2
* @param onlyConstant 定数のみを縮約するならばtrue
* @return 2行の成分のどちからかゼロシステムであるか、または両方が定数システムならばtrue、そうでなければfalse
*/
static boolean isEitherRowZeroOrBothConstant(final DoubleSystemOperator[][] matrix, final int row1, final int row2, final boolean onlyConstant) {
final int rowSize = matrix.length;
final int columnSize = rowSize == 0 ? 0 : matrix[0].length;
for (int k = 0; k < columnSize; k++) {
if (matrix[row1][k] == DoubleZeroSystem.getInstance() || matrix[row2][k] == DoubleZeroSystem.getInstance()) {
continue;
}
if (matrix[row1][k] instanceof DoubleConstantSystem) {
if (onlyConstant == false || ((DoubleConstantSystem)matrix[row1][k]).isVariable() == false) {
continue;
}
}
if (matrix[row2][k] instanceof DoubleConstantSystem) {
if (onlyConstant == false || ((DoubleConstantSystem)matrix[row2][k]).isVariable() == false) {
continue;
}
}
return false;
}
return true;
}
/**
* ゼロシステムをnull成分に設定します。
*
* @param matrix ゼロシステムを設定する配列
*/
@SuppressWarnings("null")
public static void setZeroSystemToNullElement(final DoubleSystemOperator[][] matrix) {
final int rowSize = matrix == null ? 0 : matrix.length;
final int columnSize = rowSize != 0 ? matrix[0].length : 0;
for (int row = 0; row < rowSize; row++) {
for (int column = 0; column < columnSize; column++) {
if (matrix[row][column] == null) {
matrix[row][column] = DoubleZeroSystem.getInstance();
}
}
}
}
/**
* 線形動的システムの状態空間表現による隣接行列を生成します。
*
* @param system 線形動的システム
*
* @return 線形動的システムの状態空間表現による隣接行列
*/
static DoubleSystemOperator[][] createLinearDynamicSystemBlockMatrix(final DoubleSystemOperator system) {
final DoubleSystemOperator[][] matrix = new DoubleSystemOperator[4][4];
DoubleAdjacencyMatrixUtil.setZeroSystemToNullElement(matrix);
final DoubleLinearSystemOperator linearSystem = (DoubleLinearSystemOperator)system;
final String format = linearSystem.getLinearSystem().getFormat();
if (system instanceof DoubleIntegratorSystem) {
matrix[1][2] = DoubleZeroSystem.getInstance();
matrix[0][2] = new DoubleUnitSystem(linearSystem.getA().getRowSize());
matrix[1][3] = new DoubleUnitSystem(linearSystem.getA().getRowSize());
matrix[0][3] = DoubleZeroSystem.getInstance();
matrix[2][1] = new DoubleIntegratorSystem(system.getStateSize());
((DoubleIntegratorSystem)matrix[2][1]).setTag(linearSystem.getTag());
((DoubleIntegratorSystem)matrix[2][1]).setStateNumber(((DoubleDynamicSystem)system).getStateNumber());
} else if (system.getLinearSystem().isProper() == false) {
// A取得
matrix[1][2] = new DoubleConstantSystem(linearSystem.getA());
if (linearSystem.hasVariableA()) {
// ((DoubleConstantSystem)matrix[1][2]).setExpression("A_" + linearSystem.getTag()); //$NON-NLS-1$
((DoubleConstantSystem)matrix[1][2]).setExpression(linearSystem.getTag() + "_A"); //$NON-NLS-1$
} else {
final DoubleMatrix value = linearSystem.getA();
((DoubleConstantSystem)matrix[1][2]).setExpression(toMmString(value, format));
}
((DoubleConstantSystem)matrix[1][2]).setTag(linearSystem.getTag());
((DoubleConstantSystem)matrix[1][2]).setVariable(linearSystem.hasVariableA());
// B取得
matrix[0][2] = new DoubleConstantSystem(linearSystem.getB());
if (linearSystem.hasVariableB()) {
// ((DoubleConstantSystem)matrix[0][2]).setExpression("B_" + linearSystem.getTag()); //$NON-NLS-1$
((DoubleConstantSystem)matrix[0][2]).setExpression(linearSystem.getTag() + "_B"); //$NON-NLS-1$
} else {
final DoubleMatrix value = linearSystem.getB();
((DoubleConstantSystem)matrix[0][2]).setExpression(toMmString(value, format));
}
((DoubleConstantSystem)matrix[0][2]).setTag(linearSystem.getTag());
((DoubleConstantSystem)matrix[0][2]).setVariable(linearSystem.hasVariableB());
// C取得
matrix[1][3] = new DoubleConstantSystem(linearSystem.getC());
if (linearSystem.hasVariableC()) {
// ((DoubleConstantSystem)matrix[1][3]).setExpression("C_" + linearSystem.getTag()); //$NON-NLS-1$
((DoubleConstantSystem)matrix[1][3]).setExpression(linearSystem.getTag() + "_C"); //$NON-NLS-1$
} else {
final DoubleMatrix value = linearSystem.getC();
((DoubleConstantSystem)matrix[1][3]).setExpression(toMmString(value, format));
}
((DoubleConstantSystem)matrix[1][3]).setTag(linearSystem.getTag());
((DoubleConstantSystem)matrix[1][3]).setVariable(linearSystem.hasVariableC());
// D取得
final DoubleMatrix value = linearSystem.getD();
if (value.isZero()) {
matrix[0][3] = DoubleZeroSystem.getInstance();
} else {
matrix[0][3] = new DoubleConstantSystem(linearSystem.getD());
if (linearSystem.hasVariableD()) {
// ((DoubleConstantSystem)matrix[0][3]).setExpression("D_" + linearSystem.getTag()); //$NON-NLS-1$
((DoubleConstantSystem)matrix[0][3]).setExpression(linearSystem.getTag() + "_D"); //$NON-NLS-1$
} else {
//final DoubleMatrix value = linearSystem.getD();
((DoubleConstantSystem)matrix[0][3]).setExpression(toMmString(value, format));
}
((DoubleConstantSystem)matrix[0][3]).setTag(linearSystem.getTag());
((DoubleConstantSystem)matrix[0][3]).setVariable(linearSystem.hasVariableD());
}
//E取得
final DoubleConstantSystem e = new DoubleConstantSystem(((DoubleImproperLinearSystem)linearSystem.getLinearSystem()).getE());
// e.setExpression("E_" + linearSystem.getTag()); //$NON-NLS-1$
e.setExpression(linearSystem.getTag() + "_E"); //$NON-NLS-1$
e.setTag(linearSystem.getTag());
e.setVariable(linearSystem.hasVariableE());
matrix[2][2] = e.unaryMinus().add(new DoubleUnitSystem(e.getGain().getRowSize()));
// matrix[2][1] = new DoubleIntegratorSystem(system.getStateSize());
matrix[2][1] = new DoubleIntegratorSystem(linearSystem.getA().getColumnSize());
((DoubleIntegratorSystem)matrix[2][1]).setTag("x_" + linearSystem.getTag()); //$NON-NLS-1$
((DoubleIntegratorSystem)matrix[2][1]).setStateNumber(((DoubleDynamicSystem)system).getStateNumber());
} else if (system instanceof DoubleUnitDelaySystem) {
matrix[1][2] = DoubleZeroSystem.getInstance();
matrix[0][2] = new DoubleUnitSystem(linearSystem.getA().getRowSize());
matrix[1][3] = new DoubleUnitSystem(linearSystem.getA().getRowSize());
matrix[0][3] = DoubleZeroSystem.getInstance();
matrix[2][1] = new DoubleUnitDelaySystem(system.getStateSize());
((DoubleUnitDelaySystem)matrix[2][1]).setTag(linearSystem.getTag());
((DoubleUnitDelaySystem)matrix[2][1]).setStateNumber(((DoubleDynamicSystem)system).getStateNumber());
} else {
// A取得
matrix[1][2] = new DoubleConstantSystem(linearSystem.getA());
if (linearSystem.hasVariableA()) {
// ((DoubleConstantSystem)matrix[1][2]).setExpression("A_" + linearSystem.getTag()); //$NON-NLS-1$
((DoubleConstantSystem)matrix[1][2]).setExpression(linearSystem.getTag() + "_A"); //$NON-NLS-1$
} else {
final DoubleMatrix value = linearSystem.getA();
((DoubleConstantSystem)matrix[1][2]).setExpression(toMmString(value, format));
}
((DoubleConstantSystem)matrix[1][2]).setTag(linearSystem.getTag());
((DoubleConstantSystem)matrix[1][2]).setVariable(linearSystem.hasVariableA());
// B取得
matrix[0][2] = new DoubleConstantSystem(linearSystem.getB());
if (linearSystem.hasVariableB()) {
// ((DoubleConstantSystem)matrix[0][2]).setExpression("B_" + linearSystem.getTag()); //$NON-NLS-1$
((DoubleConstantSystem)matrix[0][2]).setExpression(linearSystem.getTag() + "_B"); //$NON-NLS-1$
} else {
final DoubleMatrix value = linearSystem.getB();
((DoubleConstantSystem)matrix[0][2]).setExpression(toMmString(value, format));
}
((DoubleConstantSystem)matrix[0][2]).setTag(linearSystem.getTag());
((DoubleConstantSystem)matrix[0][2]).setVariable(linearSystem.hasVariableB());
// C取得
matrix[1][3] = new DoubleConstantSystem(linearSystem.getC());
if (linearSystem.hasVariableC()) {
// ((DoubleConstantSystem)matrix[1][3]).setExpression("C_" + linearSystem.getTag()); //$NON-NLS-1$
((DoubleConstantSystem)matrix[1][3]).setExpression(linearSystem.getTag() + "_C"); //$NON-NLS-1$
} else {
final DoubleMatrix value = linearSystem.getC();
((DoubleConstantSystem)matrix[1][3]).setExpression(toMmString(value, format));
}
((DoubleConstantSystem)matrix[1][3]).setTag(linearSystem.getTag());
((DoubleConstantSystem)matrix[1][3]).setVariable(linearSystem.hasVariableC());
// D取得
final DoubleMatrix value = linearSystem.getD();
if (value.isZero()) {
matrix[0][3] = DoubleZeroSystem.getInstance();
} else {
matrix[0][3] = new DoubleConstantSystem(linearSystem.getD());
if (linearSystem.hasVariableD()) {
// ((DoubleConstantSystem)matrix[0][3]).setExpression("D_" + linearSystem.getTag()); //$NON-NLS-1$
((DoubleConstantSystem)matrix[0][3]).setExpression(linearSystem.getTag() + "_D"); //$NON-NLS-1$
} else {
//final DoubleMatrix value = linearSystem.getD();
if (value.isZero()) {
matrix[0][3] = DoubleZeroSystem.getInstance();
}
((DoubleConstantSystem)matrix[0][3]).setExpression(toMmString(value, format));
}
((DoubleConstantSystem)matrix[0][3]).setTag(linearSystem.getTag());
((DoubleConstantSystem)matrix[0][3]).setVariable(linearSystem.hasVariableD());
}
//E取得
DoubleMatrix E = linearSystem.getE();
if (!E.equals(E.createUnit())) {
final DoubleConstantSystem e = new DoubleConstantSystem(E);
// e.setExpression("E_" + linearSystem.getTag()); //$NON-NLS-1$
e.setExpression(linearSystem.getTag() + "_E"); //$NON-NLS-1$
e.setTag(linearSystem.getTag());
e.setVariable(linearSystem.hasVariableE());
matrix[2][2] = e.unaryMinus().add(new DoubleUnitSystem(e.getGain().getRowSize()));
}
matrix[2][1] = new DoubleIntegratorSystem(system.getStateSize());
((DoubleIntegratorSystem)matrix[2][1]).setTag("x_" + linearSystem.getTag()); //$NON-NLS-1$
((DoubleIntegratorSystem)matrix[2][1]).setStateNumber(((DoubleDynamicSystem)system).getStateNumber());
}
// IngegralSystem
return matrix;
}
/**
* 線形動的システム(伝達関数)の状態空間表現による隣接行列を生成します。システムを可制御正準型で隣接行列上に展開します.
*
* @param system 線形動的システム
*
* @return 線形動的システム(伝達関数)の状態空間表現による隣接行列
*/
static DoubleSystemOperator[][] createSymbolicLinearDynamicSystemBlockMatrixForTransferFunction(final DoubleSystemOperator system) {
final DoubleLinearSystemOperator linearSystem = (DoubleLinearSystemOperator)system;
final int size = linearSystem.getA().getColumnSize();
final DoubleSystemOperator[][] matrix = new DoubleSystemOperator[size * 2 + 2][size * 2 + 2];
DoubleAdjacencyMatrixUtil.setZeroSystemToNullElement(matrix);
for (int i = 0; i < size; i++) {
matrix[size + i + 1][i + 1] = new DoubleIntegratorSystem(1);
((DoubleIntegratorSystem)matrix[size + i + 1][i + 1]).setTag("x_" + linearSystem.getTag() + "_" + (size - i)); //$NON-NLS-1$ //$NON-NLS-2$
((DoubleIntegratorSystem)matrix[size + i + 1][i + 1]).setStateNumber(((DoubleDynamicSystem)system).getStateNumber() + size - i);
}
// B取得
matrix[0][size + 1] = new DoubleUnitSystem(1);
// A取得
final DoubleMatrix A = new DoubleConstantSystem(linearSystem.getA()).getGain();
for (int i = 0; i < size; i++) {
final DoubleMatrix valueMatrix = A.getRowVector(1).getColumnVector(i + 1);
if (valueMatrix.isZero()) {
matrix[1 + i][size + 1] = DoubleZeroSystem.getInstance();
break;
}
DoubleConstantSystem a = new DoubleConstantSystem(valueMatrix.unaryMinus()).unaryMinus();
a.setExpression(linearSystem.getTag() + "_d" + "_" + (size - i - 1)); //$NON-NLS-1$ //$NON-NLS-2$
a.setTag(linearSystem.getTag() + "_" + (size - i - 1)); //$NON-NLS-1$
a.setVariable(true);
matrix[1 + i][size + 1] = a;
}
for (int i = 0; i < size - 1; i++) {
matrix[1 + i][size + 2 + i] = new DoubleUnitSystem(1);
}
// C取得
final DoubleMatrix C = new DoubleConstantSystem(linearSystem.getC()).getGain();
for (int i = 0; i < size; i++) {
final DoubleMatrix valueMatrix = C.getRowVector(1).getColumnVector(i + 1);
if (valueMatrix.isZero()) {
matrix[1 + i][size * 2 + 1] = DoubleZeroSystem.getInstance();
continue;
}
DoubleConstantSystem c = new DoubleConstantSystem(valueMatrix);
c.setExpression(linearSystem.getTag() + "_n" + "_" + (size - i - 1)); //$NON-NLS-1$ //$NON-NLS-2$
c.setTag(linearSystem.getTag() + "_" + (size - i - 1)); //$NON-NLS-1$
c.setVariable(true);
matrix[1 + i][size * 2 + 1] = c;
}
return matrix;
}
/**
* 行列の値をMMフォーマットで返します。
*
* @param value 行列の値
* @param format フォーマット
* @return 行列の値をMMフォーマット
*/
private static String toMmString(final DoubleMatrix value, final String format) {
final String expression;
if (value.getRowSize() == 1 && value.getColumnSize() == 1) {
expression = value.getElement(1, 1).toString(format);
} else {
expression = ((MatxObject)value).toMmString(format).replaceAll("\\s*", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
return expression;
}
/**
* 線形動的システムの状態空間表現によるブロックシステムに置き換えます。
*
* @param matrix 隣接行列
* @param requireringPrimitive 最小の要素まで分解するならばtrue
* @return 線形動的システムの状態空間表現をブロックシステムに置き換えた隣接行列
*/
@SuppressWarnings("boxing")
static DoubleSystemOperator[][] replaceLinearDynamicSystemWithBLockSystem(final DoubleSystemOperator[][] matrix, final boolean requireringPrimitive) {
final DoubleSystemOperator[][] newMatrix = DoubleAdjacencyMatrixUtil.createClone(matrix);
final int size = newMatrix.length;
for (int row = 0; row < size; row++) {
for (int column = 0; column < size; column++) {
if (newMatrix[row][column] == DoubleZeroSystem.getInstance()) {
continue;
}
if (!newMatrix[row][column].isLinear() || !newMatrix[row][column].isDynamic()) {
continue;
}
final List<Integer> inputNodes = new ArrayList<>(Arrays.asList(1));
final List<Integer> outputNodes = new ArrayList<>(Arrays.asList(4));
if ((newMatrix[row][column] instanceof DoubleIntegratorSystem) == false && requireringPrimitive) {
final List<Integer> newOutputNodes = new ArrayList<>(Arrays.asList(newMatrix[row][column].getLinearSystem().getStateSize() * 2 + 2));
if (((DoubleContinuousLinearDynamicSystem)newMatrix[row][column]).isTransferFuntion() == true) {
if (newMatrix[row][column].getLinearSystem().isProper() == false) throw new IllegalArgumentException(Messages.getString("AdjacencyMatrixUtil.0")); //$NON-NLS-1$
newMatrix[row][column] = new DoubleBlockContinuousExplicitDynamicSystem(createSymbolicLinearDynamicSystemBlockMatrixForTransferFunction(newMatrix[row][column]), inputNodes, newOutputNodes);
continue;
}
newMatrix[row][column] = new DoubleBlockContinuousExplicitDynamicSystem(createSymbolicLinearDynamicSystemBlockMatrix(newMatrix[row][column]), inputNodes, newOutputNodes);
} else {
newMatrix[row][column] = new DoubleBlockContinuousExplicitDynamicSystem(createLinearDynamicSystemBlockMatrix(newMatrix[row][column]), inputNodes, outputNodes);
}
}
}
return newMatrix;
}
/**
* 線形動的システム(状態空間表現)の状態空間表現による隣接行列を生成します。
*
* <p> システムを最小要素で隣接行列上に展開します.
*
* @param system 線形動的システム
*
* @return 線形動的システム(状態空間表現)の状態空間表現による隣接行列
*/
private static DoubleSystemOperator[][] createSymbolicLinearDynamicSystemBlockMatrix(final DoubleSystemOperator system) {
final DoubleLinearSystemOperator linearSystem = (DoubleLinearSystemOperator)system;
final int aSize = linearSystem.getA().getColumnSize();
final int inputSize = linearSystem.getB().getColumnSize();
final int outputSize = linearSystem.getC().getRowSize();
final DoubleSystemOperator[][] matrix = new DoubleSystemOperator[aSize * 2 + 1 + inputSize][aSize * 2 + 1 + outputSize];
DoubleAdjacencyMatrixUtil.setZeroSystemToNullElement(matrix);
for (int i = 0; i < aSize; i++) {
DoubleIntegratorSystem integrator = new DoubleIntegratorSystem(1);
integrator.setTag("x_" + linearSystem.getTag() + "_" + (i + 1)); //$NON-NLS-1$ //$NON-NLS-2$
integrator.setStateNumber(i + 1);
matrix[aSize + inputSize + i][1 + i] = integrator;
}
// B取得
DoubleMatrix b = linearSystem.getB();
for (int i = 0; i < b.getRowSize(); i++) {
for (int j = 0; j < b.getColumnSize(); j++) {
final DoubleConstantSystem element = new DoubleConstantSystem(b.getSubMatrix(i + 1, i + 1, j + 1, j + 1));
final int rowIndex = i + 1;
final int columnIndex = j + 1;
element.setExpression(linearSystem.getTag() + "_b_" + rowIndex + "_" + columnIndex); //$NON-NLS-1$ //$NON-NLS-2$
element.setTag(linearSystem.getTag() + "_b_" + rowIndex + "_" + columnIndex); //$NON-NLS-1$ //$NON-NLS-2$
element.setVariable(true);
matrix[j][aSize + 1 + i] = element;
}
}
// A取得
final DoubleMatrix a = linearSystem.getA();
for (int i = 0; i < a.getRowSize(); i++) {
for (int j = 0; j < a.getColumnSize(); j++) {
final DoubleConstantSystem element = new DoubleConstantSystem(a.getSubMatrix(i + 1, i + 1, j + 1, j + 1));
final int rowIndex = i + 1;
final int columnIndex = j + 1;
element.setExpression(linearSystem.getTag() + "_a_" + rowIndex + "_" + columnIndex); //$NON-NLS-1$ //$NON-NLS-2$
element.setTag(linearSystem.getTag() + "_a_" + rowIndex + "_" + columnIndex); //$NON-NLS-1$ //$NON-NLS-2$
element.setVariable(true);
matrix[inputSize + j][aSize + 1 + i] = element;
}
}
// C取得
final DoubleMatrix c = linearSystem.getC();
for (int i = 0; i < c.getRowSize(); i++) {
for (int j = 0; j < c.getColumnSize(); j++) {
final DoubleConstantSystem element = new DoubleConstantSystem(c.getSubMatrix(i + 1, i + 1, j + 1, j + 1));
final int rowIndex = i + 1;
final int columnIndex = j + 1;
element.setExpression(linearSystem.getTag() + "_c_" + rowIndex + "_" + columnIndex); //$NON-NLS-1$ //$NON-NLS-2$
element.setTag(linearSystem.getTag() + "_c_" + i + 1 + "_" + j + 1); //$NON-NLS-1$ //$NON-NLS-2$
element.setVariable(true);
matrix[inputSize + j][aSize * 2 + 1 + i] = element;
}
}
// D取得
final DoubleMatrix d = linearSystem.getD();
for (int i = 0; i < d.getRowSize(); i++) {
for (int j = 0; j < d.getColumnSize(); j++) {
final DoubleConstantSystem element = new DoubleConstantSystem(d.getSubMatrix(i + 1, i + 1, j + 1, j + 1));
final int rowIndex = i + 1;
final int columnIndex = j + 1;
element.setExpression(linearSystem.getTag() + "_d_" + rowIndex + "_" + columnIndex); //$NON-NLS-1$ //$NON-NLS-2$
element.setTag(linearSystem.getTag() + "_d_" + rowIndex + "_" + columnIndex); //$NON-NLS-1$ //$NON-NLS-2$
element.setVariable(true);
matrix[j][aSize * 2 + 1 + i] = element;
}
}
if (linearSystem.getLinearSystem() instanceof DoubleImproperLinearSystem) {
// E取得
DoubleMatrix e = ((DoubleAbstractLinearSystem)linearSystem.getLinearSystem()).getE();
for (int i = 0; i < e.getRowSize(); i++) {
for (int j = 0; j < e.getColumnSize(); j++) {
DoubleConstantSystem element = new DoubleConstantSystem(e.getSubMatrix(i + 1, i + 1, j + 1, j + 1));
final int rowIndex = i + 1;
final int columnIndex = j + 1;
element.setExpression(linearSystem.getTag() + "_e_" + rowIndex + "_" + columnIndex); //$NON-NLS-1$ //$NON-NLS-2$
element.setTag(linearSystem.getTag() + "_e_" + rowIndex + "_" + columnIndex); //$NON-NLS-1$ //$NON-NLS-2$
element.setVariable(true);
if (i == j) {
element = element.unaryMinus().add(new DoubleUnitSystem(1));
}
matrix[inputSize + aSize + j][aSize + 1 + i] = element;
}
}
}
return matrix;
}
/**
* 線形動的システムの状態空間表現によるブロックシステムに置き換えます。
*
* @param matrix 隣接行列
* @return 線形動的システムの状態空間表現をブロックシステムに置き換えた隣接行列
*/
@SuppressWarnings("boxing")
static DoubleSystemOperator[][] replaceLinearDynamicSystemWithBLockSystem(final DoubleSystemOperator[][] matrix) {
final DoubleSystemOperator[][] newMatrix = DoubleAdjacencyMatrixUtil.createClone(matrix);
final int size = newMatrix.length;
for (int row = 0; row < size; row++) {
for (int column = 0; column < size; column++) {
if (newMatrix[row][column] == DoubleZeroSystem.getInstance()) {
continue;
}
if (!newMatrix[row][column].isLinear() || !newMatrix[row][column].isDynamic()) {
continue;
}
final List<Integer> inputNodes = new ArrayList<>(Arrays.asList(1));
final List<Integer> outputNodes = new ArrayList<>(Arrays.asList(4));
newMatrix[row][column] = new DoubleBlockContinuousExplicitDynamicSystem(createLinearDynamicSystemBlockMatrix(newMatrix[row][column]), inputNodes, outputNodes);
}
}
return newMatrix;
}
/**
* 2列の成分のどちからかゼロシステムであるか、または両方とも定数システムであるか判定します。
*
* @param matrix 隣接行列
* @param column1 対象列1
* @param column2 対象列2
* @return 2列の成分のどちからかゼロシステムであるか、または両方とも定数システムならばtrue、そうでなければfalse
*/
static boolean isEitherColumnZeroOrBothConstant(final DoubleSystemOperator[][] matrix, final int column1, final int column2) {
final int rowSize = matrix.length;
for (int row = 0; row < rowSize; row++) {
if (matrix[row][column1] == DoubleZeroSystem.getInstance() || matrix[row][column2] == DoubleZeroSystem.getInstance()) {
continue;
}
if (matrix[row][column1] instanceof DoubleConstantSystem && matrix[row][column2] instanceof DoubleConstantSystem) {
continue;
}
return false;
}
return true;
}
/**
* 線形システムまたは定数システムに定数行列を掛けた結果を求めます。
*
* @param element 隣接行列
* @param gain 定数行列
* @return 線形システムまたは定数システムに定数行列を掛けた結果
*/
static DoubleSystemOperator multiplyGain(final DoubleLinearSystemOperator element, final DoubleMatrix gain) {
if (element instanceof DoubleConstantSystem) {
final DoubleMatrix gain2 = ((DoubleConstantSystem)element).getGain();
final DoubleMatrix mulGain = gain2.multiply(gain);
if (mulGain.isZero()) {
return DoubleZeroSystem.getInstance();
}
return new DoubleConstantSystem(gain2.multiply(gain));
}
if (element instanceof DoubleContinuousLinearDynamicSystem) {
return new DoubleContinuousLinearDynamicSystem(element.getLinearSystem().multiply(gain));
}
if (element instanceof DoubleDiscreteLinearDynamicSystem) {
return new DoubleDiscreteLinearDynamicSystem(element.getLinearSystem().multiply(gain));
}
throw new IllegalArgumentException(Messages.getString("AdjacencyMatrixUtil.5")); //$NON-NLS-1$
}
/**
* ライターに出力します。
*
* @param matrix 対象となる行列
* @param output ライター
* @param maxColumnSize 最大列の数
*/
static void print(final DoubleSystemOperator[][] matrix, final Writer output, final int maxColumnSize) {
final PrintWriter pw = new PrintWriter(output);
final int rowSize = matrix.length;
final int columnSize = rowSize == 0 ? 0 : matrix[0].length;
int remain = columnSize;
int columnOffset = 0;
while (remain > 0) {
int printColumnSize = Math.min(maxColumnSize, remain);
DoubleAdjacencyMatrixUtil.printColumnNumber(columnOffset, printColumnSize, pw);
for (int i = 0; i < rowSize; i++) {
DoubleAdjacencyMatrixUtil.printRowNumber(i, pw);
DoubleSystemOperator[] elements = new DoubleSystemOperator[printColumnSize];
for (int j = 0; j < printColumnSize; j++) {
elements[j] = matrix[i][columnOffset + j];
}
DoubleAdjacencyMatrixUtil.printElements(elements, pw);
}
columnOffset += printColumnSize;
remain -= printColumnSize;
}
pw.flush();
}
/**
* 複数個の成分をプリントライターに出力します。
*
* @param elements 成分の配列
* @param output 出力先のプリントライター
*/
private static void printElements(final DoubleSystemOperator[] elements, final PrintWriter output) {
final int size = elements.length;
for (int j = 0; j < size; j++) {
output.print(" "); //$NON-NLS-1$
output.print(elements[j]);
}
output.println();
}
/**
* 行番号を出力します。
*
* @param row 行番号
* @param output 出力先のプリントライター
*/
private static void printRowNumber(final int row, final PrintWriter output) {
output.print(String.format(" (%3d)", Integer.valueOf(row + 1))); //$NON-NLS-1$
}
/**
* 列番号を出力します。
*
* @param columnOffset 列のオフセット
* @param printColumnSize 出力する列の数
* @param output 出力先のプリントライター
*/
private static void printColumnNumber(final int columnOffset, final int printColumnSize, final PrintWriter output) {
output.print(" "); //$NON-NLS-1$
output.print(" "); //$NON-NLS-1$
for (int i = 0; i < printColumnSize; i++) {
output.print(String.format(" [ (%3d]", Integer.valueOf(columnOffset + i + 1))); //$NON-NLS-1$
}
output.println();
}
/**
* システムオペレータの配列のクローンを生成します。
*
* <p>成分の参照がコピーされます。
*
* @param matrix 元の配列
* @return 生成された配列
*/
static DoubleSystemOperator[][] createClone(final DoubleSystemOperator[][] matrix) {
final int rowSize = matrix.length;
final int columnSize = rowSize == 0 ? 0 : matrix[0].length;
final DoubleSystemOperator[][] newMatrix = new DoubleSystemOperator[rowSize][columnSize];
for (int row = 0; row < rowSize; row++) {
for (int column = 0; column < columnSize; column++) {
newMatrix[row][column] = matrix[row][column];
}
}
return newMatrix;
}
/**
* 零システムを「0」、非零システムを「1」で表わした文字列を返します。
*
* @param matrix 対象となる行列
* @return 零システムを「0」、非零システムを「1」で表わした文字列
*/
static String toByZeroOne(final DoubleSystemOperator[][] matrix) {
final int size = matrix.length;
final StringBuffer ans = new StringBuffer(size);
for (int row = 0; row < size; row++) {
for (int column = 0; column < size; column++) {
if (matrix[row][column] == DoubleZeroSystem.getInstance()) {
ans.append("0"); //$NON-NLS-1$
} else {
ans.append("1"); //$NON-NLS-1$
}
}
ans.append(System.getProperty("line.separator")); //$NON-NLS-1$
}
return ans.toString();
}
}