NodeIdentityFunctionEquation.java

/**
 * $Id: NodeIdentityFunctionEquation.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.ArrayList;
import java.util.List;

import org.mklab.nfc.matrix.ComplexNumericalMatrix;
import org.mklab.nfc.matrix.RealNumericalMatrix;
import org.mklab.nfc.nleq.NonLinearFunction;
import org.mklab.nfc.ode.SolverStopException;
import org.mklab.nfc.scalar.ComplexNumericalScalar;
import org.mklab.nfc.scalar.RealNumericalScalar;
import org.mklab.tool.control.system.BlockSystem;
import org.mklab.tool.control.system.SystemOperator;


/**
 * 値が決定されていないノードの値を計算するための「x = f(x)」を満たす恒等関数を表すクラスです。
 * 
 * @author koga
 * @version $Revision: 1.6 $
 * @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 NodeIdentityFunctionEquation<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>> implements NonLinearFunction<RS,RM> {

  /** 隣接行列 */
  protected SystemOperator<RS,RM,CS,CM>[][] matrix;
  /** ノードの仮の値 */
  protected List<RM> nodeTmpValue;
  /** 各ループ内で最も次数の小さなノードの番号のリスト(ノード番号は1から始まる) */
  protected List<Integer> minimumNode;
  /** ノードの数 */
  protected int nodeSize;
  /** ブロックシステム */
  protected BlockSystem<RS,RM,CS,CM> blockSystem;
  
  /** unit of scalar */
  private RS sunit;

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

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

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

    List<RM> nodeValue = new ArrayList<>(this.nodeSize);

    SystemOperator<RS,RM,CS,CM>[][] matrixLocal = new SystemOperator[this.nodeSize][this.nodeSize];
    List<RM> nodeTmpValueLocal = new ArrayList<>(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.set(row, this.nodeTmpValue.get(row));
    }

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

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

    return newX;
  }

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

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