DoubleNodeEquation.java

/**
 * $Id: NodeEquation.java,v 1.6 2008/03/12 14:38:29 koga Exp $
 *
 * Copyright (C) 2004-2005 Koga Laboratory. All rights reserved.
 */

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

import java.util.List;

import org.mklab.nfc.matrix.DoubleMatrix;
import org.mklab.nfc.nleq.NonLinearFunction;
import org.mklab.nfc.ode.SolverStopException;
import org.mklab.nfc.scalar.DoubleNumber;
import org.mklab.tool.control.system.DoubleBlockSystem;
import org.mklab.tool.control.system.DoubleSystemOperator;


/**
 * 値が決定されていないノードの値を計算するための「f(x) = 0」を満たす非線形関数を表すクラスです。
 * 
 * @author koga
 * @version $Revision: 1.6 $
 */
public class DoubleNodeEquation implements NonLinearFunction<DoubleNumber,DoubleMatrix> {

  /** 隣接行列 */
  protected DoubleSystemOperator[][] matrix;
  /** ノードの仮の値 */
  protected DoubleMatrix[] nodeTmpValue;
  /** 各ループ内で最も次数の小さなノードの番号のリスト(ノード番号は1から始まる) */
  protected List<Integer> minimumNode;
  /** ノードの数 */
  protected int nodeSize;
  /** ブロックシステム */
  protected DoubleBlockSystem blockSystem;

  /**
   * 新しく生成された<code>NodeEquation</code>オブジェクトを初期化します。
   * 
   * @param blockSystem ブロックシステム
   * @param matrix 隣接行列
   * @param nodeTmpValue ノードの仮の値
   * @param minimumNode 各ループ内で最も次数の小さなノードの番号のリスト
   */
  public DoubleNodeEquation(final DoubleBlockSystem blockSystem, final DoubleSystemOperator[][] matrix, final DoubleMatrix[] nodeTmpValue, final List<Integer> minimumNode) {
    this.blockSystem = blockSystem;
    this.nodeSize = nodeTmpValue.length;
    this.matrix = matrix;
    this.nodeTmpValue = nodeTmpValue;
    this.minimumNode = minimumNode;
  }

  /**
   * @see org.mklab.nfc.nleq.NonLinearFunction#eval(org.mklab.nfc.matrix.NumericalMatrix)
   */
  public DoubleMatrix eval(final DoubleMatrix x) throws SolverStopException {
    DoubleMatrix[] xx = new DoubleMatrix[this.nodeSize];

    // 次数最小ノードの値を1個のベクトルから分離します。
    int offset = 0;
    for (int i : this.minimumNode) {
      int n = this.nodeTmpValue[i - 1].length();
      xx[i - 1] = x.getSubVector(offset + 1, offset + n);
      offset = offset + n;
    }

    DoubleMatrix[] nodeValue = new DoubleMatrix[this.nodeSize];

    DoubleSystemOperator[][] matrixLocal = new DoubleSystemOperator[this.nodeSize][this.nodeSize];
    DoubleMatrix[] nodeTmpValueLocal = new DoubleMatrix[this.nodeSize];
    for (int row = 0; row < this.nodeSize; row++) {
      for (int column = 0; column < this.nodeSize; column++) {
        matrixLocal[row][column] = this.matrix[row][column];
      }

      nodeTmpValueLocal[row] = this.nodeTmpValue[row];
    }

    // 与えられた次数最小ノードの値を用いて、自身を含む各ノードの値を計算します。
    calcNonMinimumNodeValues(nodeValue, xx, matrixLocal, nodeTmpValueLocal);

    // 次数最小ノードの値を1個のベクトルに結合します。
    DoubleMatrix newX = new DoubleMatrix(0, 1);
    for (int i : this.minimumNode) {
      newX = newX.appendDown(xx[i - 1].subtract(nodeValue[i - 1]));
    }

    return newX;
  }

  /**
   * 与えられた次数最小ノードの値から他のノードの値を計算します。
   * 
   * @param nodeValue ノードの値
   * @param xx 次数最小ノードの値の配列
   * @param matrixLocal 隣接行列
   * @param nodeTmpValueLocal ノードの仮の値
   * @throws SolverStopException ソルバーが停止された場合
   */
  protected void calcNonMinimumNodeValues(final DoubleMatrix[] nodeValue, final DoubleMatrix[] xx, final DoubleSystemOperator[][] matrixLocal, final DoubleMatrix[] nodeTmpValueLocal) throws SolverStopException {
    for (int i : this.minimumNode) {
      nodeValue[i - 1] = xx[i - 1];
    }

    while (this.blockSystem.calcOutputOfDirectFeedthroughSystem(matrixLocal, nodeValue, nodeTmpValueLocal, false)) {
      this.blockSystem.setNodeValueOfNoInputNode(matrixLocal, nodeValue, nodeTmpValueLocal, false);
    }
  }
}