DoubleConstantSystem.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.DoubleMatrix;
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.DoubleNumber;
import org.mklab.nfc.scalar.DoubleNumberUtil;
import org.mklab.tool.control.DoubleLinearSystem;
import org.mklab.tool.control.DoubleLinearSystemFactory;
import org.mklab.tool.control.system.DoubleLinearSystemOperator;
import org.mklab.tool.control.system.SymbolicOperator;
import org.mklab.tool.control.system.continuous.DoubleBaseContinuousStaticSystem;
import org.mklab.tool.control.system.continuous.DoubleContinuousLinearDynamicSystem;


/**
 * 定数システムを表わすクラスです。
 * 
 * @author Koga Laboratory
 * @version $Revision: 1.41 $, 2004/11/12
 */
public class DoubleConstantSystem extends DoubleBaseContinuousStaticSystem implements DoubleLinearSystemOperator, SymbolicOperator, ReversePolishNotationOperand<DoubleNumber,DoubleMatrix> {

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

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

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

  /** シンボルのスタック */
  private List<ReversePolishNotationSymbol<DoubleNumber,DoubleMatrix>> 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 出力数
   */
  public DoubleConstantSystem(final int inputSize, final int outputSize) {
    super(inputSize, outputSize);
    setHasDirectFeedthrough(true);
    setLinear(true);
    this.tag = "" + hashCode(); //$NON-NLS-1$
    this.symbolStack.add(this);
  }

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

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

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

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

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

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

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

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

  /**
   * 二つのシステムの差システムを返します。
   * 
   * @param opponent 引くシステム
   * @return 結合したシステム
   */
  public DoubleConstantSystem subtract(final DoubleConstantSystem opponent) {
    final DoubleConstantSystem constantSystem = new DoubleConstantSystem(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 DoubleConstantSystem first, final DoubleConstantSystem 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 DoubleConstantSystem multiply(final DoubleConstantSystem opponent) {
    if (opponent instanceof DoubleUnitSystem) {
      return this;
    }

    final DoubleMatrix gain = this.gainSystem.getD().multiply(opponent.gainSystem.getD());
    final DoubleConstantSystem constantSystem = new DoubleConstantSystem(gain);
    constantSystem.setVariable(this.isVariable || opponent.isVariable);

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

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

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

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

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

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

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#setLinearSystem(org.mklab.tool.control.LinearSystem)
   */
  public void setLinearSystem(final DoubleLinearSystem 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 DoubleMatrix getA() {
    return this.gainSystem.getA();
  }

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

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

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

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

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

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

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

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

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

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

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

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#feedback(org.mklab.tool.control.system.LinearSystemOperator, boolean)
   */
  public DoubleLinearSystemOperator feedback(final DoubleLinearSystemOperator 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 DoubleLinearSystemOperator feedback(final DoubleLinearSystemOperator opponent, final boolean negativeFeedback, final boolean simplify) {
    return new DoubleContinuousLinearDynamicSystem(this.gainSystem.feedback(opponent.getLinearSystem(), negativeFeedback, simplify));
  }

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#unaryMinus()
   */
  public DoubleConstantSystem unaryMinus() {
//        final ConstantSystem constantSystem = new ConstantSystem(this.gainSystem.getD().unaryMinus());
//        constantSystem.setVariable(this.isVariable);
//    
//        if (requiringABCD == false) {
//          return constantSystem;
//        }
//        constantSystem.setUnaryMinusExpression(this);
//        return constantSystem;
    return this.multiply(new DoubleNegativeUnitSystem(this.gainSystem.getD().getColumnSize()));
  }

  /**
   * 符号を反転した数式を設定します。
   * 
   * @param system 対象となるシステム
   */
  protected void setUnaryMinusExpression(final DoubleConstantSystem 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 DoubleConstantSystem unityFeedback() {
    return unityFeedback(true, true);
  }

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

  /**
   * @see org.mklab.tool.control.system.LinearSystemOperator#unityFeedback(boolean, boolean)
   */
  public DoubleConstantSystem unityFeedback(final boolean negativeFeedback,  final boolean simplify) {
    final DoubleMatrix K = this.gainSystem.getD();
    if (negativeFeedback) {
      DoubleConstantSystem constantSystem = new DoubleConstantSystem(DoubleMatrix.unit(K).add(K).leftDivide(K));
      constantSystem.setVariable(this.isVariable);
      return constantSystem;
    }
    DoubleConstantSystem constantSystem = new DoubleConstantSystem(DoubleMatrix.unit(K).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 DoubleMatrix K = getGain();
    if (K.getRowSize() != K.getColumnSize()) {
      return false;
    }

    if (negativeFeedback) {
      return DoubleMatrix.unit(K).add(K).isFullRank();
    }
    return DoubleMatrix.unit(K).subtract(K).isFullRank();
  }

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

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

    if (isZero() || this.gainSystem.getD().isZero()) {
      return new DoubleUnitSystem(getInputSize());
    }

    final DoubleConstantSystem system = negativeFeedback ? new DoubleUnitSystem(constantSystem.getInputSize()).add(this) : new DoubleUnitSystem(constantSystem.getInputSize()).add(this.multiply(new DoubleNegativeUnitSystem(
        this.getInputSize())));
    system.setVariable(this.isVariable);
    system.setSingleTerm(false);
    return (system).inverse();
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#inverse()
   */
  public DoubleConstantSystem inverse() {
    final DoubleMatrix gain = getGain();
    gain.singularValue();
    final boolean stopIfSingular = true;
    final DoubleMatrix inversGain = gain.inverse(gain.frobNorm().doubleValue() * DoubleNumberUtil.EPS, stopIfSingular);
    final DoubleConstantSystem constantSystem = (DoubleConstantSystem)this.createOperand(inversGain);
    constantSystem.setVariable(this.isVariable);
    constantSystem.getSymbolStack().remove(0);

    constantSystem.addSymbol(this);
    constantSystem.addSymbol(new InverseOperator<DoubleNumber,DoubleMatrix>());
    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) {
    DoubleConstantSystem.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 DoubleConstantSystem clone() {
    final DoubleConstantSystem inst = (DoubleConstantSystem)super.clone();
    if (this.gainSystem != null) {
      inst.gainSystem = (DoubleLinearSystem)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<DoubleNumber,DoubleMatrix> getParsedOperand() {
    String composedExpression = ""; //$NON-NLS-1$
    for (final ReversePolishNotationSymbol<DoubleNumber,DoubleMatrix> symbol : this.getSymbolStack()) {
      final String singleExpression = ((ReversePolishNotationOperand<DoubleNumber,DoubleMatrix>)symbol).getExpression();

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

      if (((ReversePolishNotationOperand<DoubleNumber,DoubleMatrix>)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<DoubleNumber,DoubleMatrix>> reversePolishNotationSymbolStack) {
    this.symbolStack = reversePolishNotationSymbolStack;
  }

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

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

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#addSymbols(java.util.List)
   */
  public void addSymbols(final List<ReversePolishNotationSymbol<DoubleNumber,DoubleMatrix>> 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<DoubleNumber,DoubleMatrix>> createSymbolStack(final ReversePolishNotationOperand<DoubleNumber,DoubleMatrix> opponent, final ReversePolishNotationOperator<DoubleNumber,DoubleMatrix> operator) {
    final List<ReversePolishNotationSymbol<DoubleNumber,DoubleMatrix>> 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 DoubleConstantSystem invertSign() {
    final DoubleConstantSystem 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<DoubleNumber,DoubleMatrix> add(final ReversePolishNotationOperand<DoubleNumber,DoubleMatrix> opponent) {
    return this.add((DoubleConstantSystem)opponent);
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#multiply(org.mklab.nfc.rpn.ReversePolishNotationOperand)
   */
  public ReversePolishNotationOperand<DoubleNumber,DoubleMatrix> multiply(final ReversePolishNotationOperand<DoubleNumber,DoubleMatrix> opponent) {
    return this.multiply((DoubleConstantSystem)opponent);
  }

  /**
   * 掛け合わされたExpressionを持つSystemが返されます。
   * 
   * @return 掛け合わされたExpressionを持つSystem
   */
  public ReversePolishNotationOperand<DoubleNumber,DoubleMatrix> getMultipliedSystem() {
    final DoubleConstantSystem multipliedSystem = this.clone();
    final AbstractExpressionProcessor<DoubleNumber,DoubleMatrix> processor = new ExpressionProcessor<>();
    final DoubleConstantSystem system = (DoubleConstantSystem)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;
    }
    DoubleConstantSystem castedObj = (DoubleConstantSystem)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<DoubleNumber,DoubleMatrix> createOperand(DoubleMatrix value) {
    final DoubleConstantSystem constantSystem = new DoubleConstantSystem(value);
    constantSystem.setVariable(this.isVariable);
    return constantSystem;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#createUnitOperand(int)
   */
  public ReversePolishNotationOperand<DoubleNumber,DoubleMatrix> createUnitOperand(final int size) {
    final DoubleUnitSystem unitSystem = new DoubleUnitSystem(size);
    unitSystem.setVariable(this.isVariable);
    return unitSystem;
  }

  /**
   * @see org.mklab.nfc.rpn.ReversePolishNotationOperand#createNegativeUnitOperand(int)
   */
  public ReversePolishNotationOperand<DoubleNumber,DoubleMatrix> createNegativeUnitOperand(final int size) {
    final DoubleNegativeUnitSystem unitSystem = new DoubleNegativeUnitSystem(size);
    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 DoubleMatrix getOperandValue() {
    return getGain();
  }

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

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

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

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