BlockSystem.java
/**
* $Id: BlockSystem.java,v 1.162 2008/07/15 15:27:16 koga Exp $
*
* Copyright (C) 2004-2005 Koga Laboratory. All rights reserved.
*/
package org.mklab.tool.control.system;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.mklab.nfc.SolverException;
import org.mklab.nfc.matrix.BooleanMatrix;
import org.mklab.nfc.matrix.ComplexNumericalMatrix;
import org.mklab.nfc.matrix.RealNumericalMatrix;
import org.mklab.nfc.nleq.NewtonRaphsonFixedPointSolver;
import org.mklab.nfc.nleq.NonLinearEquationSolver;
import org.mklab.nfc.nleq.NonLinearFunction;
import org.mklab.nfc.ode.SolverStopException;
import org.mklab.nfc.scalar.ComplexNumericalScalar;
import org.mklab.nfc.scalar.RealNumericalScalar;
import org.mklab.tool.control.LinearSystem;
import org.mklab.tool.control.system.continuous.ContinuousLinearDynamicSystem;
import org.mklab.tool.control.system.discrete.DiscreteLinearDynamicSystem;
import org.mklab.tool.control.system.graph.MinimumUnknownEquation;
import org.mklab.tool.control.system.graph.NodeIdentityFunctionEquation;
import org.mklab.tool.control.system.math.ConstantSystem;
import org.mklab.tool.control.system.math.UnitSystem;
import org.mklab.tool.control.system.sink.ContinuousSink;
import org.mklab.tool.control.system.sink.OutputPort;
import org.mklab.tool.control.system.source.ContinuousSource;
import org.mklab.tool.control.system.source.InputPort;
/**
* ブロックシステムを表わすクラスです。
*
* @author koga
* @version $Revision: 1.162 $
* @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 abstract class BlockSystem<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>>
extends SystemOperator<RS, RM, CS, CM> {
/** ノードの数 */
private int nodeSize;
/** 入力ノードの番号のリスト */
private List<Integer> inputNodes;
/** 出力ノードの番号のリスト */
private List<Integer> outputNodes;
/** ノードの大きさのリスト */
private int[] nodeSizes;
/** 隣接行列 */
private SystemOperator<RS, RM, CS, CM>[][] elements;
/** 非直達項成分の隣接行列 */
private SystemOperator<RS, RM, CS, CM>[][] nonDirectFeedthroughElements;
/** 直達項成分の隣接行列 */
private SystemOperator<RS, RM, CS, CM>[][] directFeedthroughElements;
/** システムとその入力ノードの番号の対のマップ */
private Map<String, Integer> inputMap = new HashMap<>();
/** ノードの値 */
private ArrayList<RM> nodeValue;
/** 切るべきノードの番号のリストのリスト */
private List<List<Integer>> cuttingNodes;
/** 値が決まっていないノードの1ステップ前の値を結合したベクトルの配列 */
private ArrayList<RM> cuttingNodeValues;
/**
* 新しく生成された<code>BlockSystem</code>オブジェクトを初期化します。
*
* @param elements 隣接行列
* @param inputNodes 入力ノードの番号のリスト(番号は1から始まります)
* @param outputNodes 出力ノードの番号のリスト(番号は1から始まります)
* @param sunit unit of scalar
*/
public BlockSystem(final SystemOperator<RS, RM, CS, CM>[][] elements, List<Integer> inputNodes, final List<Integer> outputNodes, RS sunit) {
super(sunit);
checkElements(elements);
this.elements = elements;
final Integer[] inNodes = new Integer[inputNodes.size()];
this.inputNodes = new ArrayList<>(Arrays.asList(inputNodes.toArray(inNodes)));
final Integer[] outNodes = new Integer[outputNodes.size()];
this.outputNodes = new ArrayList<>(Arrays.asList(outputNodes.toArray(outNodes)));
this.nodeSize = elements.length;
this.nodeValue = new ArrayList<>(this.nodeSize);
initialize();
setInputSize(findInputSize());
setOutputSize(findOutputSize());
setupLinear();
setupInputMap();
// setZeroSizeToUnDefinedInputPort();
// setZeroSizeToUnDefinedOutputPort();
setupNodeSize();
setInputSizeAndOutpuSize();
}
/**
* 隣接行列構成要素のチェックを行います。
*
* @param localElements チェックする要素配列
*/
@SuppressWarnings("boxing")
private void checkElements(SystemOperator<RS,RM,CS,CM>[][] localElements) {
if (localElements.length == 0)
throw new IllegalArgumentException();
final int baseColumnCount = localElements[0].length;
for (int i = 0; i < localElements.length; i++) {
if (localElements[i].length != baseColumnCount)
throw new IllegalArgumentException();
for (int j = 0; j < baseColumnCount; j++) {
if (localElements[i][j] == null)
throw new IllegalArgumentException(
MessageFormat.format("Null system was detected : (row={0},column={1})", i, j)); //$NON-NLS-1$
}
}
}
/**
* 出力数が未定のInputPortの出力数を0に、入力数が未定のOutputPortの入力数を0に設定します。
*/
public void setZeroSizeToUnDefinedInputPortOutputPort() {
setZeroSizeToUnDefinedInputPort();
setZeroSizeToUnDefinedOutputPort();
setupNodeSize();
setInputSizeAndOutpuSize();
}
/**
* 他のノードから入るエッジがないノードの値を確定します。
* <p>
* ノードの仮の値を正式の値へコピーします。
*
* @param matrix 隣接行列を転置した行列
* @param nodeValue ノードの値
* @param nodeTmpValue 仮のノードの値
* @param skipping 値が決まっているノードについての処理をスキップするならばtrue、そうでなければfalse
*/
public void setNodeValueOfNoInputNode(final SystemOperator<RS, RM, CS, CM>[][] matrix, final List<RM> nodeValue,
final List<RM> nodeTmpValue, final boolean skipping) {
final int localNodeNumber = nodeTmpValue.size();
for (int i = 0; i < localNodeNumber; i++) {
if (skipping && nodeValue.get(i) != null) {
continue;
}
boolean noSystem = true;
for (int j = 0; j < localNodeNumber; j++) {
if (matrix[i][j] != ZeroSystem.getInstance(this.sunit)) {
noSystem = false;
}
}
if (noSystem) {
nodeValue.set(i, nodeTmpValue.get(i));
}
}
}
/**
* 全ての列成分がゼロまたは定数システムであるか判定します。
*
* @param matrix 隣接行列の転置
* @param column 調べる列
* @return 全ての列成分がゼロまたは定数システムならばtrue、そうでなければfalse
*/
private boolean isAllConstantOrZeroInColumn(final SystemOperator<RS, RM, CS, CM>[][] matrix, final int column) {
final int rowSize = matrix.length;
for (int row = 0; row < rowSize; row++) {
SystemOperator<RS, RM, CS, CM> system = matrix[row][column];
if (system != ZeroSystem.getInstance(this.sunit) && !(system instanceof ConstantSystem)) {
return false;
}
}
return true;
}
/**
* 極大閉路を形成するノードのリストのリストを返します。
*
* @param matrix 隣接行列
* @return 極大閉路を形成するノードのリストのリスト
*/
@SuppressWarnings("boxing")
List<List<Integer>> getLocalMaximumCycles(final SystemOperator<RS,RM,CS,CM>[][] matrix) {
final int size = matrix.length;
final List<List<Integer>> loopList = new ArrayList<>();
// 対角成分に値が入っている場合、ループがあると判断
for (int i = 0; i < size; i++) {
if (matrix[i][i] != ZeroSystem.getInstance(this.sunit)) {
final List<Integer> loop = new ArrayList<>();
loop.add(i + 1);
loopList.add(loop);
}
}
// 零でない値が入っている成分と対角成分にtrue、それ以外の成分にfalse
final BooleanMatrix nodeMatrix = BooleanMatrix.unit(size, size);
for (int row = 0; row < size; row++) {
for (int column = 0; column < size; column++) {
if (matrix[row][column] != ZeroSystem.getInstance(this.sunit)) {
nodeMatrix.setElement(row + 1, column + 1, true);
}
}
nodeMatrix.setElement(row + 1, row + 1, true);
}
// ノードの数だけ累乗を求める
final BooleanMatrix loopMatrix = nodeMatrix.power(size);
// iノードからjノードへのパスがあり、jノードからiノードへのパスがあれば、
// iノードとjノードは同一ループ中に存在する
for (int j = 1; j <= size; j++) {
final List<Integer> loop = new ArrayList<>();
for (int i = 1; i <= size; i++) {
if (loopMatrix.getElement(i, j) && loopMatrix.getElement(j, i)) {
loop.add(i);
}
}
if (loop.size() > 1 && loopList.contains(loop) == false) {
loopList.add(loop);
}
}
return loopList;
}
/**
* 自己ループをもつノード(システム)の入出力を求め、このシステムを隣接行列から削除します。
*
* @param matrix 隣接行列
* @param tmpValue ノードの仮の値
* @return 縮約したならばtrue、そうでなければfalse
*/
private boolean resolveConstantSelfLoop(final SystemOperator<RS, RM, CS, CM>[][] matrix, final List<RM> tmpValue) {
final int rowSize = matrix.length;
boolean changed = false;
for (int i = 0; i < rowSize; i++) {
if (!(matrix[i][i] instanceof ConstantSystem) || ! isAllZeroInRow(matrix, i, i)) {
continue;
}
changed = true;
final RM D = ((ConstantSystem<RS,RM,CS,CM>) matrix[i][i]).getGain();
final int size = D.getRowSize();
tmpValue.set(i, this.sunit.createUnitGrid(size, size).subtract(D).leftDivide(tmpValue.get(i)));
matrix[i][i] = ZeroSystem.getInstance(this.sunit);
}
return changed;
}
/**
* (行方向に)定数システムと定数システムの直列を結合(定数直列エッジを縮約)します。
*
* @param matrix 隣接行列
* @param nodeTmpValue 仮のノードの値
* @return 縮約したならばtrue、そうでなければfalse
* @throws SolverStopException ソルバーが停止された場合
*/
private boolean contractConstantEdgeForwardRowWise(final SystemOperator<RS, RM, CS, CM>[][] matrix,
final List<RM> nodeTmpValue) throws SolverStopException {
final int rowSize = matrix.length;
final int columnSize = rowSize == 0 ? 0 : matrix[0].length;
boolean changed = false;
for (int row = 0; row < rowSize; row++) {
final boolean hasSelfLoop = (matrix[row][row] != ZeroSystem.getInstance(this.sunit));
if (hasSelfLoop) {
return changed;
}
for (int column = 0; column < columnSize; column++) {
if (!(matrix[row][column] instanceof ConstantSystem)) {
continue;
}
if (! isAllZeroInRow(matrix, row, column) && !isAllConstantOrZeroInColumn(matrix, row)) {
continue;
}
if (! isEitherColumnZeroOrBothConstant(matrix, row, column)) {
continue;
}
if (! isAllLinearOrConstantOrZeroInColumn(matrix, row)) {
continue;
}
final ConstantSystem<RS,RM,CS,CM> gainSystem = ((ConstantSystem<RS,RM,CS,CM>) matrix[row][column]);
final RM gain1 = gainSystem.getGain();
if (nodeTmpValue.get(row).isZero()) {
for (int k = 0; k < rowSize; k++) {
final SystemOperator<RS,RM,CS,CM> systemInRow = matrix[k][row];
final SystemOperator<RS,RM,CS,CM> systemInColumn = matrix[k][column];
if (systemInRow == ZeroSystem.getInstance(this.sunit)) {
continue;
}
if (isAllZeroInRow(matrix, row, column) == false) {
continue;
}
if (systemInRow instanceof ConstantSystem && systemInColumn instanceof ConstantSystem) {
matrix[k][column] = ((ConstantSystem<RS,RM,CS,CM>) systemInColumn)
.add(((ConstantSystem<RS,RM,CS,CM>) systemInRow).multiply(gainSystem));
} else {
final SystemOperator<RS,RM,CS,CM> contractedSystem;
if (systemInRow instanceof ConstantSystem) {
contractedSystem = ((ConstantSystem<RS,RM,CS,CM>) systemInRow).multiply(gainSystem);
} else {
contractedSystem = multiplyGain((LinearSystemOperator<RS,RM,CS,CM>) systemInRow, gain1);
}
if (contractedSystem.hasDirectFeedthrough()) {
matrix[k][column] = contractedSystem;
} else {
nodeTmpValue.set(k, nodeTmpValue.get(k).add(calcOutputOfNonDirectFeedthroughSystem(contractedSystem)));
matrix[k][column] = ZeroSystem.getInstance(this.sunit);
}
}
changed = true;
if (isAllZeroInRow(matrix, row, column)) {
matrix[k][row] = ZeroSystem.getInstance(this.sunit);
}
}
} else if (isAllConstantOrZeroInColumn(matrix, row)) {
for (int k = 0; k < rowSize; k++) {
final SystemOperator<RS,RM,CS,CM> systemInRow = matrix[k][row];
final SystemOperator<RS,RM,CS,CM> systemInColumn = matrix[k][column];
if (systemInRow == ZeroSystem.getInstance(this.sunit)) {
continue;
}
if (isAllZeroInRow(matrix, row, column) == false) {
continue;
}
if (systemInRow instanceof ConstantSystem && systemInColumn instanceof ConstantSystem) {
matrix[k][column] = ((ConstantSystem<RS,RM,CS,CM>) systemInColumn)
.add(((ConstantSystem<RS,RM,CS,CM>) systemInRow).multiply(gainSystem));
} else {
final SystemOperator<RS,RM,CS,CM> contractedSystem;
if (systemInRow instanceof ConstantSystem) {
contractedSystem = ((ConstantSystem<RS,RM,CS,CM>) systemInRow).multiply(gainSystem);
} else {
contractedSystem = multiplyGain((LinearSystemOperator<RS,RM,CS,CM>) systemInRow, gain1);
}
if (contractedSystem.hasDirectFeedthrough()) {
matrix[k][column] = contractedSystem;
} else {
nodeTmpValue.set(k, nodeTmpValue.get(k).add(calcOutputOfNonDirectFeedthroughSystem(contractedSystem)));
matrix[k][column] = ZeroSystem.getInstance(this.sunit);
}
}
final RM gain2 = ((ConstantSystem<RS,RM,CS,CM>) systemInRow).getGain();
nodeTmpValue.set(k, nodeTmpValue.get(k).add(gain2.multiply(nodeTmpValue.get(row))));
changed = true;
if (isAllZeroInRow(matrix, row, column)) {
matrix[k][row] = ZeroSystem.getInstance(this.sunit);
}
}
}
}
}
return changed;
}
/**
* (行方向に)単位システムを前方のシステムに結合(単位エッジを縮約)します。
*
* @param matrix 隣接行列
* @param tmpValue 仮のノードの値
* @return 縮約したならばtrue、そうでなければfalse
*/
boolean contractUnitEdgeForwardRowWise(final SystemOperator<RS, RM, CS, CM>[][] matrix, final RM[] tmpValue) {
final int rowSize = matrix.length;
final int columnSize = rowSize == 0 ? 0 : matrix[0].length;
boolean changed = false;
for (int row = 0; row < rowSize; row++) {
for (int column = 0; column < columnSize; column++) {
boolean hasSelfLoop = (row == column && matrix[row][column] != ZeroSystem.getInstance(this.sunit));
if (hasSelfLoop) {
return changed;
}
if (!(matrix[row][column] instanceof UnitSystem)) {
continue;
}
if (! isAllZeroInRow(matrix, row, column)) {
continue;
}
if (! isEitherColumnZeroOrBothConstant(matrix, row, column)) {
continue;
}
if (tmpValue[row].isZero()) {
for (int k = 0; k < rowSize; k++) {
if (matrix[k][row] == ZeroSystem.getInstance(this.sunit)) {
continue;
}
changed = true;
matrix[k][column] = matrix[k][row];
matrix[k][row] = ZeroSystem.getInstance(this.sunit);
}
} else if (isAllConstantOrZeroInColumn(matrix, column)) {
for (int k = 0; k < rowSize; k++) {
if (matrix[k][row] == ZeroSystem.getInstance(this.sunit)) {
continue;
}
changed = true;
matrix[k][column] = matrix[k][row];
RM gain = ((ConstantSystem<RS,RM,CS,CM>) matrix[k][row]).getGain();
tmpValue[k] = tmpValue[k].add(gain.multiply(tmpValue[row]));
matrix[k][row] = ZeroSystem.getInstance(this.sunit);
}
}
}
}
return changed;
}
/**
* 入力の数を返します。
*
* @return 入力ノードの入力の数
*/
private int findInputSize() {
if (this.inputNodes.size() == 0) {
return 0;
}
int inputSize = 0;
for (int inputNode : this.inputNodes) {
inputSize += Math.max(findNodeSize(inputNode), 0);
}
return inputSize;
}
/**
* 出力数が未定のInputPortの出力数を0に設定します。
*/
private void setZeroSizeToUnDefinedInputPort() {
for (int inputNode : this.inputNodes) {
for (int column = 0; column < this.nodeSize; column++) {
SystemOperator<RS,RM,CS,CM> system = this.elements[inputNode - 1][column];
if (system == null || system == ZeroSystem.getInstance(this.sunit)) {
continue;
}
if (system instanceof UnitSystem && system.getOutputSize() == -1) {
system.setOutputSize(0);
}
}
}
}
/**
* 入力数が未定のOutputPortの入力数を0に設定します。
*/
private void setZeroSizeToUnDefinedOutputPort() {
for (int outputNode : this.outputNodes) {
for (int row = 0; row < this.nodeSize; row++) {
SystemOperator<RS,RM,CS,CM> system = this.elements[row][outputNode - 1];
if (system == null || system == ZeroSystem.getInstance(this.sunit)) {
continue;
}
if (system instanceof UnitSystem && system.getInputSize() == -1) {
system.setInputSize(0);
}
}
}
}
/**
* 出力の数を返します。
*
* @return 出力ノードの出力の数
*/
private int findOutputSize() {
if (this.outputNodes.size() == 0) {
return 0;
}
int outputSize = 0;
for (int outputNode : this.outputNodes) {
outputSize += Math.max(findNodeSize(outputNode), 0);
}
return outputSize;
}
/**
* ノードの大きさ(信号の数)を返します。
*
* @param nodeNumber ノードの番号
* @return ノードの大きさ(信号の数)
*/
private int findNodeSize(int nodeNumber) {
for (int column = 0; column < this.nodeSize; column++) {
final SystemOperator<RS,RM,CS,CM> system = this.elements[nodeNumber - 1][column];
if (system != ZeroSystem.getInstance(this.sunit)) {
// inlet の場合は入力の数が0
final int size = system.getInputSize();
if (size >= 0) {
return size;
}
}
}
for (int row = 0; row < this.nodeSize; row++) {
final SystemOperator<RS,RM,CS,CM> system = this.elements[row][nodeNumber - 1];
if (system != ZeroSystem.getInstance(this.sunit)) {
// outlet の場合は出力の数が0
final int size = system.getOutputSize();
if (size >= 0) {
return size;
}
}
}
return -1;
}
/**
* 入力数と出力数が決定されていないシステムの入出力数を設定します。
*/
private void setInputSizeAndOutpuSize() {
boolean nodeSizeResized = false;
do {
nodeSizeResized = false;
for (int column = 0; column < this.nodeSize; column++) {
for (int row = 0; row < this.nodeSize; row++) {
final SystemOperator<RS,RM,CS,CM> system = this.elements[row][column];
if (system == ZeroSystem.getInstance(this.sunit)) {
continue;
}
final int inputNodeSize = this.nodeSizes[row];
if (inputNodeSize != -1) {
if (system.isAutoSize() == false && system.getInputSize() != inputNodeSize) {
throw new RuntimeException("" + system + ": " + Messages.getString("BlockSystem.3")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
if (inputNodeSize != system.getInputSize()) {
system.setInputSize(inputNodeSize);
if (this.nodeSizes[column] != system.getOutputSize() && system.getOutputSize() != -1) {
this.nodeSizes[column] = system.getOutputSize();
nodeSizeResized = true;
}
}
}
final int outputNodeSize = this.nodeSizes[column];
if (outputNodeSize != -1) {
if (system.isAutoSize() == false && system.getOutputSize() != outputNodeSize) {
throw new RuntimeException("" + system + ": " + Messages.getString("BlockSystem.4")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
if (outputNodeSize != system.getOutputSize()) {
system.setOutputSize(outputNodeSize);
if (this.nodeSizes[row] != system.getInputSize() && system.getInputSize() != -1) {
this.nodeSizes[row] = system.getInputSize();
nodeSizeResized = true;
}
}
}
}
}
} while (nodeSizeResized);
}
/**
* システムと入力ノード番号の対を設定します。
*/
@SuppressWarnings("boxing")
private void setupInputMap() {
this.inputMap.clear();
final int size = this.nodeSize;
for (int row = 0; row < size; row++) {
for (int column = 0; column < size; column++) {
final SystemOperator<RS,RM,CS,CM> system = this.elements[row][column];
if (system != ZeroSystem.getInstance(this.sunit)) {
this.inputMap.put(system.getID(), row);
}
}
}
}
/**
* ノードの大きさ(信号の数)を設定します。
*/
private void setupNodeSize() {
this.nodeSizes = new int[this.nodeSize];
for (int i = 0; i < this.nodeSize; i++) {
this.nodeSizes[i] = findNodeSize(i + 1);
}
}
/**
* 入力ノードに値を設定します。
*
* @param u 入力ノードの値
*/
public void setInputNodeValue(RM u) {
if (u.length() != getInputSize()) {
throw new RuntimeException(Messages.getString("BlockSystem.8")); //$NON-NLS-1$
}
int offset = 1;
for (int inputNode : this.inputNodes) {
int size = this.nodeSizes[inputNode - 1];
if (size > 0) {
this.nodeValue.set(inputNode - 1, u.getSubVector(offset, offset + size - 1));
offset += size;
}
}
}
/**
* 出力ノードの値を返します。
*
* @return 出力ノードの値
*/
protected RM getOutputNodeValue() {
RM y = this.sunit.createZeroGrid(0, 1);
for (int outputNode : this.outputNodes) {
y = y.appendDown(this.nodeValue.get(outputNode - 1));
}
return y;
}
/**
* システムへ入力するノードの値を返します。
*
* @param system 入力するノードの値を調べるシステム
* @return システムへ入力するノードの値
*/
@SuppressWarnings("boxing")
public RM getInputNodeValueOf(SystemOperator<RS,RM,CS,CM> system) {
if (this.inputMap.containsKey(system.getID()) == false) {
throw new RuntimeException(Messages.getString("BlockSystem.11")); //$NON-NLS-1$
}
return this.nodeValue.get(this.inputMap.get(system.getID()));
}
/**
* ノードの数を返します。
*
* @return ノードの数
*/
public int getNodeSize() {
return this.nodeSize;
}
/**
* 入力ノードの数を返します。
*
* @return 入力ノードの数
*/
public int getInputNodeSize() {
return this.inputNodes.size();
}
/**
* 出力ノードの数を返します。
*
* @return 出力ノードの数
*/
public int getOutputNodeSize() {
return this.outputNodes.size();
}
/**
* 線形でないシステムが含まれているか調べ、線形性を設定します。
*/
private void setupLinear() {
setLinear(true);
final int size = this.nodeSize;
for (int row = 0; row < size; row++) {
for (int column = 0; column < size; column++) {
final SystemOperator<RS,RM,CS,CM> system = this.elements[row][column];
final boolean notLinear = system.isLinear() == false;
final boolean notInputPort = (system instanceof InputPort) == false;
final boolean notOutputPort = (system instanceof OutputPort) == false;
final boolean notZeroSystem = system != ZeroSystem.getInstance(this.sunit);
if (notZeroSystem && notInputPort && notOutputPort && notLinear) {
setLinear(false);
return;
}
}
}
}
/**
* ノードの値をリセットします。
*/
protected void resetNodeValue() {
final int size = this.nodeSize;
for (int i = 0; i < size; i++) {
this.nodeValue.set(i, null);
}
}
/**
* ノードの仮の値をゼロに設定します。
*
* @param nodeTmpValue ノードの仮の値
*/
private void setZeroNodeTmpValue(final ArrayList<RM> nodeTmpValue) {
final int size = this.nodeSize;
for (int column = 0; column < size; column++) {
for (int row = 0; row < size; row++) {
if (this.elements[row][column] == ZeroSystem.getInstance(this.sunit)) {
continue;
}
int nodeSizeI = this.elements[row][column].getOutputSize();
if (nodeTmpValue.get(column) == null) {
nodeTmpValue.set(column, this.sunit.createZeroGrid(nodeSizeI, 1));
} else if (nodeTmpValue.get(column).getRowSize() != nodeSizeI) {
throw new RuntimeException(Messages.getString("BlockSystem.12")); //$NON-NLS-1$
}
int nodeSizeJ = this.elements[row][column].getInputSize();
if (nodeTmpValue.get(row) == null) {
nodeTmpValue.set(row, this.sunit.createZeroGrid(nodeSizeJ, 1));
} else if (nodeTmpValue.get(row).getRowSize() != nodeSizeJ) {
throw new RuntimeException(Messages.getString("BlockSystem.13")); //$NON-NLS-1$
}
}
}
for (int i = 0; i < size; i++) {
if (nodeTmpValue.get(i) == null) {
throw new RuntimeException(Messages.getString("BlockSystem.14") + i + Messages.getString("BlockSystem.15")); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
/**
* 値が決定されていない(nullである)番号を返します。
*
* @param values ノードの値の配列
* @return 値が決定されていない(nullである)番号の配列
*/
private int[] getUnknownNode(final List<RM> values) {
final int size = values.size();
int count = 0;
for (int i = 0; i < size; i++) {
if (values.get(i) == null) {
count++;
}
}
int[] unknownNode = new int[count];
for (int i = 0, j = 0; i < size; i++) {
if (values.get(i) == null) {
unknownNode[j++] = i;
}
}
return unknownNode;
}
/**
* 直達項成分の隣接行列の転置を生成します。
*
* @param matrix 隣接行列
* @return 直達項成分の隣接行列の転置
*/
@SuppressWarnings("boxing")
private SystemOperator<RS, RM, CS, CM>[][] getDirectFeedthroughPart(final SystemOperator<RS, RM, CS, CM>[][] matrix) {
final int size = this.nodeSize;
final SystemOperator<RS, RM, CS, CM>[][] newMatrix = new SystemOperator[size][size];
for (int row = 0; row < size; row++) {
for (int column = 0; column < size; column++) {
final SystemOperator<RS,RM,CS,CM> system = matrix[row][column];
if (!system.hasDirectFeedthrough()) {
newMatrix[row][column] = ZeroSystem.getInstance(this.sunit);
} else if (system instanceof LinearSystemOperator && ((LinearSystemOperator<RS,RM,CS,CM>) system).hasVariableE() == false
&& system instanceof DynamicSystem) {
final RM D = ((LinearSystemOperator<RS,RM,CS,CM>) system).getLinearSystem().getD();
final SystemOperator<RS,RM,CS,CM> newSystem = new ConstantSystem<>(D);
newMatrix[row][column] = newSystem;
newMatrix[row][column].setID(system.getID() + "D"); //$NON-NLS-1$
final int inputNumber = this.inputMap.get(system.getID());
this.inputMap.put(newSystem.getID(), inputNumber);
} else {
newMatrix[row][column] = system;
}
}
}
return newMatrix;
}
/**
* 転置グリッドを生成します。
*
* @param grid 元のグリッド
* @return 転置グリッド
*/
private SystemOperator<RS, RM, CS, CM>[][] transpose(final SystemOperator<RS, RM, CS, CM>[][] grid) {
final int rowSize = grid.length;
final int columnSize = rowSize == 0 ? 0 : grid[0].length;
SystemOperator<RS, RM, CS, CM>[][] ans = new SystemOperator[columnSize][rowSize];
for (int row = 0; row < rowSize; row++) {
SystemOperator<RS, RM, CS, CM>[] gridi = grid[row];
for (int column = 0; column < columnSize; column++) {
ans[column][row] = gridi[column]; // not generate clone
}
}
return ans;
}
/**
* 部分グリッドを返します。
*
* @param grid 元のグリッド
* @param rowIndex 該当する行の番号
* @param columnIndex 該当する列の番号
* @return 部分グリッド
*/
final SystemOperator<RS,RM,CS,CM>[][] getSubMatrix(final SystemOperator<RS,RM,CS,CM>[][] grid, final int[] rowIndex,
final int[] columnIndex) {
final int rowSize = rowIndex.length;
final int columnSize = columnIndex.length;
SystemOperator<RS,RM,CS,CM>[][] ans = new SystemOperator[rowSize][columnSize];
for (int row = 0; row < rowSize; row++) {
SystemOperator<RS,RM,CS,CM>[] ansi = ans[row];
SystemOperator<RS,RM,CS,CM>[] gridi = grid[rowIndex[row]];
for (int column = 0; column < columnSize; column++) {
ansi[column] = gridi[columnIndex[column]]; // not generage clone
}
}
return ans;
}
/**
* 直達項の無いシステムの出力を求めます。
*
* @param system 直達項の無いシステム
* @return 直達項の無いシステムの出力
* @exception SolverStopException ソルバーが停止された場合
*/
protected abstract RM calcOutputOfNonDirectFeedthroughSystem(SystemOperator<RS,RM,CS,CM> system) throws SolverStopException;
/**
* 直達項のあるシステムの出力を求めます。
*
* @param system 直達項のあるシステム
* @param u 入力
* @return 直達項のあるシステムの出力
* @exception SolverStopException ソルバーが停止された場合
*/
protected abstract RM calcOutputOfDirectFeedthroughSystem(SystemOperator<RS,RM,CS,CM> system, RM u) throws SolverStopException;
/**
* 強プロパーな線形動的システムを生成します。
*
* @param system バイプロパーな線形動的システム
* @return 強プロパーな線形動的システム
*/
protected abstract SystemOperator<RS,RM,CS,CM> createStrictlyProperLinearDynamicSystem(SystemOperator<RS,RM,CS,CM> system);
/**
* 動的システムのリストの成分を新しいシステムに入れ替えます。
*
* @param oldSystem リストに登録されている旧システム
* @param newSystem リストに登録する新システム
* @return 入れ替えが成功した場合true
*/
protected abstract boolean replaceDynamicSystemList(SystemOperator<RS,RM,CS,CM> oldSystem, SystemOperator<RS,RM,CS,CM> newSystem);
/**
* 次数最小の未知のノードの値を計算します。
*
* @param matrix 隣接行列を転置した行列
* @param nodeTmpValue ノードの仮の値
* @param unknownNode 未知のノードの番号の配列
*/
private void calcUnknownMinimumNodeValues(final SystemOperator<RS, RM, CS, CM>[][] matrix, final List<RM> nodeTmpValue,
final int[] unknownNode) {
SystemOperator<RS, RM, CS, CM>[][] newMatrix = getSubMatrix(matrix, unknownNode, unknownNode);
ArrayList<RM> newNodeTmpValue = new ArrayList<>(unknownNode.length);
for (int i = 0; i < unknownNode.length; i++) {
newNodeTmpValue.set(i, nodeTmpValue.get(unknownNode[i]));
}
if (this.cuttingNodes == null) {
this.cuttingNodes = new MinimumUnknownEquation<>(new AdjacencyMatrix<>(newMatrix, this.sunit)).getCuttingNodes();
// this.cuttingNodes = getCuttingNodes(newMatrix);
}
// 初期値の設定
if (this.cuttingNodeValues == null) {
this.cuttingNodeValues = new ArrayList<>(this.cuttingNodes.size());
int k = 0;
for (List<Integer> nodes : this.cuttingNodes) {
int n = 0;
for (int i : nodes) {
n = n + newNodeTmpValue.get(i - 1).length();
}
this.cuttingNodeValues.set(k++, this.sunit.createZeroGrid(n, 1));
}
}
final NonLinearEquationSolver<RS,RM> solver = new NewtonRaphsonFixedPointSolver<>();
int k = 0;
for (List<Integer> nodes : this.cuttingNodes) {
NonLinearFunction<RS,RM> ne = new NodeIdentityFunctionEquation<>(this, newMatrix, newNodeTmpValue, nodes);
try {
this.cuttingNodeValues.set(k, solver.solve(ne, this.cuttingNodeValues.get(k)));
} catch (SolverException e) {
throw new RuntimeException(e);
}
int offset = 0;
for (int i : nodes) {
int n = newNodeTmpValue.get(i - 1).length();
this.nodeValue.set(unknownNode[i - 1], this.cuttingNodeValues.get(k).getSubVector(offset + 1, offset + n));
offset = offset + n;
}
k++;
}
}
/**
* 直達項の無いシステムの出力を仮のノードへ加え、そのシステムを隣接行列から削除します。
*
* @param matrix 隣接行列を転置した行列
* @param nodeTmpValue 仮のノードの値
* @exception SolverStopException ソルバーが停止された場合
*/
private void calcOutputOfNonDirectFeedthroughSystem(final SystemOperator<RS, RM, CS, CM>[][] matrix,
final List<RM> nodeTmpValue) throws SolverStopException {
final int size = this.nodeSize;
for (int row = 0; row < size; row++) {
for (int column = 0; column < size; column++) {
SystemOperator<RS,RM,CS,CM> system = matrix[row][column];
if (system == null)
throw new IllegalArgumentException("Adjacency matrix contained null system."); //$NON-NLS-1$
if (system == ZeroSystem.getInstance(this.sunit)) {
continue;
}
if (system.hasDirectFeedthrough()) {
continue;
}
RM output = calcOutputOfNonDirectFeedthroughSystem(system);
nodeTmpValue.set(row, nodeTmpValue.get(row).add(output));
matrix[row][column] = ZeroSystem.getInstance(this.sunit);
}
}
}
/**
* 非直達項成分の隣接行列の転置を生成します。
*
* @param matrix 隣接行列
* @return 非直達項成分の隣接行列の転置
*/
@SuppressWarnings("boxing")
private SystemOperator<RS, RM, CS, CM>[][] getNonDirectFeedthroughPart(
final SystemOperator<RS, RM, CS, CM>[][] matrix) {
final int size = this.nodeSize;
final SystemOperator<RS, RM, CS, CM>[][] newMatrix = new SystemOperator[size][size];
for (int row = 0; row < size; row++) {
for (int column = 0; column < size; column++) {
final SystemOperator<RS, RM, CS, CM> system = matrix[row][column];
if (!system.hasDirectFeedthrough()) {
newMatrix[row][column] = system;
} else if (system instanceof LinearSystemOperator && ((LinearSystemOperator<RS, RM, CS, CM>) system).hasVariableE() == false
&& system instanceof DynamicSystem) {
final SystemOperator<RS, RM, CS, CM> newSystem = createStrictlyProperLinearDynamicSystem(system);
newMatrix[row][column] = newSystem;
newMatrix[row][column].setID(system.getID() + "N"); //$NON-NLS-1$
final int inputNumber = this.inputMap.get(system.getID());
this.inputMap.put(newSystem.getID(), inputNumber);
replaceDynamicSystemList(system, newSystem);
} else {
newMatrix[row][column] = ZeroSystem.getInstance(this.sunit);
}
}
}
return newMatrix;
}
/**
* 確定したノードの値を用いて各直達項の有るシステムの出力を計算し、その値を仮のノードへ加えます。
* <p>
* そして、そのシステムを隣接行列から削除します。
*
* @param matrix 隣接行列を転置した行列
* @param localNodeValue ノードの値
* @param nodeTmpValue 仮のノードの値
* @param skip 値が決定しているノードについて計算をスキップする場合true
* @return 隣接行列から削除されたシステムがある場合true
* @exception SolverStopException ソルバーが停止された場合
*/
public boolean calcOutputOfDirectFeedthroughSystem(final SystemOperator<RS, RM, CS, CM>[][] matrix,
final List<RM> localNodeValue, final List<RM> nodeTmpValue, final boolean skip) throws SolverStopException {
final int localNodeNumber = nodeTmpValue.size();
boolean changed = false;
for (int row = 0; row < localNodeNumber; row++) {
if (skip && localNodeValue.get(row) != null) {
continue;
}
for (int column = 0; column < localNodeNumber; column++) {
RM u = localNodeValue.get(column);
SystemOperator<RS, RM, CS, CM> system = matrix[row][column];
if (u == null || system == ZeroSystem.getInstance(this.sunit)) {
continue;
}
RM output = calcOutputOfDirectFeedthroughSystem(system, u);
nodeTmpValue.set(row, nodeTmpValue.get(row).add(output));
matrix[row][column] = ZeroSystem.getInstance(this.sunit);
changed = true;
}
}
return changed;
}
/**
* ノードの値を計算します。
*
* @exception SolverStopException ソルバーが停止された場合
*/
protected void calcNodeValue() throws SolverStopException {
SystemOperator<RS, RM, CS, CM>[][] noDirectMatrix = transpose(this.nonDirectFeedthroughElements);
SystemOperator<RS, RM, CS, CM>[][] matrix = transpose(this.directFeedthroughElements);
ArrayList<RM> nodeTmpValue = new ArrayList<>(this.nodeSize);
setZeroNodeTmpValue(nodeTmpValue);
calcOutputOfNonDirectFeedthroughSystem(noDirectMatrix, nodeTmpValue);
setNodeValueOfNoInputNode(matrix, this.nodeValue, nodeTmpValue, true);
do {
while (calcOutputOfDirectFeedthroughSystem(matrix, this.nodeValue, nodeTmpValue, true)) {
setNodeValueOfNoInputNode(matrix, this.nodeValue, nodeTmpValue, true);
}
boolean changed1 = contractConstantEdgeForwardRowWise(matrix, nodeTmpValue);
if (changed1) {
setNodeValueOfNoInputNode(matrix, this.nodeValue, nodeTmpValue, true);
}
boolean changed2 = resolveConstantSelfLoop(matrix, nodeTmpValue);
if (changed2) {
setNodeValueOfNoInputNode(matrix, this.nodeValue, nodeTmpValue, true);
}
if (!changed1 && !changed2) {
break;
}
} while (true);
int[] unknownNode = getUnknownNode(this.nodeValue);
if (unknownNode.length == 0) {
return;
}
calcUnknownMinimumNodeValues(matrix, nodeTmpValue, unknownNode);
while (calcOutputOfDirectFeedthroughSystem(matrix, this.nodeValue, nodeTmpValue, true)) {
setNodeValueOfNoInputNode(matrix, this.nodeValue, nodeTmpValue, true);
}
}
/**
* @see org.mklab.tool.control.system.SystemOperator#getLinearSystem()
*/
@Override
public LinearSystem<RS,RM,CS,CM> getLinearSystem() {
final AdjacencyMatrix<RS,RM,CS,CM> adjMatrix = new AdjacencyMatrix<>(this.elements, this.sunit).clone();
adjMatrix.setInputNodes(this.inputNodes);
adjMatrix.setOutputNodes(this.outputNodes);
adjMatrix.setRequiringLinearSystem(true);
return adjMatrix.getLinearSystem(false);
}
/**
* @see org.mklab.tool.control.system.SystemOperator#initialize()
*/
@Override
public void initialize() {
final int rowSize = this.elements.length;
final int columnSize = rowSize == 0 ? 0 : this.elements[0].length;
for (int row = 0; row < rowSize; row++) {
for (int column = 0; column < columnSize; column++) {
SystemOperator<RS,RM,CS,CM> system = this.elements[row][column];
if (system == ZeroSystem.getInstance(this.sunit)) {
continue;
}
system.initialize();
}
}
}
/**
* 非直達項成分と直達項成分を分離し、2個の隣接行列を生成します。
*/
public void separateDirectFeedthroughAndNonDirectFeedthrough() {
this.directFeedthroughElements = getDirectFeedthroughPart(this.elements);
this.nonDirectFeedthroughElements = getNonDirectFeedthroughPart(this.elements);
}
/**
* 単一のシステムであるか判定します。
*
* @return 単一のシステムならばtrue、そうでなければfalse
*/
public boolean isSingleSystem() {
if (this.nodeSize != 2) {
return false;
}
if (this.elements[0][0] != ZeroSystem.getInstance(this.sunit)) {
return false;
}
if (this.elements[1][0] != ZeroSystem.getInstance(this.sunit)) {
return false;
}
if (this.elements[1][1] != ZeroSystem.getInstance(this.sunit)) {
return false;
}
if (this.elements[0][1] == ZeroSystem.getInstance(this.sunit)) {
return false;
}
return true;
}
/**
* 単一のシステムであるならば、単一システムを返します。
*
* @return 単一システム
* @throws RuntimeException 単一のシステムでない場合
*/
public SystemOperator<RS,RM,CS,CM> getSingleSystem() {
if (isSingleSystem() == false) {
throw new RuntimeException(Messages.getString("BlockSystem.19")); //$NON-NLS-1$
}
return this.elements[0][1];
}
/**
* ブロックシステムを拡張された隣接行列に代入します。
*
* @param matrix 拡張された隣接行列
* @param row ブロックシステムの行番号
* @param column ブロックシステムの列番号
* @param blockSystem ブロックシステムの成分
* @return Sourceが接続されているノードのリスト、Sinkが接続されているノードのリスト
*/
public List<List<Integer>> setBlockMatrix(final SystemOperator<RS,RM,CS,CM>[][] matrix, final int row, final int column,
final BlockSystem<RS,RM,CS,CM> blockSystem) {
final SystemOperator<RS,RM,CS,CM>[][] blockMatrix = blockSystem.elements;
final int blockSize = blockMatrix.length - 1; // 最初のinputNodeSize列と最終のoutputNodeSize行は全て零成分
final int inputNodeSize = blockSystem.getInputNodeSize();
final int outputNodeSize = blockSystem.getOutputNodeSize();
final int inputOutputNodeSize = Math.min(inputNodeSize, outputNodeSize);
final int firstColumn = column - inputOutputNodeSize + 1;
// final int firstColumn = column - outputNodeSize + 1;
final List<Integer> sourceNodes = new ArrayList<>();
final List<Integer> sinkNodes = new ArrayList<>();
if (row <= column) {
// input row
for (int i = 0; i < inputNodeSize; i++) {
for (int j = 0; j < blockSize; j++) {
final SystemOperator<RS,RM,CS,CM> system = blockMatrix[i][j + 1];
final int input = row + i;
final int output = firstColumn + j;
matrix[input][output] = system;
setupSourceSink(system, input + 1, output + 1, sourceNodes, sinkNodes);
}
}
for (int i = inputNodeSize; i < blockSize; i++) {
for (int j = 0; j < blockSize; j++) {
final SystemOperator<RS,RM,CS,CM> system = blockMatrix[i][j + 1];
final int input = firstColumn - 1 + i;
final int output = firstColumn + j;
matrix[input][output] = system;
setupSourceSink(system, input + 1, output + 1, sourceNodes, sinkNodes);
}
}
} else {
// input row
for (int i = 0; i < inputNodeSize; i++) {
for (int j = 0; j < blockSize; j++) {
final SystemOperator<RS,RM,CS,CM> system = blockMatrix[i][j + 1];
final int input = row + i + blockSize - outputNodeSize;
final int output = firstColumn + j;
matrix[input][output] = system;
setupSourceSink(system, input + 1, output + 1, sourceNodes, sinkNodes);
}
}
for (int i = inputNodeSize; i < blockSize; i++) {
for (int j = 0; j < blockSize; j++) {
final SystemOperator<RS,RM,CS,CM> system = blockMatrix[i][j + 1];
final int input = firstColumn - 1 + i;
final int output = firstColumn + j;
matrix[input][output] = system;
setupSourceSink(system, input + 1, output + 1, sourceNodes, sinkNodes);
}
}
}
final List<List<Integer>> sourceNodesSinkNodes = new ArrayList<>();
sourceNodesSinkNodes.add(sourceNodes);
sourceNodesSinkNodes.add(sinkNodes);
return sourceNodesSinkNodes;
}
/**
* システムがSourceまたはSinkならば、接続されているノードをリストに追加します。
*
* @param system システム
* @param inputNode 入力ノード
* @param outputNode 出力ノード
* @param sourceNodes Sourceが接続されているノードのリスト
* @param sinkNodes Sinkが接続されているノードのリスト
*/
@SuppressWarnings("boxing")
private void setupSourceSink(final SystemOperator<RS,RM,CS,CM> system, final int inputNode, final int outputNode,
final List<Integer> sourceNodes, final List<Integer> sinkNodes) {
if (system == null || system == ZeroSystem.getInstance(this.sunit)) {
return;
}
if (system instanceof ContinuousSource && system instanceof InputPort == false) {
sourceNodes.add(inputNode);
}
if (system instanceof ContinuousSink && system instanceof OutputPort == false) {
sinkNodes.add(outputNode);
}
}
/**
* 指定されたノード間にあるシステムを返します。
*
* @param inputNode 入力ノード番号
* @param outputNode 出力ノード番号
* @return 指定されたノード間にあるシステム
*/
protected SystemOperator<RS,RM,CS,CM> getSystemOperator(final int inputNode, final int outputNode) {
return this.elements[inputNode][outputNode];
}
/**
* @see org.mklab.tool.control.system.SystemOperator#isAutoSize()
*/
@Override
public boolean isAutoSize() {
if (this.isSingleSystem()) {
return getSingleSystem().isAutoSize();
}
return super.isAutoSize();
}
/**
* @see org.mklab.tool.control.system.SystemOperator#setAutoSize(boolean)
*/
@Override
public void setAutoSize(final boolean autoSize) {
if (this.isSingleSystem()) {
this.getSingleSystem().setAutoSize(autoSize);
}
super.setAutoSize(autoSize);
}
/**
* @see org.mklab.tool.control.system.SystemOperator#resetAutoSize()
*/
@Override
public void resetAutoSize() {
if (this.isSingleSystem() == false) {
return;
}
super.setInputSize(-1);
super.setOutputSize(-1);
this.getSingleSystem().resetAutoSize();
}
/**
* @see org.mklab.tool.control.system.SystemOperator#setInputSize(int)
*/
@Override
public void setInputSize(final int inputSize) {
if (this.isSingleSystem()) {
final int singleInputSize = this.getSingleSystem().getInputSize();
if (singleInputSize != -1) {
super.setInputSize(singleInputSize);
}
} else {
super.setInputSize(inputSize);
}
}
/**
* @see org.mklab.tool.control.system.SystemOperator#setOutputSize(int)
*/
@Override
public void setOutputSize(final int outputSize) {
if (this.isSingleSystem()) {
final int singoleOutputSize = this.getSingleSystem().getOutputSize();
if (singoleOutputSize != -1) {
super.setOutputSize(singoleOutputSize);
}
} else {
super.setOutputSize(outputSize);
}
}
/**
* 全ての列成分がゼロ、線形システム、定数システムであるか判定します。
*
* @param matrix 隣接行列
* @param column 調べる列
* @return 全ての列成分がゼロ、線形システム、定数システムならばtrue、そうでなければfalse
*/
boolean isAllLinearOrConstantOrZeroInColumn(final SystemOperator<RS,RM,CS,CM>[][] matrix, final int column) {
final int rowSize = matrix.length;
for (int row = 0; row < rowSize; row++) {
SystemOperator<RS,RM,CS,CM> system = matrix[row][column];
if (system == ZeroSystem.getInstance(this.sunit) || system instanceof LinearSystemOperator || system instanceof ConstantSystem) {
continue;
}
return false;
}
return true;
}
/**
* 2列の成分のどちからかゼロシステムであるか、または両方とも定数システムであるか判定します。
*
* @param matrix 隣接行列
* @param column1 対象列1
* @param column2 対象列2
* @return 2列の成分のどちからかゼロシステムであるか、または両方とも定数システムならばtrue、そうでなければfalse
*/
boolean isEitherColumnZeroOrBothConstant(final SystemOperator<RS,RM,CS,CM>[][] matrix, final int column1, final int column2) {
final int rowSize = matrix.length;
for (int row = 0; row < rowSize; row++) {
if (matrix[row][column1] == ZeroSystem.getInstance(this.sunit) || matrix[row][column2] == ZeroSystem.getInstance(this.sunit)) {
continue;
}
if (matrix[row][column1] instanceof ConstantSystem && matrix[row][column2] instanceof ConstantSystem) {
continue;
}
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
*/
boolean isAllZeroInRow(final SystemOperator<RS,RM,CS,CM>[][] 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] != ZeroSystem.getInstance(this.sunit)) {
return false;
}
}
for (int k = column + 1; k < columnSize; k++) {
if (matrix[row][k] != ZeroSystem.getInstance(this.sunit)) {
return false;
}
}
return true;
}
/**
* 線形システムまたは定数システムに定数行列を掛けた結果を求めます。
*
* @param element 隣接行列
* @param gain 定数行列
* @return 線形システムまたは定数システムに定数行列を掛けた結果
*/
SystemOperator<RS,RM,CS,CM> multiplyGain(final LinearSystemOperator<RS, RM, CS, CM> element, final RM gain) {
if (element instanceof ConstantSystem) {
final RM gain2 = ((ConstantSystem<RS, RM, CS, CM>)element).getGain();
final RM mulGain = gain2.multiply(gain);
if (mulGain.isZero()) {
return ZeroSystem.getInstance(this.sunit);
}
return new ConstantSystem<>(gain2.multiply(gain));
}
if (element instanceof ContinuousLinearDynamicSystem) {
return new ContinuousLinearDynamicSystem<>(element.getLinearSystem().multiply(gain), this.sunit);
}
if (element instanceof DiscreteLinearDynamicSystem) {
return new DiscreteLinearDynamicSystem<>(element.getLinearSystem().multiply(gain), this.sunit);
}
throw new IllegalArgumentException(Messages.getString("AdjacencyMatrixUtil.5")); //$NON-NLS-1$
}
}