ContinuousLinearDynamicSystem.java

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

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

import org.mklab.nfc.matrix.ComplexNumericalMatrix;
import org.mklab.nfc.matrix.RealNumericalMatrix;
import org.mklab.nfc.scalar.ComplexNumericalScalar;
import org.mklab.nfc.scalar.RealNumericalScalar;
import org.mklab.tool.control.ImproperLinearSystem;
import org.mklab.tool.control.LinearSystem;
import org.mklab.tool.control.LinearSystemFactory;
import org.mklab.tool.control.ProperLinearSystem;
import org.mklab.tool.control.system.LinearSystemOperator;


/**
 * 連続時間線形動的システムを表すクラスです。
 * 
 * @author Koga Laboratory
 * @version $Revision$, 2004/11/24
 * @param <RS> type of real scalar
 * @param <RM> type of real matrix
 * @param <CS> type of complex scalar
 * @param <CM> type of complex matrix
 */
public class ContinuousLinearDynamicSystem<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 BaseContinuousExplicitDynamicSystem<RS,RM,CS,CM> implements LinearSystemOperator<RS,RM,CS,CM> {

  /** システム */
  private LinearSystem<RS,RM,CS,CM> 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>オブジェクトを初期化します。
   * @param sunit unit of scalar
   */
  public ContinuousLinearDynamicSystem(RS sunit) {
    super(-1, -1, 0, sunit);
    setLinear(true);
    setHasJacobianMatrix(true);
    this.tag = "" + hashCode(); //$NON-NLS-1$
  }

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

    if (D == null || D.isEmpty() || D.isZero()) {
      setHasDirectFeedthrough(false);
    }
    
    final RM 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 ゲイン行列
   * @param sunit unit of scalar
   */
  public ContinuousLinearDynamicSystem(final RM A, final RM B, final RM C, final RM D, RS sunit) {
    this(LinearSystemFactory.createLinearSystem(A, B, C, D), sunit);
  }
  
  /**
   * 新しく生成された<code>ContinuousLinearDynamicSystem</code>オブジェクトを初期化します。
   * 
   * @param A システム行列
   * @param B 入力行列
   * @param C 出力行列
   * @param D ゲイン行列
   * @param E ディスクリプタ行列
   * @param sunit unit of scalar
   */
  public ContinuousLinearDynamicSystem(final RM A, final RM B, final RM C, final RM D, final RM E, RS sunit) {
    this(LinearSystemFactory.createLinearSystem(A, B, C, D, E), sunit);
  }

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

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

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

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

  /**
   * @see org.mklab.tool.control.system.SystemOperator#getLinearSystem()
   */
  @Override
  public LinearSystem<RS,RM,CS,CM> getLinearSystem() {
    return this.sys;
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#setLinearSystem(org.mklab.tool.control.LinearSystem)
   */
  public void setLinearSystem(final LinearSystem<RS,RM,CS,CM> 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 RM getA() {
    return this.sys.getA();
  }

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

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

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

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

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

  /**
   * {@inheritDoc}
   */
  public ContinuousLinearDynamicSystem<RS,RM,CS,CM> add(final LinearSystemOperator<RS,RM,CS,CM> opponent) {
    return add(opponent, true);
  }

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

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#subtract(org.mklab.tool.control.system.LinearSystemOperator)
   */
  public ContinuousLinearDynamicSystem<RS,RM,CS,CM> subtract(final LinearSystemOperator<RS,RM,CS,CM> opponent) {
    return subtract(opponent, true);
  }

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

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#multiply(org.mklab.tool.control.system.LinearSystemOperator)
   */
  public ContinuousLinearDynamicSystem<RS,RM,CS,CM> multiply(final LinearSystemOperator<RS,RM,CS,CM> opponent) {
    return multiply(opponent, true);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#multiply(org.mklab.tool.control.system.LinearSystemOperator, boolean)
   */
  public ContinuousLinearDynamicSystem<RS,RM,CS,CM> multiply(final LinearSystemOperator<RS,RM,CS,CM> opponent, final boolean simplify) {
    return new ContinuousLinearDynamicSystem<>(this.sys.multiply(opponent.getLinearSystem(), simplify), this.sunit);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#feedback(org.mklab.tool.control.system.LinearSystemOperator)
   */
  public ContinuousLinearDynamicSystem<RS,RM,CS,CM> feedback(final LinearSystemOperator<RS,RM,CS,CM> feedbackElement) {
    return feedback(feedbackElement, true, true);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#feedback(org.mklab.tool.control.system.LinearSystemOperator, boolean)
   */
  public ContinuousLinearDynamicSystem<RS,RM,CS,CM> feedback(final LinearSystemOperator<RS,RM,CS,CM> 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 ContinuousLinearDynamicSystem<RS,RM,CS,CM> feedback(final LinearSystemOperator<RS,RM,CS,CM> feedbackElement, final boolean negative, final boolean simplify) {
    if (!(feedbackElement instanceof ContinuousLinearDynamicSystem)) {
      throw new RuntimeException(Messages.getString("ContinuousLinearDynamicSystem.4")); //$NON-NLS-1$
    }
    return new ContinuousLinearDynamicSystem<>(this.sys.feedback(feedbackElement.getLinearSystem(), negative, simplify), this.sunit);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#unaryMinus()
   */
  public ContinuousLinearDynamicSystem<RS,RM,CS,CM> unaryMinus() {
    return new ContinuousLinearDynamicSystem<>(this.sys.unaryMinus(), this.sunit);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#unityFeedback()
   */
  public ContinuousLinearDynamicSystem<RS,RM,CS,CM> unityFeedback() {
    return unityFeedback(true, true);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#unityFeedback(boolean)
   */
  public ContinuousLinearDynamicSystem<RS,RM,CS,CM> unityFeedback(final boolean negative) {
    return unityFeedback(negative, true);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#unityFeedback(boolean, boolean)
   */
  public ContinuousLinearDynamicSystem<RS,RM,CS,CM> unityFeedback(final boolean negative, final boolean simplify) {
    return new ContinuousLinearDynamicSystem<>(this.sys.unityFeedback(negative, simplify), this.sunit);
  }

  /**
   * @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;
    }
    ContinuousLinearDynamicSystem<RS,RM,CS,CM> castedObj = (ContinuousLinearDynamicSystem<RS,RM,CS,CM>)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 ContinuousLinearDynamicSystem<RS,RM,CS,CM> clone() {
    ContinuousLinearDynamicSystem<RS,RM,CS,CM> inst = (ContinuousLinearDynamicSystem<RS,RM,CS,CM>)super.clone();
    //    inst.sys = this.sys == null ? null : (LinearSystem)this.sys.clone();

    if (this.sys instanceof ImproperLinearSystem) {
      inst.sys = this.sys == null ? null : (ImproperLinearSystem<RS,RM,CS,CM>)this.sys.clone();
    } else {
      inst.sys = this.sys == null ? null : (ProperLinearSystem<RS,RM,CS,CM>)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;
  //  }
}