DoubleAbstractLinearSystem.java
/*
* Created on 2009/06/18
* Copyright (C) 2009 Koga Laboratory. All rights reserved.
*
*/
package org.mklab.tool.control;
import java.io.CharArrayWriter;
import java.io.Serializable;
import java.util.List;
import org.mklab.nfc.matrix.DoubleMatrix;
import org.mklab.nfc.matrix.DoubleRationalPolynomialMatrix;
import org.mklab.nfc.matrix.IntMatrix;
import org.mklab.nfc.scalar.DoubleNumber;
import org.mklab.tool.matrix.Diag;
import org.mklab.tool.matrix.Simplify;
/**
* 線形システムの抽象クラスです。
*
* @author Anan
*/
public abstract class DoubleAbstractLinearSystem implements Serializable, Cloneable, DoubleLinearSystem {
/** バージョン番号 */
private static final long serialVersionUID = -7441324992413004621L;
/** プロパーならばtrue */
protected boolean proper = true;
/** 厳密にプロバーならばtrue */
protected boolean strictlyProper = true;
/** 伝達関数行列 */
protected DoubleRationalPolynomialMatrix G = null;
/** 時間領域でのシステムの種類 */
protected TimeDomainType timeDomainType = TimeDomainType.CONTINUOUS;
/** 入力数 */
protected int inputSize;
/** 状態数 */
protected int stateSize;
/** 出力数 */
protected int outputSize;
/** システム行列 */
protected DoubleMatrix a = null;
/** 入力行列 */
protected DoubleMatrix b = null;
/** 出力行列 */
protected DoubleMatrix c = null;
/** ゲイン行列 */
protected DoubleMatrix d = null;
/** E行列 */
protected DoubleMatrix e = null;
/** 指数 */
protected IntMatrix index = null;
/** システム行列の式 */
private String[][] aSymbol;
/** 入力行列の式 */
private String[][] bSymbol;
/** 出力行列の式 */
private String[][] cSymbol;
/** ゲイン行列の式 */
private String[][] dSymbol;
/** ディスクリプタ行列の式 */
private String[][] eSymbol;
/** 入力ポートのタグ */
protected List<String> inputPortTags;
/** 出力ポートのタグ */
protected List<String> outputPortTags;
/** 状態のタグ */
private List<String> stateTags;
/**
* 2個のシステムが等しいか判定します。
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object opponent) {
if (this == opponent) {
return true;
}
if (opponent == null) {
return false;
}
if (opponent.getClass() != getClass()) {
return false;
}
final DoubleRationalPolynomialMatrix g1 = getTransferFunctionMatrix();
final DoubleRationalPolynomialMatrix g2 = ((DoubleLinearSystem)opponent).getTransferFunctionMatrix();
return g1.equals(g2);
}
/**
* 2個のシステムが等しいか判定します。
*
* @param opponent 対象となる線形システム
* @param tolerance 許容誤差
* @return 2個のシステムが等しいければtrue、そうでなければfalse
*/
public boolean equals(final Object opponent, final double tolerance) {
if (this == opponent) {
return true;
}
if (opponent == null) {
return false;
}
if (opponent.getClass() != getClass()) {
return false;
}
final DoubleRationalPolynomialMatrix g1 = getTransferFunctionMatrix();
final DoubleRationalPolynomialMatrix g2 = ((DoubleProperLinearSystem)opponent).getTransferFunctionMatrix();
return g1.equals(g2, tolerance);
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int hashCode = 1;
hashCode = 31 * hashCode + (int)(+serialVersionUID ^ (serialVersionUID >>> 32));
hashCode = 31 * hashCode + (this.proper ? 1231 : 1237);
hashCode = 31 * hashCode + (this.strictlyProper ? 1231 : 1237);
hashCode = 31 * hashCode + (this.G == null ? 0 : this.G.hashCode());
hashCode = 31 * hashCode + this.inputSize;
hashCode = 31 * hashCode + this.stateSize;
hashCode = 31 * hashCode + this.outputSize;
hashCode = 31 * hashCode + (this.a == null ? 0 : this.a.hashCode());
hashCode = 31 * hashCode + (this.b == null ? 0 : this.b.hashCode());
hashCode = 31 * hashCode + (this.c == null ? 0 : this.c.hashCode());
hashCode = 31 * hashCode + (this.d == null ? 0 : this.d.hashCode());
hashCode = 31 * hashCode + (this.inputPortTags == null ? 0 : this.inputPortTags.hashCode());
hashCode = 31 * hashCode + (this.outputPortTags == null ? 0 : this.outputPortTags.hashCode());
return hashCode;
}
/**
* 行番号を1からに設定します。
*
* @param matrix 行列の文字列
*/
protected void resetRowNumber(final String[] matrix) {
for (int i = 1; i < matrix.length; i++) {
matrix[i] = matrix[i].replaceFirst("\\(\\s*\\d+\\)", String.format("(% 3d)", Integer.valueOf(i))); //$NON-NLS-1$//$NON-NLS-2$
}
}
/**
* フォーマットされた状態のタグを返します。
*
* @return フォーマットされた状態のタグ
*/
protected String[] getSymbolicState() {
final int stateLength = getSymbolicStateLength();
final int outputLength = getSymbolicOutputLength();
final int length = Math.max(stateLength, outputLength);
final String[] symbolicStates = new String[getSubSystemSize()];
for (int i = 0; i < getSubSystemSize(); i++) {
final String stateTag = this.stateTags.get(i);
final String format = "%" + length + "s"; //$NON-NLS-1$ //$NON-NLS-2$
symbolicStates[i] = String.format(format, stateTag);
}
return symbolicStates;
}
/**
* フォーマットされた出力のタグを返します。
*
* @return フォーマットされた出力のタグ
*/
protected String[] getSymbolicOutput() {
final int stateLength = getSymbolicStateLength();
final int outputLength = getSymbolicOutputLength();
final int length = Math.max(stateLength, outputLength);
final String[] symbolicOutputs = new String[this.outputPortTags.size()];
for (int i = 0; i < this.outputPortTags.size(); i++) {
final String outputPortaTag = this.outputPortTags.get(i);
final String format = "%" + length + "s"; //$NON-NLS-1$ //$NON-NLS-2$
symbolicOutputs[i] = String.format(format, outputPortaTag);
}
return symbolicOutputs;
}
/**
* フォーマットされた入力のタグを返します。
*
* @return フォーマットされた入力のタグ
*/
protected String[] getSymbolicInput() {
final int stateLength = getSymbolicStateLength();
final int inputLength = getSymbolicInputLength();
final int length = Math.max(stateLength, inputLength);
final String[] symbolicInputs = new String[this.inputPortTags.size()];
for (int i = 0; i < this.inputPortTags.size(); i++) {
final String inputPortaTag = this.inputPortTags.get(i);
final String format = "%" + length + "s"; //$NON-NLS-1$ //$NON-NLS-2$
symbolicInputs[i] = String.format(format, inputPortaTag);
}
return symbolicInputs;
}
/**
* 状態のタグの最大長を返します。
*
* @return 状態のタグの最大長
*/
private int getSymbolicStateLength() {
int stateLength = 0;
for (final String stateTag : this.stateTags) {
if (stateLength < stateTag.length()) {
stateLength = stateTag.length();
}
}
return stateLength;
}
/**
* 入力ポートのタグの最大長を返します。
*
* @return 入力ポートのタグの最大長
*/
private int getSymbolicInputLength() {
int inputLength = 0;
for (final String inputPortTag : this.inputPortTags) {
if (inputLength < inputPortTag.length()) {
inputLength = inputPortTag.length();
}
}
return inputLength;
}
/**
* 出力ポートのタグの最大長を返します。
*
* @return 出力ポートのタグの最大長
*/
private int getSymbolicOutputLength() {
int outputLength = 0;
for (final String outputPortTag : this.outputPortTags) {
if (outputLength < outputPortTag.length()) {
outputLength = outputPortTag.length();
}
}
return outputLength;
}
/**
* Aの数式を返します。
*
* @return Aの数式
*/
public String getSymbolicA() {
final StringBuffer string = new StringBuffer();
final int[] columnLengthes = getColumnLengthesOfABCD();
for (int row = 0; row < getSubSystemSize(); row++) {
for (int column = 0; column < getSubSystemSize(); column++) {
final String format = "%" + columnLengthes[column] + "s"; //$NON-NLS-1$ //$NON-NLS-2$
string.append(String.format(format, this.aSymbol[row][column]));
if (column != getSubSystemSize() - 1) {
string.append(" "); //$NON-NLS-1$
}
}
string.append(System.getProperty("line.separator")); //$NON-NLS-1$
}
return string.toString();
}
/**
* Bの数式を返します。
*
* @return Bの数式
*/
public String getSymbolicB() {
final StringBuffer string = new StringBuffer();
final int[] columnLengthes = getColumnLengthesOfABCD();
for (int row = 0; row < getSubSystemSize(); row++) {
for (int column = 0; column < getInputPortSize(); column++) {
final String format = "%" + columnLengthes[column + getSubSystemSize()] + "s"; //$NON-NLS-1$ //$NON-NLS-2$
string.append(String.format(format, this.bSymbol[row][column]));
if (column != getInputSize() - 1) {
string.append(" "); //$NON-NLS-1$
}
}
string.append(System.getProperty("line.separator")); //$NON-NLS-1$
}
return string.toString();
}
/**
* Cの数式を返します。
*
* @return Cの数式
*/
public String getSymbolicC() {
final StringBuffer string = new StringBuffer();
final int[] columnLengthes = getColumnLengthesOfABCD();
for (int row = 0; row < getOutputPortSize(); row++) {
for (int column = 0; column < getSubSystemSize(); column++) {
final String format = "%" + columnLengthes[column] + "s"; //$NON-NLS-1$ //$NON-NLS-2$
string.append(String.format(format, this.cSymbol[row][column]));
if (column != getSubSystemSize() - 1) {
string.append(" "); //$NON-NLS-1$
}
}
string.append(System.getProperty("line.separator")); //$NON-NLS-1$
}
return string.toString();
}
/**
* Dの数式を返します。
*
* @return Dの数式
*/
public String getSymbolicD() {
final StringBuffer string = new StringBuffer();
final int[] columnLengthes = getColumnLengthesOfABCD();
for (int row = 0; row < getOutputPortSize(); row++) {
for (int column = 0; column < getInputPortSize(); column++) {
final String format = "%" + columnLengthes[column + getSubSystemSize()] + "s"; //$NON-NLS-1$ //$NON-NLS-2$
string.append(String.format(format, this.dSymbol[row][column]));
if (column != getInputPortSize() - 1) {
string.append(" "); //$NON-NLS-1$
}
}
string.append(System.getProperty("line.separator")); //$NON-NLS-1$
}
return string.toString();
}
/**
* Eの数式を返します。
*
* @return Eの数式
*/
public String getSymbolicE() {
final StringBuffer string = new StringBuffer();
final int[] columnLengthes = getColumnLengthesOfABCD();
for (int row = 0; row < getSubSystemSize(); row++) {
for (int column = 0; column < getSubSystemSize(); column++) {
final String format = "%" + columnLengthes[column] + "s"; //$NON-NLS-1$ //$NON-NLS-2$
string.append(String.format(format, this.eSymbol[row][column]));
if (column != getSubSystemSize() - 1) {
string.append(" "); //$NON-NLS-1$
}
}
string.append(System.getProperty("line.separator")); //$NON-NLS-1$
}
return string.toString();
}
/**
* 上部と下部を分割する水平線を描きます。
*
* @param string 生成する文字列
* @param columnLengthes 各列の文字列の長さ
*/
protected void drawHorizontalLine(final StringBuffer string, final int[] columnLengthes) {
int firstLength = 0;
for (int i = 0; i < getSubSystemSize(); i++) {
firstLength += columnLengthes[i];
if (i != getSubSystemSize() - 1) {
firstLength += 2;
}
}
int secondLength = 0;
for (int i = 0; i < getInputPortSize(); i++) {
secondLength += columnLengthes[i + getSubSystemSize()];
if (i != getInputPortSize() - 1) {
secondLength += 2;
}
}
for (int i = 0; i < firstLength; i++) {
string.append("-"); //$NON-NLS-1$
}
string.append("+"); //$NON-NLS-1$
for (int i = 0; i < secondLength; i++) {
string.append("-"); //$NON-NLS-1$
}
}
/**
* 列毎の成分の長さの最大値を返します。
*
* @return 列毎の成分の長さの最大値
*/
protected int[] getColumnLengthesOfABCD() {
final int[] columnLengthes = new int[getSubSystemSize() + getInputPortSize()];
for (int column = 0; column < getSubSystemSize(); column++) {
final int aLength = getMaxLengthColumnWise(this.aSymbol, column);
final int cLength = getMaxLengthColumnWise(this.cSymbol, column);
columnLengthes[column] = aLength > cLength ? aLength : cLength;
}
for (int column = 0; column < getInputPortSize(); column++) {
final int bLength = getMaxLengthColumnWise(this.bSymbol, column);
final int dLength = getMaxLengthColumnWise(this.dSymbol, column);
columnLengthes[column + getSubSystemSize()] = bLength > dLength ? bLength : dLength;
}
return columnLengthes;
}
/**
* 指定された列の成分の最大の長さを返します。
*
* @param matrix 対象となる行列
* @param column 指定列
* @return 指定された列の成分の最大の長さ
*/
protected int getMaxLengthColumnWise(final String[][] matrix, final int column) {
int length = 0;
for (int row = 0; row < matrix.length; row++) {
if (matrix[row] != null && matrix[row][column] != null && matrix[row][column].length() > length) {
length = matrix[row][column].length();
}
}
return length;
}
/**
* プロパーであるか判定します。
*
* @return プロパーならばtrue、そうでなければfalse
*/
public boolean isProper() {
return this.proper;
}
/**
* 厳密にプロパーであるか判定します。
*
* @return 厳密にプロパーならばtrue、そうでなければfalse
*/
public boolean isStrictlyProper() {
return this.strictlyProper;
}
/**
* 1入力1出力(SISO)であるか判定します。
*
* @return SISO(1入力1出力)システムならばtrue、そうでなければfalse
*/
public boolean isSISO() {
return getInputSize() == 1 && getOutputSize() == 1;
}
/**
* A行列(システム行列)を返します。
*
* @return A行列(システム行列)
*/
public DoubleMatrix getA() {
return this.a;
}
/**
* B行列(入力行列)を返します。
*
* @return B行列(入力行列)
*/
public DoubleMatrix getB() {
return this.b;
}
/**
* C行列(出力行列)を返します。
*
* @return C行列(出力行列)
*/
public DoubleMatrix getC() {
return this.c;
}
/**
* E行列(ディスクリプタ行列)を返します。
*
* @return the e
*/
public DoubleMatrix getE() {
return this.e;
}
/**
* D行列(ゲイン行列)を返します。
*
* @return D行列(ゲイン行列)
*/
public DoubleMatrix getD() {
return this.d;
}
/**
* 状態の数を返します。
*
* @return 状態の数
*/
public int getStateSize() {
return this.stateSize;
}
/**
* 入力の数を返します。
*
* @return 入力の数
*/
public int getInputSize() {
return this.inputSize;
}
/**
* 出力の数を返します。
*
* @return 出力の数
*/
public int getOutputSize() {
return this.outputSize;
}
/**
* システムの伝達関数行列を返します。
*
* <p>生成されるシステムを簡単化します。
*
* @return 伝達関数行列
*/
public DoubleRationalPolynomialMatrix getTransferFunctionMatrix() {
final double tolerance = 1.0E-15;
return getTransferFunctionMatrix(true, tolerance);
}
/**
* システム<code>opponent</code>との和(並列結合)でできるシステムを返します。
*
* <p>結合システムは簡単化されます。
*
* @param opponent 結合する(加えられる)システム
* @return システム<code>opponent</code>との和(並列結合)でできるシステム
*/
public DoubleLinearSystem add(final DoubleLinearSystem opponent) {
return add(opponent, true);
}
/**
* システム<code>opponent</code>との和(並列結合)でできるシステムを返します。
*
* @param opponent 結合する(加えられる)システム
* @param simplify 簡単化するならばtrue、そうでなければfalse
* @return システム<code>opponent</code>との和(並列結合)でできるシステム
*/
public DoubleLinearSystem add(final DoubleLinearSystem opponent, final boolean simplify) {
if (isProper() && opponent.isProper()) {
DoubleMatrix ansA = Diag.diag(this.a, ((DoubleAbstractLinearSystem)opponent).a);
DoubleMatrix ansB = this.b.appendDown(((DoubleAbstractLinearSystem)opponent).b);
DoubleMatrix ansC = this.c.appendRight(((DoubleAbstractLinearSystem)opponent).c);
DoubleMatrix ansD = this.d.add(((DoubleAbstractLinearSystem)opponent).d);
if (simplify) {
List<DoubleMatrix> abcd = Minreal.minreal(ansA, ansB, ansC, ansD);
ansA = abcd.get(0);
ansB = abcd.get(1);
ansC = abcd.get(2);
ansD = abcd.get(3);
}
return DoubleLinearSystemFactory.createLinearSystem(ansA, ansB, ansC, ansD);
}
DoubleRationalPolynomialMatrix ansG;
if (isProper()) {
ansG = getTransferFunctionMatrix(simplify).add(((DoubleAbstractLinearSystem)opponent).G);
} else if (opponent.isProper()) {
ansG = this.G.add(opponent.getTransferFunctionMatrix(simplify));
} else {
ansG = this.G.add(((DoubleAbstractLinearSystem)opponent).G);
}
if (simplify) {
ansG = Simplify.simplify(ansG);
}
return DoubleLinearSystemFactory.createLinearSystem(ansG);
}
/**
* 定数行列<code>constantMatrix</code>を右から掛けてできるシステムを返します。
*
* @param constantMatrix 定数行列
* @return 定数行列<code>constantMatrix</code>を右から掛けてできるシステム
*/
public DoubleLinearSystem multiply(final DoubleMatrix constantMatrix) {
if (isProper()) {
final DoubleMatrix ansB = this.b.multiply(constantMatrix);
final DoubleMatrix ansD = this.d.multiply(constantMatrix);
return DoubleLinearSystemFactory.createLinearSystem(this.a.createClone(), ansB, this.c.createClone(), ansD);
}
return DoubleLinearSystemFactory.createLinearSystem(this.G.multiply(new DoubleRationalPolynomialMatrix(constantMatrix)));
}
/**
* 定数行列<code>constantMatrix</code>を左から掛けてできるシステムを返します。
*
* @param constantMatrix 定数行列
* @return 定数行列<code>constantMatrix</code>を左から掛けてできるシステム
*/
public DoubleLinearSystem leftMultiply(final DoubleMatrix constantMatrix) {
if (isProper()) {
final DoubleMatrix ansC = constantMatrix.multiply(this.c);
final DoubleMatrix ansD = constantMatrix.multiply(this.d);
return DoubleLinearSystemFactory.createLinearSystem(this.a.createClone(), this.b.createClone(), ansC, ansD);
}
return DoubleLinearSystemFactory.createLinearSystem(new DoubleRationalPolynomialMatrix(constantMatrix).multiply(this.G));
}
/**
* システム<code>opponent</code>との積(直列結合)(右からの積)でできるシステムを返します。
*
* <p>結合システムを簡単化します。
*
* @param opponent 結合するシステム(入力側に掛けられるシステム)
* @return システム<code>opponent</code>との積(直列結合)(右からの積)でできるシステム
*/
public DoubleLinearSystem multiply(final DoubleLinearSystem opponent) {
return multiply(opponent, true);
}
/**
* システム<code>opponent</code>との積(直列結合)(右からの積)でできるシステムを返します。
*
* @param opponent 結合するシステム(入力側に掛けられるシステム)
* @param simplify 簡単化するならばtrue、そうでなければfalse
* @return システム<code>opponent</code>との積(直列結合)(右からの積)でできるシステム
*/
public DoubleLinearSystem multiply(final DoubleLinearSystem opponent, final boolean simplify) {
if (isProper() && opponent.isProper()) {
if (isSISO() && !opponent.isSISO()) {
final DoubleRationalPolynomialMatrix g1 = getTransferFunctionMatrix(simplify);
final DoubleRationalPolynomialMatrix g2 = opponent.getTransferFunctionMatrix(simplify);
DoubleRationalPolynomialMatrix ansG = g2.multiply(g1.getElement(1, 1));
if (simplify) {
ansG = Simplify.simplify(ansG);
}
return DoubleLinearSystemFactory.createLinearSystem(ansG);
}
if (!isSISO() && opponent.isSISO()) {
final DoubleRationalPolynomialMatrix g1 = getTransferFunctionMatrix(simplify);
final DoubleRationalPolynomialMatrix g2 = opponent.getTransferFunctionMatrix(simplify);
DoubleRationalPolynomialMatrix ansG = g1.multiply(g2.getElement(1, 1));
if (simplify) {
ansG = Simplify.simplify(ansG);
}
return DoubleLinearSystemFactory.createLinearSystem(ansG);
}
DoubleMatrix ansA = this.a.appendRight(this.b.multiply(((DoubleAbstractLinearSystem)opponent).c)).appendDown(
this.a.createZero(((DoubleAbstractLinearSystem)opponent).stateSize, this.stateSize).appendRight(((DoubleAbstractLinearSystem)opponent).a));
DoubleMatrix ansB = this.b.multiply(((DoubleAbstractLinearSystem)opponent).d).appendDown(((DoubleAbstractLinearSystem)opponent).b);
DoubleMatrix ansC = this.c.appendRight(this.d.multiply(((DoubleAbstractLinearSystem)opponent).c));
DoubleMatrix ansD = this.d.multiply(((DoubleAbstractLinearSystem)opponent).d);
if (simplify) {
List<DoubleMatrix> abcd = Minreal.minreal(ansA, ansB, ansC, ansD);
ansA = abcd.get(0);
ansB = abcd.get(1);
ansC = abcd.get(2);
ansD = abcd.get(3);
}
return DoubleLinearSystemFactory.createLinearSystem(ansA, ansB, ansC, ansD);
}
final DoubleRationalPolynomialMatrix g1, g2;
if (isProper()) {
g1 = getTransferFunctionMatrix(simplify);
g2 = ((DoubleAbstractLinearSystem)opponent).G;
} else if (opponent.isProper()) {
g1 = this.G;
g2 = opponent.getTransferFunctionMatrix(simplify);
} else {
g1 = this.G;
g2 = ((DoubleAbstractLinearSystem)opponent).G;
}
DoubleRationalPolynomialMatrix ansG;
if (isSISO()) {
ansG = g2.multiply(g1.getElement(1, 1));
} else if (opponent.isSISO()) {
ansG = g1.multiply(g2.getElement(1, 1));
} else {
ansG = g1.multiply(g2);
}
if (simplify) {
ansG = Simplify.simplify(ansG);
}
return DoubleLinearSystemFactory.createLinearSystem(ansG);
}
/**
* システム<code>opponent</code>との差(符合が異なる並列結合)でできるシステムを返します。
*
* <p>結合システムを簡単化します。
*
* @param opponent 結合するシステム(引かれるシステム)
* @return システム<code>opponent</code>との差(符合が異なる並列結合)でできるシステム
*/
public DoubleLinearSystem subtract(final DoubleLinearSystem opponent) {
return subtract(opponent, true);
}
/**
* システム<code>opponent</code>との差(符合が異なる並列結合)でできるシステムを返します。
*
* @param opponent 結合するシステム(引かれるシステム)
* @param simplify 簡単化するならばtrue、そうでなければfalse
* @return システム<code>opponent</code>との差(符合が異なる並列結合)でできるシステム
*/
public DoubleLinearSystem subtract(final DoubleLinearSystem opponent, final boolean simplify) {
if (isProper() && opponent.isProper()) {
DoubleMatrix ansA = Diag.diag(this.a, ((DoubleAbstractLinearSystem)opponent).a);
DoubleMatrix ansB = this.b.appendDown(((DoubleAbstractLinearSystem)opponent).b);
DoubleMatrix ansC = this.c.appendRight(((DoubleAbstractLinearSystem)opponent).c.unaryMinus());
DoubleMatrix ansD = this.d.add(((DoubleAbstractLinearSystem)opponent).d.unaryMinus());
if (simplify) {
final List<DoubleMatrix> abcd = Minreal.minreal(ansA, ansB, ansC, ansD);
ansA = abcd.get(0);
ansB = abcd.get(1);
ansC = abcd.get(2);
ansD = abcd.get(3);
}
return DoubleLinearSystemFactory.createLinearSystem(ansA, ansB, ansC, ansD);
}
DoubleRationalPolynomialMatrix ansG;
if (isProper()) {
ansG = getTransferFunctionMatrix(simplify).subtract(((DoubleAbstractLinearSystem)opponent).G);
} else if (opponent.isProper()) {
ansG = this.G.subtract(opponent.getTransferFunctionMatrix(simplify));
} else {
ansG = this.G.subtract(((DoubleAbstractLinearSystem)opponent).G);
}
if (simplify) {
ansG = Simplify.simplify(ansG);
}
return DoubleLinearSystemFactory.createLinearSystem(ansG);
}
/**
* 入力または出力の符合を反転にしてできるシステムを返します。
*
* @return 入力または出力の符合を反転にしてできるシステム
*/
public DoubleLinearSystem unaryMinus() {
if (isProper()) {
final DoubleMatrix ansA = this.a.createClone();
final DoubleMatrix ansB = this.b.unaryMinus();
final DoubleMatrix ansC = this.c.createClone();
final DoubleMatrix ansD = this.d.unaryMinus();
return DoubleLinearSystemFactory.createLinearSystem(ansA, ansB, ansC, ansD);
}
return DoubleLinearSystemFactory.createLinearSystem(this.G.unaryMinus());
}
/**
* 逆システム(入力と出力を逆にしたシステム)を返します。
*
* <p>生成されたシステムを簡単化します。
*
* @return 逆システム(入力と出力を逆にしたシステム)
*/
public DoubleLinearSystem inverse() {
return inverse(true);
}
/**
* 逆システム(入力と出力を逆にしたシステム)を返します。
*
* @param simplify 生成されたシステムを簡単化するならばtrue、そうでなければfalse
* @return 逆システム(入力と出力を逆にしたシステム)
*
*/
public DoubleLinearSystem inverse(final boolean simplify) {
if (isProper()) {
DoubleMatrix ansA = this.a.subtract(this.b.multiply(this.d.leftDivide(this.c)));
DoubleMatrix ansB = this.b.multiply(this.d.inverse());
DoubleMatrix ansC = this.d.leftDivide(this.c).unaryMinus();
DoubleMatrix ansD = this.d.inverse();
if (simplify) {
final List<DoubleMatrix> abcd = Minreal.minreal(ansA, ansB, ansC, ansD);
ansA = abcd.get(0);
ansB = abcd.get(1);
ansC = abcd.get(2);
ansD = abcd.get(3);
}
return DoubleLinearSystemFactory.createLinearSystem(ansA, ansB, ansC, ansD);
}
DoubleRationalPolynomialMatrix ansG = this.G.inverse();
if (simplify) {
ansG = Simplify.simplify(ansG);
}
return DoubleLinearSystemFactory.createLinearSystem(ansG);
}
/**
* 転置してできるシステムを返します。
*
* @return 転置してできるシステム
*/
public DoubleLinearSystem transpose() {
if (isProper()) {
final DoubleMatrix ansA = this.a.transpose();
final DoubleMatrix ansB = this.c.transpose();
final DoubleMatrix ansC = this.b.transpose();
final DoubleMatrix ansD = this.d.transpose();
return DoubleLinearSystemFactory.createLinearSystem(ansA, ansB, ansC, ansD);
}
return DoubleLinearSystemFactory.createLinearSystem(this.G.transpose());
}
/**
* 複素共役転置してできるシステムを返します。
*
* @return 複素共役転置してできるシステム
*/
public DoubleLinearSystem conjugateTranspose() {
if (isProper()) {
final DoubleMatrix ansA = this.a.conjugateTranspose();
final DoubleMatrix ansB = this.c.conjugateTranspose();
final DoubleMatrix ansC = this.b.conjugateTranspose();
final DoubleMatrix ansD = this.d.conjugateTranspose();
return DoubleLinearSystemFactory.createLinearSystem(ansA, ansB, ansC, ansD);
}
return DoubleLinearSystemFactory.createLinearSystem(this.G.conjugateTranspose());
}
/**
* システム<code>feedbackElement</code>をフィードバック結合(負帰還)してできるシステムを返します。
*
* <p>生成されるシステムを簡単化します。
*
* @param feedbackElement フィードバック結合するシステム
* @return システム<code>feedbackElement</code>をフィードバック結合(負帰還)してできるシステム
*
* <p>feedback-connected system
*/
public DoubleLinearSystem feedback(final DoubleLinearSystem feedbackElement) {
return feedback(feedbackElement, true, true);
}
/**
* システム<code>feedbackElement</code>をフィードバック結合してできるシステムを返します。
*
* <p>生成されるシステムを簡単化します。
*
* @param feedbackElement フィードバック要素
* @param negative ネガティブフィードバックならばtrue、そうでなければfalse
* @return システム<code>feedbackElement</code>をフィードバック結合(負帰還)してできるシステム
*/
public DoubleLinearSystem feedback(final DoubleLinearSystem feedbackElement, final boolean negative) {
return feedback(feedbackElement, negative, true);
}
/**
* システムfeedbackElementをフィードバック結合してできるシステムを返します。
*
* @param feedbackElement フィードバック要素
* @param negative ネガティブフィードバックならばtrue、そうでなければfalse
* @param simplify 生成されたシステムを簡単化するならばtrue、そうでなければfalse
* @return フィードバック結合してできるシステム
*/
public DoubleLinearSystem feedback(final DoubleLinearSystem feedbackElement, final boolean negative, final boolean simplify) {
if (isProper() && feedbackElement.isProper()) {
DoubleMatrix ansA, ansB, ansC, ansD;
if (negative) {
// T1 = I + D2*D1
// T2 = I + D1*D2
final DoubleMatrix T1 = this.d.createUnit(this.outputSize).add(((DoubleAbstractLinearSystem)feedbackElement).d.multiply(this.d));
final DoubleMatrix T2 = this.d.createUnit(this.outputSize).add(this.d.multiply(((DoubleAbstractLinearSystem)feedbackElement).d));
if (T1.isFullRank() == false) {
throw new RuntimeException(Messages.getString("LinearSystem.27")); //$NON-NLS-1$
}
if (T2.isFullRank() == false) {
throw new RuntimeException(Messages.getString("LinearSystem.28")); //$NON-NLS-1$
}
// A = [[A1-B1/T1*D2*C1 -B1/T1*C2 ]
// [ B2/T2*C1 A2-B2/T2*D1*C2]];
final DoubleMatrix a11 = this.a.subtract(this.b.divide(T1).multiply(((DoubleAbstractLinearSystem)feedbackElement).d).multiply(this.c));
final DoubleMatrix a12 = this.b.divide(T1).multiply(((DoubleAbstractLinearSystem)feedbackElement).c).unaryMinus();
final DoubleMatrix a21 = ((DoubleAbstractLinearSystem)feedbackElement).b.divide(T2).multiply(this.c);
final DoubleMatrix a22 = ((DoubleAbstractLinearSystem)feedbackElement).a
.subtract(((DoubleAbstractLinearSystem)feedbackElement).b.divide(T2).multiply(this.d).multiply(((DoubleAbstractLinearSystem)feedbackElement).c));
ansA = a11.appendRight(a12).appendDown(a21.appendRight(a22));
// B = [[ B1/T1 ]
// [B2/T2*D1]];
final DoubleMatrix b1 = this.b.divide(T1);
final DoubleMatrix b2 = ((DoubleAbstractLinearSystem)feedbackElement).b.divide(T2).multiply(this.d);
ansB = b1.appendDown(b2);
// [T2\C1, -T2\D1*C2];
ansC = T2.leftDivide(this.c).appendRight(T2.leftDivide(this.d).multiply(((DoubleAbstractLinearSystem)feedbackElement).c).unaryMinus());
// [T2\D1]
ansD = T2.leftDivide(this.d);
} else {
// T1 = I - D2*D1
// T2 = I - D1*D2
final DoubleMatrix T1 = this.d.createUnit(this.outputSize).subtract(((DoubleAbstractLinearSystem)feedbackElement).d.multiply(this.d));
final DoubleMatrix T2 = this.d.createUnit(this.outputSize).subtract(this.d.multiply(((DoubleAbstractLinearSystem)feedbackElement).d));
if (T1.isFullRank() == false) {
throw new RuntimeException(Messages.getString("LinearSystem.29")); //$NON-NLS-1$
}
if (T2.isFullRank() == false) {
throw new RuntimeException(Messages.getString("LinearSystem.30")); //$NON-NLS-1$
}
// A = [[A1+B1/T1*D2*C1 B1/T1*C2 ]
// [ B2/T2*C1 A2+B2/T2*D1*C2]];
final DoubleMatrix a11 = this.a.add(this.b.divide(T1).multiply(((DoubleAbstractLinearSystem)feedbackElement).d).multiply(this.c));
final DoubleMatrix a12 = this.b.divide(T1).multiply(((DoubleAbstractLinearSystem)feedbackElement).c);
final DoubleMatrix a21 = ((DoubleAbstractLinearSystem)feedbackElement).b.divide(T2).multiply(this.c);
final DoubleMatrix a22 = ((DoubleAbstractLinearSystem)feedbackElement).a.add(((DoubleAbstractLinearSystem)feedbackElement).b.divide(T2).multiply(this.d).multiply(((DoubleAbstractLinearSystem)feedbackElement).c));
ansA = a11.appendRight(a12).appendDown(a21.appendRight(a22));
// B = [[ B1/T1 ]
// [B2/T2*D1]];
final DoubleMatrix b1 = this.b.divide(T1);
final DoubleMatrix b2 = ((DoubleAbstractLinearSystem)feedbackElement).b.divide(T2).multiply(this.d);
ansB = b1.appendDown(b2);
// [T2\C1, T2\D1*C2];
ansC = T2.leftDivide(this.c).appendRight(T2.leftDivide(this.d).multiply(((DoubleAbstractLinearSystem)feedbackElement).c));
// [T2\D1]
ansD = T2.leftDivide(this.d);
}
if (simplify) {
final List<DoubleMatrix> abcd = Minreal.minreal(ansA, ansB, ansC, ansD);
ansA = abcd.get(0);
ansB = abcd.get(1);
ansC = abcd.get(2);
ansD = abcd.get(3);
}
return DoubleLinearSystemFactory.createLinearSystem(ansA, ansB, ansC, ansD);
}
final DoubleRationalPolynomialMatrix g1, g2;
if (isProper()) {
g1 = getTransferFunctionMatrix(simplify);
g2 = ((DoubleAbstractLinearSystem)feedbackElement).G;
} else if (feedbackElement.isProper()) {
g1 = this.G;
g2 = feedbackElement.getTransferFunctionMatrix(simplify);
} else {
g1 = this.G;
g2 = ((DoubleAbstractLinearSystem)feedbackElement).G;
}
final DoubleRationalPolynomialMatrix g1g2 = g1.multiply(g2);
DoubleRationalPolynomialMatrix ansG;
if (negative) {
ansG = g1g2.createUnit(g1g2.getRowSize()).add(g1g2).inverse().multiply(g1);
} else {
ansG = g1g2.createUnit(g1g2.getRowSize()).subtract(g1g2).inverse().multiply(g1);
}
if (simplify) {
ansG = Simplify.simplify(ansG);
}
return DoubleLinearSystemFactory.createLinearSystem(ansG);
}
/**
* 単一フィードバック(ネガティブフィードバック)してできるシステムを返します。
*
* <p>生成されるシステムを簡単化します。
*
* @return 単一フィードバック(ネガティブフィードバック)してできるシステム
*
* <p>unity feedback connected system
*/
public DoubleLinearSystem unityFeedback() {
return unityFeedback(true, true);
}
/**
* 単一フィードバックしてできるシステムを返します。
*
* <p>生成されるシステムを簡単化します。
*
* @param negative ネガティブフィードバックならばtrue、そうでなければfalse
*
* @return フィードバック結合してできるシステム
*/
public DoubleLinearSystem unityFeedback(final boolean negative) {
return unityFeedback(negative, true);
}
/**
* 単一フィードバックしてできるシステムを返します。
*
* @param negative ネガティブフィードバックならばtrue、そうでなければfalse
* @param simplify 生成されるシステムを簡単化するならばtrue、そうでなければfalse
* @return フィードバック結合してできるシステム
*/
public DoubleLinearSystem unityFeedback(final boolean negative, final boolean simplify) {
if (isProper()) {
DoubleMatrix ansA, ansB, ansC, ansD;
if (negative) {
final DoubleMatrix T = this.d.createUnit(this.d.getRowSize()).add(this.d);
if (T.isFullRank() == false) {
throw new RuntimeException(Messages.getString("LinearSystem.31")); //$NON-NLS-1$
}
ansA = this.a.subtract(this.b.divide(T).multiply(this.c));
ansB = this.b.multiply(T.inverse());
ansC = this.c.subtract(this.d.divide(T).multiply(this.c));
ansD = this.d.multiply(T.inverse());
} else {
final DoubleMatrix T = this.d.createUnit(this.d.getRowSize()).subtract(this.d);
if (T.isFullRank() == false) {
throw new RuntimeException(Messages.getString("LinearSystem.32")); //$NON-NLS-1$
}
ansA = this.a.add(this.b.divide(T).multiply(this.c));
ansB = this.b.multiply(T.inverse());
ansC = this.c.add(this.d.divide(T).multiply(this.c));
ansD = this.d.multiply(T.inverse());
}
if (simplify) {
final List<DoubleMatrix> abcd = Minreal.minreal(ansA, ansB, ansC, ansD);
ansA = abcd.get(0);
ansB = abcd.get(1);
ansC = abcd.get(2);
ansD = abcd.get(3);
}
return DoubleLinearSystemFactory.createLinearSystem(ansA, ansB, ansC, ansD);
}
DoubleRationalPolynomialMatrix ansG;
if (negative) {
ansG = this.G.createUnit(this.G.getRowSize()).add(this.G).inverse().multiply(this.G);
} else {
ansG = this.G.createUnit(this.G.getRowSize()).subtract(this.G).inverse().multiply(this.G);
}
if (simplify) {
ansG = Simplify.simplify(ansG);
}
return DoubleLinearSystemFactory.createLinearSystem(ansG);
}
/**
* システム<code>opponent</code>を行方向に結合した(出力を加算する)システムを返します。
*
* <p>生成されるシステムを簡単化します。
*
* @param opponent 結合するシステム
* @return システム<code>opponent</code>を行方向に結合した(出力を加算する)システム
*
* <p>row-wise connected system
*/
public DoubleLinearSystem appendRight(final DoubleLinearSystem opponent) {
return appendRight(opponent, true);
}
/**
* システム<code>opponent</code>を行方向に結合した(出力を加算する)システムを返します。
*
* @param opponent 結合するシステム
* @param simplify 生成されるシステムを簡単化するならばtrue、そうでなければfalse
* @return システム<code>opponent</code>を行方向に結合した(出力を加算する)システム
*
* <p>row-wise connected system
*/
public DoubleLinearSystem appendRight(final DoubleLinearSystem opponent, final boolean simplify) {
if (isProper() && opponent.isProper()) {
DoubleMatrix ansA = Diag.diag(this.a, ((DoubleAbstractLinearSystem)opponent).a);
DoubleMatrix ansB = Diag.diag(this.b, ((DoubleAbstractLinearSystem)opponent).b);
DoubleMatrix ansC = this.c.appendRight(((DoubleAbstractLinearSystem)opponent).c);
DoubleMatrix ansD = this.d.appendRight(((DoubleAbstractLinearSystem)opponent).d);
if (simplify) {
final List<DoubleMatrix> abcd = Minreal.minreal(ansA, ansB, ansC, ansD);
ansA = abcd.get(0);
ansB = abcd.get(1);
ansC = abcd.get(2);
ansD = abcd.get(3);
}
return DoubleLinearSystemFactory.createLinearSystem(ansA, ansB, ansC, ansD);
}
DoubleRationalPolynomialMatrix ansG;
if (this.isProper()) {
ansG = getTransferFunctionMatrix(simplify).appendRight(((DoubleAbstractLinearSystem)opponent).G);
} else if (opponent.isProper()) {
ansG = this.G.appendRight(opponent.getTransferFunctionMatrix(simplify));
} else {
ansG = this.G.appendRight(((DoubleAbstractLinearSystem)opponent).G);
}
return DoubleLinearSystemFactory.createLinearSystem(ansG);
}
/**
* システム<code>opponent</code>を列方向に結合した(同一の入力を加える)システムを返します。
*
* <p>生成されるシステムを簡単化します。
*
* @param opponent 結合するシステム
* @return システム<code>opponent</code>を列方向に結合した(同一の入力を加える)システム
*
* <p>column-wise connected system
*/
public DoubleLinearSystem appendDown(final DoubleLinearSystem opponent) {
return appendDown(opponent, true);
}
/**
* システム<code>opponent</code>を列方向に結合した(同一の入力を加える)システムを返します。
*
* @param opponent 結合するシステム
* @param simplify 生成されるシステムを簡単化するならばtrue、そうでなければfalse
* @return システム<code>opponent</code>を列方向に結合した(同一の入力を加える)システム
*
* <p>column-wise connected system
*/
public DoubleLinearSystem appendDown(final DoubleLinearSystem opponent, final boolean simplify) {
if (isProper() && opponent.isProper()) {
DoubleMatrix ansA = Diag.diag(this.a, ((DoubleAbstractLinearSystem)opponent).a);
DoubleMatrix ansB = this.b.appendDown(((DoubleAbstractLinearSystem)opponent).b);
DoubleMatrix ansC = Diag.diag(this.c, ((DoubleAbstractLinearSystem)opponent).c);
DoubleMatrix ansD = this.d.appendDown(((DoubleAbstractLinearSystem)opponent).d);
if (simplify) {
final List<DoubleMatrix> abcd = Minreal.minreal(ansA, ansB, ansC, ansD);
ansA = abcd.get(0);
ansB = abcd.get(1);
ansC = abcd.get(2);
ansD = abcd.get(3);
}
return DoubleLinearSystemFactory.createLinearSystem(ansA, ansB, ansC, ansD);
}
final DoubleRationalPolynomialMatrix ansG;
if (this.isProper()) {
ansG = getTransferFunctionMatrix(simplify).appendDown(((DoubleAbstractLinearSystem)opponent).G);
} else if (opponent.isProper()) {
ansG = this.G.appendDown(opponent.getTransferFunctionMatrix(simplify));
} else {
ansG = this.G.appendDown(((DoubleAbstractLinearSystem)opponent).G);
}
return DoubleLinearSystemFactory.createLinearSystem(ansG);
}
/**
* 最小実現したシステムを返します。
*
* @return 最小実現したシステム
*
* <p>minimal realization
*/
public DoubleLinearSystem simplify() {
return simplify(-1);
}
/**
* 最小実現したシステムを返します。
*
* @param tolerance 許容誤差
* @return 最小実現したシステム
*
* <p>minimal realization
*/
public DoubleLinearSystem simplify(double tolerance) {
return simplify(new DoubleNumber(tolerance));
}
/**
* 最小実現したシステムを返します。
*
* @param tolerance 許容誤差
* @return 最小実現したシステム
*
* <p>minimal realization
*/
public DoubleLinearSystem simplify(DoubleNumber tolerance) {
if (isProper()) {
final List<DoubleMatrix> abcd = Minreal.minreal(this.a, this.b, this.c, this.d, tolerance);
DoubleMatrix ansA = abcd.get(0);
DoubleMatrix ansB = abcd.get(1);
DoubleMatrix ansC = abcd.get(2);
DoubleMatrix ansD = abcd.get(3);
return DoubleLinearSystemFactory.createLinearSystem(ansA, ansB, ansC, ansD);
}
if (this.G == null) {
this.G = getTransferFunctionMatrix(true, tolerance.doubleValue());
}
return this;
//final DoubleRationalPolynomialMatrix ansG = Simplify.simplify(this.G);
//return DoubleLinearSystemFactory.createLinearSystem(ansG);
}
/**
* 時間領域でのシステムの種類を設定します。
*
* @param type 時間領域でのシステムの種類
*/
public void setTimeDomainType(final TimeDomainType type) {
this.timeDomainType = type;
}
/**
* 時間領域でのシステムの種類を返します。
*
* @return 時間領域でのシステムの種類
*/
public TimeDomainType getTimeDomainType() {
return this.timeDomainType;
}
/**
* 連続時間システムであるか判定します。
*
* @return 連続時間システムならばtrue、そうでなければfalse
*/
public boolean isContinuous() {
return this.timeDomainType == TimeDomainType.CONTINUOUS;
}
/**
* 離散時間システムであるか判定します。
*
* @return 離散時間システムならばtrue、そうでなければfalse
*/
public boolean isDiscrete() {
return this.timeDomainType == TimeDomainType.DISCRETE;
}
/**
* サンプル値システムであるか判定します。
*
* @return サンプル値システムならばtrue、そうでなければfalse
*/
public boolean isSampled() {
return this.timeDomainType == TimeDomainType.SAMPLED;
}
/**
* 数値の出力フォーマットを設定します。
*
* @param format 数値の出力フォーマット
*/
public void setFormat(final String format) {
this.a.setElementFormat(format);
this.b.setElementFormat(format);
this.c.setElementFormat(format);
this.d.setElementFormat(format);
if (this.e != null) {
this.e.setElementFormat(format);
}
if (this.G != null) {
this.G.setElementFormat(format);
}
}
/**
* 数値の出力フォーマットを返します。
*
* @return 数値の出力フォーマット
*/
public String getFormat() {
return this.a.getElementFormat();
}
/**
* 状態空間実現の係数行列の数式を設定します。
*
* @param aSymbol A行列の数式
* @param bSymbol B行列の数式
* @param cSymbol C行列の数式
* @param dSymbol D行列の数式
* @param eSymbol E行列の数式
*/
public void setSymbolicString(final String[][] aSymbol, final String[][] bSymbol, final String[][] cSymbol, final String[][] dSymbol, final String[][] eSymbol) {
this.aSymbol = aSymbol;
this.bSymbol = bSymbol;
this.cSymbol = cSymbol;
this.dSymbol = dSymbol;
this.eSymbol = eSymbol;
}
/**
* サブシステムの数を返します。
*
* @return サブシステムの数
*/
protected int getSubSystemSize() {
return this.aSymbol.length;
}
/**
* 入力ポートの数を返します。
*
* @return 入力ポートの数
*/
protected int getInputPortSize() {
return this.bSymbol.length != 0 ? this.bSymbol[0].length : this.dSymbol[0].length;
}
/**
* 出力ポートの数を返します。
*
* @return 出力ポートの数
*/
protected int getOutputPortSize() {
return this.cSymbol.length;
}
/**
* 入力ポートのタグを返します。
*
* @return 入力ポートのタグ
*/
public List<String> getInputPortTags() {
return this.inputPortTags;
}
/**
* 入力ポートのタグを設定します。
*
* @param inputPortTags 入力ポートのタグ
*/
public void setInputPortTags(List<String> inputPortTags) {
this.inputPortTags = inputPortTags;
}
/**
* 出力ポートのタグを返します。
*
* @return 出力ポートのタグ
*/
public List<String> getOutputPortTags() {
return this.outputPortTags;
}
/**
* 出力ポートのタグを設定します。
*
* @param outputPortTags 出力ポートのタグ
*/
public void setOutputTags(List<String> outputPortTags) {
this.outputPortTags = outputPortTags;
}
/**
* 状態のタグを返します。
*
* @return 状態のタグ
*/
public List<String> getStateTags() {
return this.stateTags;
}
/**
* 状態のタグを設定します。
*
* @param stateTags 状態のタグ
*/
public void setStateTags(List<String> stateTags) {
this.stateTags = stateTags;
}
/**
* A行列の文字列をString[][]で返します。 (テストケースのための一時的なものです。)
*
* @return String[][](aSymbol)
*/
protected String[][] getSymbolicAMatrix() {
return this.aSymbol;
}
/**
* B行列の文字列をString[][]で返します。 (テストケースのための一時的なものです。)
*
* @return String[][](bSymbol)
*/
protected String[][] getSymbolicBMatrix() {
return this.bSymbol;
}
/**
* C行列の文字列をString[][]で返します。 (テストケースのための一時的なものです。)
*
* @return String[][](cSymbol)
*/
protected String[][] getSymbolicCMatrix() {
return this.cSymbol;
}
/**
* D行列の文字列をString[][]で返します。 (テストケースのための一時的なものです。)
*
* @return String[][](dSymbol)
*/
protected String[][] getSymbolicDMatrix() {
return this.dSymbol;
}
/**
* eSymbolを返します.(一時的実装)
*
* @return eSymbol
*/
protected String[][] getSymbolicEMatrix() {
return this.eSymbol;
}
/**
* @see org.mklab.nfc.matrix.GridElement#clone()
*/
@Override
abstract public Object clone();
/**
* 表示文字列を返します。
*
* @return 表示文字列
*/
public String getPrintingString() {
try (final CharArrayWriter output = new CharArrayWriter()) {
print(output);
final String printString = output.toString();
return printString;
}
}
/**
* 指数を返します。
* @return 指数
*/
public IntMatrix getIndex() {
return this.index;
}
/**
* 指数を設定します。
* @param index 指数
*/
public void setIndex(IntMatrix index) {
this.index = index;
}
}