ConstantSystem.java

/*
 * $Id: ConstantSystem.java,v 1.41 2008/07/16 03:51:37 koga Exp $
 *
 * Copyright (C) 2004 Koga Laboratory. All rights reserved.
 *
 */

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.mklab.nfc.matrix.ComplexNumericalMatrix;
import org.mklab.nfc.matrix.RealNumericalMatrix;
import org.mklab.nfc.rpn.AbstractExpressionProcessor;
import org.mklab.nfc.rpn.AddOperator;
import org.mklab.nfc.rpn.DoubleOperandOperator;
import org.mklab.nfc.rpn.ExpressionProcessor;
import org.mklab.nfc.rpn.InverseOperator;
import org.mklab.nfc.rpn.MultiplyOperator;
import org.mklab.nfc.rpn.ReversePolishNotationOperand;
import org.mklab.nfc.rpn.ReversePolishNotationOperator;
import org.mklab.nfc.rpn.ReversePolishNotationSymbol;
import org.mklab.nfc.rpn.SingleOperandOperator;
import org.mklab.nfc.scalar.ComplexNumericalScalar;
import org.mklab.nfc.scalar.RealNumericalScalar;
import org.mklab.tool.control.LinearSystem;
import org.mklab.tool.control.LinearSystemFactory;
import org.mklab.tool.control.system.LinearSystemOperator;
import org.mklab.tool.control.system.SymbolicOperator;
import org.mklab.tool.control.system.continuous.BaseContinuousStaticSystem;
import org.mklab.tool.control.system.continuous.ContinuousLinearDynamicSystem;


/**
 * 定数システムを表わすクラスです。
 * 
 * @author Koga Laboratory
 * @version $Revision: 1.41 $, 2004/11/12
  * @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 ConstantSystem<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 BaseContinuousStaticSystem<RS,RM,CS,CM> implements LinearSystemOperator<RS,RM,CS,CM>, SymbolicOperator, ReversePolishNotationOperand<RS,RM> {

  /** システム */
  private LinearSystem<RS,RM,CS,CM> gainSystem;

  /** 数式 */
  private String expression = ""; //$NON-NLS-1$

  /** 1個の項として扱えるシステムならばtrue */
  private boolean singleTerm = true;

  /** シンボルのスタック */
  private List<ReversePolishNotationSymbol<RS,RM>> symbolStack = new ArrayList<>();

  /** タグ */
  private String tag;

  /** 状態空間実現を求めるならばtrue */
  private static boolean requiringABCD = false;

  /** マイナスの項ならばtrue */
  private boolean isNegative = false;

  /** 変数として扱うならtrue */
  private boolean isVariable = false;

  /**
   * 新しく生成された<code>ConstantSystem</code>オブジェクトを初期化します。
   * 
   * @param inputSize 入力数
   * @param outputSize 出力数
   * @param sunit unit of scalar
   */
  public ConstantSystem(final int inputSize, final int outputSize, RS sunit) {
    super(inputSize, outputSize, sunit);
    setHasDirectFeedthrough(true);
    setLinear(true);
    this.tag = "" + hashCode(); //$NON-NLS-1$
    this.symbolStack.add(this);
  }

  /**
   * 新しく生成された<code>ConstantSystem</code>オブジェクトを初期化します。
   * 
   * @param gain 定数ゲイン行列
   */
  public ConstantSystem(final RM gain) {
    this(gain.getColumnSize(), gain.getRowSize(), gain.getElement(1,1).createUnit());
    this.gainSystem = LinearSystemFactory.createConstant(gain);
    final int inputSize = gain.getColumnSize();
    final int outputSize = gain.getRowSize();
    this.expression = "ConstantSystem(" + inputSize + " inputs, " + outputSize + " outputs)"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  }

  /**
   * 定数ゲイン行列を設定します。
   * 
   * @param gain 定数ゲイン行列
   */
  public void setGain(final RM gain) {
    this.gainSystem = LinearSystemFactory.createConstant(gain);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public RM outputEquation( final RS t, final RM u) {
    return this.gainSystem.getD().multiply(u);
  }

  /**
   * 単位システムであるか判定します。
   * 
   * @return 単位システムならtrue、そうでなければfalse
   */
  public boolean isUnit() {
    final RM K = this.gainSystem.getD();
    return K.getRowSize() == K.getColumnSize() && K.isUnit();
  }

  /**
   * 負の単位システムであるか判定します。
   * 
   * @return 負の単位システムならtrue、そうでなければfalse
   */
  public boolean isNegativeUnit() {
    final RM K = this.gainSystem.getD();
    return K.getRowSize() == K.getColumnSize() && K.unaryMinus().isUnit();
  }

  /**
   * 二つのシステムの和システムを返します。
   * 
   * @param opponent 足すシステム
   * @return 結合したシステム
   */
  public ConstantSystem<RS,RM,CS,CM> add(final ConstantSystem<RS,RM,CS,CM> opponent) {
    final RM gain = this.gainSystem.getD().add(opponent.gainSystem.getD());
    final ConstantSystem<RS,RM,CS,CM> constantSystem = new ConstantSystem<>(gain);
    constantSystem.setVariable(this.isVariable || opponent.isVariable);

    if (requiringABCD == false) {
      return constantSystem;
    }

    constantSystem.setSymbolStack(this.createSymbolStack(opponent, new AddOperator<RS,RM>()));
    return constantSystem;
  }

  /**
   * 二つのシステムの差システムを返します。
   * 
   * @param opponent 引くシステム
   * @return 結合したシステム
   */
  public ConstantSystem<RS,RM,CS,CM> subtract(final ConstantSystem<RS,RM,CS,CM> opponent) {
    final ConstantSystem<RS,RM,CS,CM> constantSystem = new ConstantSystem<>(this.gainSystem.getD().subtract(opponent.gainSystem.getD()));
    constantSystem.setVariable(this.isVariable || opponent.isVariable);

    if (requiringABCD == false) {
      return constantSystem;
    }

    constantSystem.setSubtractiveExpression(this, opponent);
    return constantSystem;
  }

  /**
   * 二つのシステムの差を表す数式を設定します。
   * TODO(koga)
   * @param first 第一項
   * @param second 第二項
   */
  private void setSubtractiveExpression(final ConstantSystem<RS,RM,CS,CM> first, final ConstantSystem<RS,RM,CS,CM> second) {
    String firstExpression = first.getMultipliedSystem().getExpression();
    if (first.isSingleTerm() == false) {
      firstExpression =  "(" + firstExpression + ")"; //$NON-NLS-1$ //$NON-NLS-2$
    }
    
    String secondExpression = second.getMultipliedSystem().getExpression();
    if (second.isSingleTerm() == false) {
      secondExpression =  "(" + secondExpression + ")"; //$NON-NLS-1$ //$NON-NLS-2$
    }
    
    if (second.isZero() || second.gainSystem.getD().isZero()) {
      setExpression(firstExpression);
    } else if (first.isZero() || first.gainSystem.getD().isZero()) {
      setExpression("- " + secondExpression); //$NON-NLS-1$
    } else {
      setExpression(firstExpression + " - " + secondExpression); //$NON-NLS-1$
    }

    setSingleTerm(false);
  }

  /**
   * 二つのシステムの積システムを返します。
   * 
   * @param opponent 掛けるシステム
   * @return 結合したシステム
   */
  public ConstantSystem<RS,RM,CS,CM> multiply(final ConstantSystem<RS,RM,CS,CM> opponent) {
    if (opponent instanceof UnitSystem) {
      return this;
    }

    final RM gain = this.gainSystem.getD().multiply(opponent.gainSystem.getD());
    final ConstantSystem<RS,RM,CS,CM> constantSystem = new ConstantSystem<>(gain);
    constantSystem.setVariable(this.isVariable || opponent.isVariable);

    if (requiringABCD == false) {
      return constantSystem;
    }

    constantSystem.setSymbolStack(this.createSymbolStack(opponent, new MultiplyOperator<RS,RM>()));
    return constantSystem;
  }

  /**
   * (ネガティブ)フィードバック結合したシステムを返します。
   * 
   * @param opponent フィードバック成分
   * @return 結合したシステム
   */
  public ConstantSystem<RS,RM,CS,CM> feedback(final ConstantSystem<RS,RM,CS,CM> opponent) {
    return feedback(opponent, true);
  }

  /**
   * フィードバック結合したシステムを返します。
   * 
   * @param opponent フィードバック要素
   * @param negativeFeedback ネガティブフィードバックならばtrue、そうでなければfalse
   * @return 結合したシステム
   */
  public ConstantSystem<RS,RM,CS,CM> feedback(final ConstantSystem<RS,RM,CS,CM> opponent, final boolean negativeFeedback) {
    final RM gain1 = this.gainSystem.getD();
    final RM gain2 = opponent.gainSystem.getD();
    if (negativeFeedback) {
      ConstantSystem<RS,RM,CS,CM> constantSystem = new ConstantSystem<>(this.sunit.createUnitGrid(gain1.getRowSize()).add(gain1.multiply(gain2)).leftDivide(gain1));
      constantSystem.setVariable(this.isVariable || opponent.isVariable);
      return constantSystem;
    }
    ConstantSystem<RS,RM,CS,CM> constantSystem = new ConstantSystem<>(this.sunit.createUnitGrid(gain1.getRowSize()).subtract(gain1.multiply(gain2)).leftDivide(gain1));
    constantSystem.setVariable(this.isVariable || opponent.isVariable);
    return constantSystem;
  }

  /**
   * 定数ゲイン行列を返します。
   * 
   * @return 定数ゲイン行列
   */
  public RM getGain() {
    return this.gainSystem.getD();
  }

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

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#setLinearSystem(org.mklab.tool.control.LinearSystem)
   */
  public void setLinearSystem(final LinearSystem<RS,RM,CS,CM> system) {
    this.gainSystem = system;
    setInputSize(system.getInputSize());
    setOutputSize(system.getOutputSize());
  }

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

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

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

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

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

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

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

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

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

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#setHasVariableE(boolean)
   */
  public void setHasVariableE( final boolean hasVariableE) {
    // nothing to do;
  }

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

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

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

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

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

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#add(org.mklab.tool.control.system.LinearSystemOperator)
   */
  public LinearSystemOperator<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 LinearSystemOperator<RS,RM,CS,CM> add(final LinearSystemOperator<RS,RM,CS,CM> opponent, final boolean simplify) {
    return new ContinuousLinearDynamicSystem<>(this.gainSystem.add(opponent.getLinearSystem(), simplify), this.sunit);
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#subtract(org.mklab.tool.control.system.LinearSystemOperator)
   */
  public LinearSystemOperator<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 LinearSystemOperator<RS,RM,CS,CM> subtract(final LinearSystemOperator<RS,RM,CS,CM> opponent, final boolean simplify) {
    return new ContinuousLinearDynamicSystem<>(this.gainSystem.subtract(opponent.getLinearSystem(), simplify), this.sunit);
  }

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

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

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

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

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

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#unaryMinus()
   */
  public ConstantSystem<RS,RM,CS,CM> unaryMinus() {
//        final ConstantSystem<RS,RM,CS,CM> constantSystem = new ConstantSystem<RS,RM,CS,CM>(this.gainSystem.getD().unaryMinus());
//        constantSystem.setVariable(this.isVariable);
//    
//        if (requiringABCD == false) {
//          return constantSystem;
//        }
//        constantSystem.setUnaryMinusExpression(this);
//        return constantSystem;
    return this.multiply(new NegativeUnitSystem<>(this.gainSystem.getD().getColumnSize(), this.sunit));
  }

  /**
   * 符号を反転した数式を設定します。
   * 
   * @param system 対象となるシステム
   */
  protected void setUnaryMinusExpression(final ConstantSystem<RS,RM,CS,CM> system) {
    if (system.isZero() || system.gainSystem.getD().isZero()) {
      setExpression(""); //$NON-NLS-1$
    } else {
      //      setExpression(system.getExpression());
      setTag(system.getTag());
      setNegative(!system.isNegative);
    }
  }

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

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

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#unityFeedback(boolean, boolean)
   */
  public ConstantSystem<RS,RM,CS,CM> unityFeedback(final boolean negativeFeedback,  final boolean simplify) {
    final RM K = this.gainSystem.getD();
    if (negativeFeedback) {
      ConstantSystem<RS,RM,CS,CM> constantSystem = new ConstantSystem<>(this.sunit.createUnitGrid(K.getRowSize()).add(K).leftDivide(K));
      constantSystem.setVariable(this.isVariable);
      return constantSystem;
    }
    ConstantSystem<RS,RM,CS,CM> constantSystem = new ConstantSystem<>(this.sunit.createUnitGrid(K.getRowSize()).subtract(K).leftDivide(K));
    constantSystem.setVariable(this.isVariable);
    return constantSystem;
  }

  /**
   * 単一フィードバック系がwell-posedであるか判定します。
   * 
   * <p>(I + G)または(I - G)が正則であるか判定します。
   * 
   * @param negativeFeedback 負フィードバックならばtrue、正フィードバックならばfalse
   * @return 単一フィードバック系がwell-posedならばtrue、そうでなければfalse
   */
  public boolean isUnityFeedbackWellPosed(final boolean negativeFeedback) {
    final RM K = getGain();
    if (K.getRowSize() != K.getColumnSize()) {
      return false;
    }

    if (negativeFeedback) {
      return this.sunit.createUnitGrid(K.getRowSize()).add(K).isFullRank();
    }
    return this.sunit.createUnitGrid(K.getRowSize()).subtract(K).isFullRank();
  }

  /**
   * 単一フィードバック系の感度関数「(I + K)~」(負フィードバック)、「(I - K)~」(正フィードバック)を返します。
   * 
   * @param negativeFeedback 負フィードバックならばtrue、正フィードバックならばfalse
   * @return 単一フィードバック系の感度関数「(I + K)~」(負フィードバック)、「(I - K)~」(正フィードバック)
   */
  public ConstantSystem<RS,RM,CS,CM> getSensitivityOfUnityFeedback(final boolean negativeFeedback) {
    final RM K = getGain();
    final RM gain = negativeFeedback ? this.sunit.createUnitGrid(K.getRowSize()).add(K).inverse() : this.sunit.createUnitGrid(K.getRowSize()).subtract(K).inverse();
    final ConstantSystem<RS,RM,CS,CM> constantSystem = new ConstantSystem<>(gain);
    constantSystem.setVariable(this.isVariable);

    if (requiringABCD == false) {
      return constantSystem;
    }

    if (isZero() || this.gainSystem.getD().isZero()) {
      return new UnitSystem<>(getInputSize(), this.sunit);
    }

    final ConstantSystem<RS,RM,CS,CM> system = negativeFeedback ? new UnitSystem<>(constantSystem.getInputSize(), this.sunit).add(this) : new UnitSystem<>(constantSystem.getInputSize(), this.sunit).add(this.multiply(new NegativeUnitSystem<>(
        this.getInputSize(), this.sunit)));
    system.setVariable(this.isVariable);
    system.setSingleTerm(false);
    return (system).inverse();
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#inverse()
   */
  public ConstantSystem<RS,RM,CS,CM> inverse() {
    final RM gain = getGain();
    gain.singularValue();
    final boolean stopIfSingular = true;
    final RM inversGain = gain.inverse(gain.frobNorm().multiply(this.sunit.getMachineEpsilon()), stopIfSingular);
    final ConstantSystem<RS,RM,CS,CM> constantSystem = (ConstantSystem<RS,RM,CS,CM>)this.createOperand(inversGain);
    constantSystem.setVariable(this.isVariable);
    constantSystem.getSymbolStack().remove(0);

    constantSystem.addSymbol(this);
    constantSystem.addSymbol(new InverseOperator<RS,RM>());
    return constantSystem;
  }

  /**
   * @see org.mklab.tool.control.system.SymbolicOperator#getExpression()
   */
  public String getExpression() {
    return this.expression;
  }

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

  /**
   * @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;
  }

  /**
   * 状態空間を求めるから判定します。
   * 
   * @return 状態空間を求めるならばtrue、そうでなければfalse
   */
  public static boolean isRequiringABCD() {
    return requiringABCD;
  }

  /**
   * 状態空間を求めるか設定します。
   * 
   * @param reruiringABCD 状態空間を求めるならばtrue、そうでなければfalse
   */
  public static void setRequiringABCD(final boolean reruiringABCD) {
    ConstantSystem.requiringABCD = reruiringABCD;
  }

  /**
   * 1個の項からなるシステムであるか判定します。
   * 
   * @return 1個の項からなるシステムならばtrue、そうでなければfalse
   */
  public boolean isSingleTerm() {
    return this.singleTerm;
  }

  /**
   * 1個の項からなるシステムであるかを設定します。
   * 
   * @param singleTerm 1個の項からなるシステムならばtrue、そうでなければfalse
   */
  public void setSingleTerm(final boolean singleTerm) {
    this.singleTerm = singleTerm;
  }

  /**
   * @see org.mklab.tool.control.system.SystemOperator#clone()
   */
  @Override
  public ConstantSystem<RS,RM,CS,CM> clone() {
    final ConstantSystem<RS,RM,CS,CM> inst = (ConstantSystem<RS,RM,CS,CM>)super.clone();
    if (this.gainSystem != null) {
      inst.gainSystem = (LinearSystem<RS,RM,CS,CM>)this.gainSystem.clone();
    }
    if (this.expression == null) {
      inst.expression = null;
    } else {
      inst.expression = new String(this.expression);
    }
    inst.singleTerm = this.singleTerm;
    inst.tag = this.tag;
    inst.symbolStack = Collections.unmodifiableList(this.symbolStack);
    inst.isNegative = this.isNegative;
    inst.isVariable = this.isVariable;
    return inst;
  }

  /**
   * @see org.mklab.tool.control.system.SystemOperator#hashCode()
   */
  @Override
  public int hashCode() {
    int hashCode = super.hashCode();
    hashCode = 31 * hashCode + (this.gainSystem == null ? 0 : this.gainSystem.hashCode());
    hashCode = 31 * hashCode + (this.expression == null ? 0 : this.expression.hashCode());
    hashCode = 31 * hashCode + (this.singleTerm ? 1231 : 1237);
    hashCode = 31 * hashCode + (this.tag == null ? 0 : this.tag.hashCode());
    hashCode = 31 * hashCode + (requiringABCD ? 1231 : 1237);
    return hashCode;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#getSignedExpression()
   */
  public String getSignedExpression() {
    return this.isNegative() ? "-" + this.getExpression() : this.getExpression(); //$NON-NLS-1$
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#getParsedOperand()
   */
  public ReversePolishNotationOperand<RS,RM> getParsedOperand() {
    String composedExpression = ""; //$NON-NLS-1$
    for (final ReversePolishNotationSymbol<RS,RM> symbol : this.getSymbolStack()) {
      final String singleExpression = ((ReversePolishNotationOperand<RS,RM>)symbol).getExpression();

      if (composedExpression.equals("")) { //$NON-NLS-1$
        //if (this.isNegative()) {
        if (((ReversePolishNotationOperand<RS,RM>)symbol).isNegative()) {
          composedExpression = ((ReversePolishNotationOperand<RS,RM>)symbol).getSignedExpression();
        } else {
          composedExpression = singleExpression;
        }
        continue;
      }

      if (((ReversePolishNotationOperand<RS,RM>)symbol).isNegative()) {
        composedExpression = composedExpression + " - " + singleExpression; //$NON-NLS-1$
      } else {
        composedExpression = composedExpression + " + " + singleExpression; //$NON-NLS-1$
      }
    }

    setExpression(composedExpression);
    return this;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#setSymbolStack(java.util.List)
   */
  public void setSymbolStack(final List<ReversePolishNotationSymbol<RS,RM>> reversePolishNotationSymbolStack) {
    this.symbolStack = reversePolishNotationSymbolStack;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#getSymbolStack()
   */
  public List<ReversePolishNotationSymbol<RS,RM>> getSymbolStack() {
    return this.symbolStack;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#addSymbol(org.mklab.nfc.rpn.ReversePolishNotationSymbol)
   */
  public void addSymbol(final ReversePolishNotationSymbol<RS,RM> symbol) {
    this.symbolStack.add(symbol);
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#addSymbols(java.util.List)
   */
  public void addSymbols(final List<ReversePolishNotationSymbol<RS,RM>> symbols) {
    this.symbolStack.addAll(symbols);
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#getStringOfSymbol()
   */
  public String getStringOfSymbol() {
    return this.getExpression();
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#isNegative()
   */
  public boolean isNegative() {
    return this.isNegative;
  }

//  /**
//   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#isReversePolishNotationOperator()
//   */
//  public boolean isReversePolishNotationOperator() {
//    return false;
//  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#createSymbolStack(org.mklab.nfc.rpn.ReversePolishNotationOperand, org.mklab.nfc.rpn.ReversePolishNotationOperator)
   */
  public List<ReversePolishNotationSymbol<RS,RM>> createSymbolStack(final ReversePolishNotationOperand<RS,RM> opponent, final ReversePolishNotationOperator<RS,RM> operator) {
    final List<ReversePolishNotationSymbol<RS,RM>> ans = new ArrayList<>();

    ans.addAll(opponent.getSymbolStack());
    ans.addAll(this.getSymbolStack());
    ans.add(operator);

    return ans;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#setNegative(boolean)
   */
  public void setNegative(final boolean isNegative) {
    this.isNegative = isNegative;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#invertSign()
   */
  public ConstantSystem<RS,RM,CS,CM> invertSign() {
    final ConstantSystem<RS,RM,CS,CM> clone = clone();
    clone.setGain(clone.getGain().unaryMinus());
    clone.setNegative(!this.isNegative);
    return clone;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#isZeroOperand()
   */
  public boolean isZeroOperand() {
    return this.gainSystem.getD().isZero();
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#add(org.mklab.nfc.rpn.ReversePolishNotationOperand)
   */
  public ReversePolishNotationOperand<RS,RM> add(final ReversePolishNotationOperand<RS,RM> opponent) {
    return this.add((ConstantSystem<RS,RM,CS,CM>)opponent);
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#multiply(org.mklab.nfc.rpn.ReversePolishNotationOperand)
   */
  public ReversePolishNotationOperand<RS,RM> multiply(final ReversePolishNotationOperand<RS,RM> opponent) {
    return this.multiply((ConstantSystem<RS,RM,CS,CM>)opponent);
  }

  /**
   * 掛け合わされたExpressionを持つSystemが返されます。
   * 
   * @return 掛け合わされたExpressionを持つSystem
   */
  public ReversePolishNotationOperand<RS,RM> getMultipliedSystem() {
    final ConstantSystem<RS,RM,CS,CM> multipliedSystem = this.clone();
    final AbstractExpressionProcessor<RS,RM> processor = new ExpressionProcessor<>();
    final ConstantSystem<RS,RM,CS,CM> system = (ConstantSystem<RS,RM,CS,CM>)processor.evaluate(multipliedSystem);
    if (system.isSingleTerm() == false) system.getParsedOperand();
    return system;
  }

  /**
   * @see org.mklab.tool.control.system.SystemOperator#equals(java.lang.Object)
   */
  @Override
  public boolean equals(final Object o) {
    if (this == o) {
      return true;
    }
    if (!super.equals(o)) {
      return false;
    }
    if (o == null) {
      return false;
    }
    if (o.getClass() != getClass()) {
      return false;
    }
    ConstantSystem<RS,RM,CS,CM> castedObj = (ConstantSystem<RS,RM,CS,CM>)o;
    return ((this.gainSystem == null ? castedObj.gainSystem == null : this.gainSystem.equals(castedObj.gainSystem))
        && (this.expression == null ? castedObj.expression == null : this.expression.equals(castedObj.expression)) && (this.singleTerm == castedObj.singleTerm) && (this.isNegative == castedObj.isNegative));
  }

  /**
   * {@inheritDoc}
   */
  public ReversePolishNotationOperand<RS,RM> createOperand(RM value) {
    final ConstantSystem<RS,RM,CS,CM> constantSystem = new ConstantSystem<>(value);
    constantSystem.setVariable(this.isVariable);
    return constantSystem;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#createUnitOperand(int)
   */
  public ReversePolishNotationOperand<RS,RM> createUnitOperand(final int size) {
    final UnitSystem<RS,RM,CS,CM> unitSystem = new UnitSystem<>(size, this.sunit);
    unitSystem.setVariable(this.isVariable);
    return unitSystem;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#createNegativeUnitOperand(int)
   */
  public ReversePolishNotationOperand<RS,RM> createNegativeUnitOperand(final int size) {
    final NegativeUnitSystem<RS,RM,CS,CM> unitSystem = new NegativeUnitSystem<>(size, this.sunit);
    unitSystem.setVariable(this.isVariable);
    return unitSystem;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#setVariable(boolean)
   */
  public void setVariable(boolean isVariable) {
    this.isVariable = isVariable;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#isVariable()
   */
  public boolean isVariable() {
    return this.isVariable;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#isUnitOperand()
   */
  public boolean isUnitOperand() {
    return false;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#isNegativeUnitOperand()
   */
  public boolean isNegativeUnitOperand() {
    return false;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#getOperandValue()
   */
  public RM getOperandValue() {
    return getGain();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {
    if (this.isNegative) {
      return "-" + this.expression; //$NON-NLS-1$
    }
    return this.expression;
  }

  /**
   * {@inheritDoc}
   */
  public ReversePolishNotationOperand<RS,RM> toOperand() {
    // TODO stub automaticaly generated
    return null;
  }

  /**
   * {@inheritDoc}
   */
  public SingleOperandOperator<RS,RM> toSingleOperandOperator() {
    // TODO stub automaticaly generated
    return null;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleOperandOperator<RS,RM> toDoubleOperandOperator() {
    // TODO stub automaticaly generated
    return null;
  }
}