DoubleContinuousLinearDynamicSystem.java

/*
 * $Id$
 *
 * Copyright (C) 2004 Koga Laboratory. All rights reserved.
 *
 */

package org.mklab.tool.control.system.continuous;

import org.mklab.nfc.matrix.DoubleMatrix;
import org.mklab.tool.control.DoubleImproperLinearSystem;
import org.mklab.tool.control.DoubleLinearSystem;
import org.mklab.tool.control.DoubleLinearSystemFactory;
import org.mklab.tool.control.DoubleProperLinearSystem;
import org.mklab.tool.control.system.DoubleLinearSystemOperator;


/**
 * 連続時間線形動的システムを表すクラスです。
 * 
 * @author Koga Laboratory
 * @version $Revision$, 2004/11/24
 */
public class DoubleContinuousLinearDynamicSystem extends DoubleBaseContinuousExplicitDynamicSystem implements DoubleLinearSystemOperator {

  /** システム */
  private DoubleLinearSystem sys;

  /** 識別するためのタグ */
  private String tag;

  /** Aを変数として扱うならばtrue */
  private boolean hasVariableA = true;
  /** Bを変数として扱うならばtrue */
  private boolean hasVariableB = true;
  /** Cを変数として扱うならばtrue */
  private boolean hasVariableC = true;
  /** Dを変数として扱うならばtrue */
  private boolean hasVariableD = true;
  /** Eを変数として扱うならばtrue */
  private boolean hasVariableE = true;

  /**
   * 伝達関数から作成されたならばtrue <p>数式伝達関数や最小要素数式のために,伝達関数表現の最小数式にするか定数行列の最小数式にするかを判断する一時的な手段です</p>
   */
  private boolean isTransferFunction = false;

  /**
   * 新しく生成された<code>ContinuousLinearDynamicSystem</code>オブジェクトを初期化します。
   */
  public DoubleContinuousLinearDynamicSystem() {
    super(-1, -1, 0);
    setLinear(true);
    setHasJacobianMatrix(true);
    this.tag = "" + hashCode(); //$NON-NLS-1$
  }

  /**
   * 新しく生成された<code>ContinuousLinearDynamicSystem</code>オブジェクトを初期化します。
   * 
   * @param sys 線形システム
   */
  public DoubleContinuousLinearDynamicSystem(final DoubleLinearSystem sys) {
    super(sys.getInputSize(), sys.getOutputSize(), sys.getStateSize());
    this.sys = sys;
    final DoubleMatrix D = sys.getD();

    if (D == null || D.isEmpty() || D.isZero()) {
      setHasDirectFeedthrough(false);
    }
    
    final DoubleMatrix E = sys.getE();
    
    if (E == null || E.isEmpty() || E.isUnit()) {
      setHasVariableE(false);
    }
    
    setIndex(sys.getIndex());

    setLinear(true);
    setHasJacobianMatrix(true);
    
    this.tag = "" + hashCode(); //$NON-NLS-1$
  }

  /**
   * 新しく生成された<code>ContinuousLinearDynamicSystem</code>オブジェクトを初期化します。
   * 
   * @param A システム行列
   * @param B 入力行列
   * @param C 出力行列
   * @param D ゲイン行列
   */
  public DoubleContinuousLinearDynamicSystem(final DoubleMatrix A, final DoubleMatrix B, final DoubleMatrix C, final DoubleMatrix D) {
    this(DoubleLinearSystemFactory.createLinearSystem(A, B, C, D));
  }
  
  /**
   * 新しく生成された<code>ContinuousLinearDynamicSystem</code>オブジェクトを初期化します。
   * 
   * @param A システム行列
   * @param B 入力行列
   * @param C 出力行列
   * @param D ゲイン行列
   * @param E ディスクリプタ行列
   */
  public DoubleContinuousLinearDynamicSystem(final DoubleMatrix A, final DoubleMatrix B, final DoubleMatrix C, final DoubleMatrix D, final DoubleMatrix E) {
    this(DoubleLinearSystemFactory.createLinearSystem(A, B, C, D, E));
  }

  /**
   * 新しく生成された<code>ContinuousLinearDynamicSystem</code>オブジェクトを初期化します。
   * 
   * <p>Dは、零行列です。
   * 
   * @param A システム行列
   * @param B 入力行列
   * @param C 出力行列
   */
  public DoubleContinuousLinearDynamicSystem(final DoubleMatrix A, final DoubleMatrix B, final DoubleMatrix C) {
    this(A, B, C, new DoubleMatrix(C.getRowSize(), B.getColumnSize()));
    setHasDirectFeedthrough(false);
    setForcedSystem(true);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleMatrix stateEquation( final double t, final DoubleMatrix x, final DoubleMatrix u) {
    final DoubleMatrix a = this.sys.getA();
    final DoubleMatrix b = this.sys.getB();
    return a.multiply(x).add(b.multiply(u));
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public DoubleMatrix outputEquation( final double t, final DoubleMatrix x, final DoubleMatrix u) {
    if (!hasDirectFeedthrough()) {
      throw new RuntimeException(Messages.getString("ContinuousLinearDynamicSystem.0")); //$NON-NLS-1$
    }
    final DoubleMatrix c = this.sys.getC();
    final DoubleMatrix d = this.sys.getD();
    return c.multiply(x).add(d.multiply(u));
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public DoubleMatrix outputEquation( final double t, final DoubleMatrix x) {
    if (hasDirectFeedthrough()) {
      throw new RuntimeException(Messages.getString("ContinuousLinearDynamicSystem.1")); //$NON-NLS-1$
    }
    final DoubleMatrix c = this.sys.getC();
    return c.multiply(x);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public DoubleLinearSystem getLinearSystem() {
    return this.sys;
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#setLinearSystem(org.mklab.tool.control.LinearSystem)
   */
  public void setLinearSystem(final DoubleLinearSystem system) {
    this.sys = system;
    if (system.isStrictlyProper()) {
      setHasDirectFeedthrough(false);
    } else {
      setHasDirectFeedthrough(true);
    }

    setStateSize(this.sys.getStateSize());
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#hasVariableA()
   */
  public boolean hasVariableA() {
    return this.hasVariableA;
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#hasVariableB()
   */
  public boolean hasVariableB() {
    return this.hasVariableB;
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#hasVariableC()
   */
  public boolean hasVariableC() {
    return this.hasVariableC;
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#hasVariableD()
   */
  public boolean hasVariableD() {
    return this.hasVariableD;
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#hasVariableE()
   */
  public boolean hasVariableE() {
    return this.hasVariableE;
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#setHasVariableA(boolean)
   */
  public void setHasVariableA(final boolean hasVariableA) {
    this.hasVariableA = hasVariableA;
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#setHasVariableB(boolean)
   */
  public void setHasVariableB(final boolean hasVariableB) {
    this.hasVariableB = hasVariableB;
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#setHasVariableC(boolean)
   */
  public void setHasVariableC(final boolean hasVariableC) {
    this.hasVariableC = hasVariableC;
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#setHasVariableD(boolean)
   */
  public void setHasVariableD(final boolean hasVariableD) {
    this.hasVariableD = hasVariableD;
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#setHasVariableE(boolean)
   */
  public void setHasVariableE(final boolean hasVariableE) {
    this.hasVariableE = hasVariableE;
    setDifferentialAlgebraicSystem(this.hasVariableE);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#getA()
   */
  public DoubleMatrix getA() {
    return this.sys.getA();
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#getB()
   */
  public DoubleMatrix getB() {
    return this.sys.getB();
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#getC()
   */
  public DoubleMatrix getC() {
    return this.sys.getC();
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#getD()
   */
  public DoubleMatrix getD() {
    return this.sys.getD();
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#getE()
   */
  public DoubleMatrix getE() {
    return this.sys.getE();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public DoubleMatrix getMatrixM() {
    if (this.hasVariableE) {
      return this.sys.getE();
    }
    return super.getMatrixM();
  }
  
  /**
   * {@inheritDoc}
   */
  
  @Override
  public DoubleMatrix getJacobianMatrix(double t, DoubleMatrix x, DoubleMatrix u) {
    return this.sys.getA();
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#add(org.mklab.tool.control.system.LinearSystemOperator)
   */
  public DoubleContinuousLinearDynamicSystem add(final DoubleLinearSystemOperator opponent) {
    return add(opponent, true);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#add(org.mklab.tool.control.system.LinearSystemOperator, boolean)
   */
  public DoubleContinuousLinearDynamicSystem add(final DoubleLinearSystemOperator opponent, final boolean simplify) {
    if (!(opponent instanceof DoubleContinuousLinearDynamicSystem)) {
      throw new RuntimeException(Messages.getString("ContinuousLinearDynamicSystem.2")); //$NON-NLS-1$
    }
    return new DoubleContinuousLinearDynamicSystem(this.sys.add(opponent.getLinearSystem(), simplify));
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#subtract(org.mklab.tool.control.system.LinearSystemOperator)
   */
  public DoubleContinuousLinearDynamicSystem subtract(final DoubleLinearSystemOperator opponent) {
    return subtract(opponent, true);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#subtract(org.mklab.tool.control.system.LinearSystemOperator, boolean)
   */
  public DoubleContinuousLinearDynamicSystem subtract(final DoubleLinearSystemOperator opponent, final boolean simplify) {
    if (!(opponent instanceof DoubleContinuousLinearDynamicSystem)) {
      throw new RuntimeException(Messages.getString("ContinuousLinearDynamicSystem.3")); //$NON-NLS-1$
    }
    return new DoubleContinuousLinearDynamicSystem(this.sys.subtract(opponent.getLinearSystem(), simplify));
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#multiply(org.mklab.tool.control.system.LinearSystemOperator)
   */
  public DoubleContinuousLinearDynamicSystem multiply(final DoubleLinearSystemOperator opponent) {
    return multiply(opponent, true);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#multiply(org.mklab.tool.control.system.LinearSystemOperator, boolean)
   */
  public DoubleContinuousLinearDynamicSystem multiply(final DoubleLinearSystemOperator opponent, final boolean simplify) {
    return new DoubleContinuousLinearDynamicSystem(this.sys.multiply(opponent.getLinearSystem(), simplify));
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#feedback(org.mklab.tool.control.system.LinearSystemOperator)
   */
  public DoubleContinuousLinearDynamicSystem feedback(final DoubleLinearSystemOperator feedbackElement) {
    return feedback(feedbackElement, true, true);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#feedback(org.mklab.tool.control.system.LinearSystemOperator, boolean)
   */
  public DoubleContinuousLinearDynamicSystem feedback(final DoubleLinearSystemOperator feedbackElement, final boolean negative) {
    return feedback(feedbackElement, negative, true);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#feedback(org.mklab.tool.control.system.LinearSystemOperator, boolean, boolean)
   */
  public DoubleContinuousLinearDynamicSystem feedback(final DoubleLinearSystemOperator feedbackElement, final boolean negative, final boolean simplify) {
    if (!(feedbackElement instanceof DoubleContinuousLinearDynamicSystem)) {
      throw new RuntimeException(Messages.getString("ContinuousLinearDynamicSystem.4")); //$NON-NLS-1$
    }
    return new DoubleContinuousLinearDynamicSystem(this.sys.feedback(feedbackElement.getLinearSystem(), negative, simplify));
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#unaryMinus()
   */
  public DoubleContinuousLinearDynamicSystem unaryMinus() {
    return new DoubleContinuousLinearDynamicSystem(this.sys.unaryMinus());
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#unityFeedback()
   */
  public DoubleContinuousLinearDynamicSystem unityFeedback() {
    return unityFeedback(true, true);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#unityFeedback(boolean)
   */
  public DoubleContinuousLinearDynamicSystem unityFeedback(final boolean negative) {
    return unityFeedback(negative, true);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#unityFeedback(boolean, boolean)
   */
  public DoubleContinuousLinearDynamicSystem unityFeedback(final boolean negative, final boolean simplify) {
    return new DoubleContinuousLinearDynamicSystem(this.sys.unityFeedback(negative, simplify));
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#getTag()
   */
  public String getTag() {
    return this.tag;
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#setTag(java.lang.String)
   */
  public void setTag(final String tag) {
    this.tag = tag;
  }

  /**
   * @see org.mklab.tool.control.system.continuous.BaseContinuousExplicitDynamicSystem#equals(java.lang.Object)
   */
  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (!super.equals(o)) {
      return false;
    }
    if (o == null) {
      return false;
    }
    if (o.getClass() != getClass()) {
      return false;
    }
    DoubleContinuousLinearDynamicSystem castedObj = (DoubleContinuousLinearDynamicSystem)o;
    return ((this.sys == null ? castedObj.sys == null : this.sys.equals(castedObj.sys)));
  }

  /**
   * @see org.mklab.tool.control.system.continuous.BaseContinuousExplicitDynamicSystem#hashCode()
   */
  @Override
  public int hashCode() {
    int hashCode = super.hashCode();
    hashCode = 31 * hashCode + (this.sys == null ? 0 : this.sys.hashCode());
    hashCode = 31 * hashCode + (this.tag == null ? 0 : this.tag.hashCode());
    return hashCode;
  }

  /**
   * @see org.mklab.tool.control.system.continuous.BaseContinuousExplicitDynamicSystem#clone()
   */
  @Override
  public DoubleContinuousLinearDynamicSystem clone() {
    DoubleContinuousLinearDynamicSystem inst = (DoubleContinuousLinearDynamicSystem)super.clone();
    //    inst.sys = this.sys == null ? null : (LinearSystem)this.sys.clone();

    if (this.sys instanceof DoubleImproperLinearSystem) {
      inst.sys = this.sys == null ? null : (DoubleImproperLinearSystem)this.sys.clone();
    } else {
      inst.sys = this.sys == null ? null : (DoubleProperLinearSystem)this.sys.clone();
    }
    inst.tag = this.tag;
    return inst;
  }

  /**
   * 伝達関数から作成されたかどうかを設定します. <p>数式伝達関数や最小要素数式のために,伝達関数表現の最小数式にするか定数行列の最小数式にするかを判断する一時的な手段です</p>
   * 
   * @param isTransferFunction 伝達関数から作成されたならばtrue,そうでなければfalse
   */
  public void setTransferFunction(final boolean isTransferFunction) {
    this.isTransferFunction = isTransferFunction;
  }

  /**
   * 伝達関数から作成されたかどうかを返します. <p>数式伝達関数や最小要素数式のために,伝達関数表現の最小数式にするか定数行列の最小数式にするかを判断する一時的な手段です</p>
   * 
   * @return 伝達関数から作成されたならばtrue,そうでなければfalse
   */
  public boolean isTransferFuntion() {
    return this.isTransferFunction;
  }

  //  /**
  //   * @see org.mklab.tool.control.system.continuous.BaseContinuousDynamicSystem#equals(java.lang.Object)
  //   */
  //  @Override
  //  public boolean equals(Object o) {
  //    if (this == o) {
  //      return true;
  //    }
  //    if (!super.equals(o)) {
  //      return false;
  //    }
  //    if (o == null) {
  //      return false;
  //    }
  //    if (o.getClass() != getClass()) {
  //      return false;
  //    }
  //    ContinuousLinearDynamicSystem castedObj = (ContinuousLinearDynamicSystem) o;
  //    return ((this.sys == null ? castedObj.sys == null : this.sys.equals(castedObj.sys)));
  //  }
  //
  //  /**
  //   * @see org.mklab.tool.control.system.continuous.BaseContinuousDynamicSystem#hashCode()
  //   */
  //  @Override
  //  public int hashCode() {
  //    int hashCode = super.hashCode();
  //    hashCode = 31 * hashCode + (this.sys == null ? 0 : this.sys.hashCode());
  //    return hashCode;
  //  }
}