Maxima.java

/*
 * Created on 2008/01/28
 * Copyright (C) 2008 Koga Laboratory. All rights reserved.
 *
 */
package org.mklab.tool.control.system.rpn;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import org.mklab.nfc.matrix.ComplexNumericalMatrix;
import org.mklab.nfc.matrix.RealNumericalMatrix;
import org.mklab.nfc.rpn.ReversePolishNotationOperator;
import org.mklab.nfc.rpn.ReversePolishNotationSymbol;
import org.mklab.nfc.scalar.ComplexNumericalScalar;
import org.mklab.nfc.scalar.RealNumericalScalar;
import org.mklab.tool.control.system.SystemOperator;
import org.mklab.tool.control.system.math.ConstantSystem;
import org.mklab.tool.control.system.math.NegativeUnitSystem;
import org.mklab.tool.control.system.math.UnitSystem;


/**
 * Maximaエンジンを呼び出すクラスです。
 * 
 * @author Anan
 * @version $Revision: 1.9 $, 2008/01/28
 * @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 Maxima<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>> {

  /** lineSeparator */
  private static final String lineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$
  /** variableList */
  // private static final List<ConstantSystem> variableList = new
  // ArrayList<ConstantSystem>();
  private static final List<String> variableList = new ArrayList<>();
  /** process */
  private Process process = null;
  /** writer */
  private PrintWriter writer = null;
  /** reader */
  private BufferedReader reader = null;

  /**
   * ConstantSystemからMaxima用のMatrixを作ります。
   * 
   * @param system 対象となるシステム
   * @return Maxima用に変換されたMatrix
   */
  private String createMatrixFromConstantSystem(final ConstantSystem<RS,RM,CS,CM> system) {
    String variable = system.getExpression();
    variable = variable.replaceAll("/", "division"); //$NON-NLS-1$ //$NON-NLS-2$
    return (variable + ":" + getMatrixString(system.getD())); //$NON-NLS-1$
  }

  /**
   * MatrixからMaxima用のMatrixを作ります。
   * 
   * @param matrix 対象となる行列
   * @return Maxima用に変換されたMatrix
   */
  private String getMatrixString(final RM matrix) {
    final StringBuilder str = new StringBuilder();
    str.append("matrix("); //$NON-NLS-1$
    for (int i = 1; i < matrix.getRowSize() + 1; i++) {
      str.append("["); //$NON-NLS-1$
      for (int j = 1; j < matrix.getColumnSize() + 1; j++) {
//        if (matrix instanceof IntMatrix) {
//          str.append((((IntMatrix)matrix).getIntElement(i, j)));
//        } else {
          str.append((matrix.getElement(i, j)));
//        }
        if ((j >= matrix.getColumnSize()) == false) {
          str.append(","); //$NON-NLS-1$
        }
      }
      str.append("]"); //$NON-NLS-1$
      if ((i >= matrix.getRowSize()) == false) {
        str.append(","); //$NON-NLS-1$
      }
    }
    str.append(");" + lineSeparator); //$NON-NLS-1$
    return str.toString();
  }

  /**
   * Maximaを起動し引数に渡されたコマンドを実行します。
   * 
   * @throws IOException 出力できない場合
   */
  public void open() throws IOException {
    final String maximaHome = System.getenv("MAXIMA_HOME"); //$NON-NLS-1$
    final String command = "\"" + maximaHome + "\\" + "maxima.bat\" --very-quiet --disable-readline"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    this.process = Runtime.getRuntime().exec(command);
    this.writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(this.process.getOutputStream())));
    this.reader = new BufferedReader(new InputStreamReader(this.process.getInputStream()));
    initialize();
  }

  /**
   * Maximaにコマンドを送ります。
   * 
   * @param comands コマンド
   */
  public void sendComand(final StringBuilder comands) {
    this.writer.print(comands.toString() + lineSeparator);
    this.writer.flush();
  }

  /**
   * Maximaに終了処理コマンドを送ります。
   */
  private void terminate() {
    this.writer.print("quit();" + lineSeparator); //$NON-NLS-1$
    this.writer.flush();
  }

  /**
   * Maximaに初期化コマンドを送ります。
   */
  private void initialize() {
    this.writer.print("ttyoff:true;" + lineSeparator); //$NON-NLS-1$
    this.writer.flush();
    this.writer.print("ratprint:false;" + lineSeparator); //$NON-NLS-1$
    this.writer.flush();
    this.writer.print("display2d:false;" + lineSeparator); //$NON-NLS-1$
    this.writer.flush();
    this.writer.print("scalarmatrixp:all;" + lineSeparator); //$NON-NLS-1$
    this.writer.flush();
    this.writer.print("linel:200;" + lineSeparator); //$NON-NLS-1$
    this.writer.flush();
    this.writer.print("doallmxops:false;" + lineSeparator); //$NON-NLS-1$
    this.writer.flush();
  }

  /**
   * Maximaからの結果を受け取ります。
   * 
   * @return 実行結果
   * @throws IOException 入力できない場合
   */
  public String receiveResult() throws IOException {
    this.reader.readLine();
    final String result = this.reader.readLine();
    // String resultMatrix = "";
    // while (true) {
    // String result = this.reader.readLine();
    // if (result == null) break;
    // resultMatrix = result;
    System.out.println(result);
    // }
    // System.out.println(resultMatrix);
    close();
    return result;
  }

  /**
   * Maximaを終了します。
   * 
   * @throws IOException 入力を閉じれない場合
   */
  private void close() throws IOException {
    terminate();
    this.writer.close();
    this.reader.close();
    this.process.destroy();
    variableList.clear();
  }

  /**
   * systemの定数システムの宣言をMaxima用に生成します。
   * 
   * @param system システム
   * @return systemの定数システムの変数宣言
   */
  public StringBuilder getDeclearOfSystems(final SystemOperator<RS,RM,CS,CM> system) {
    final StringBuilder systemsDeclear = new StringBuilder();

    final ConstantSystem<RS,RM,CS,CM> constantSystem = (ConstantSystem<RS,RM,CS,CM>)system;
    for (ReversePolishNotationSymbol<RS,RM> sys : constantSystem.getSymbolStack()) {
      if (sys instanceof ReversePolishNotationOperator) {
        continue;
      }
      if (((ConstantSystem<RS,RM,CS,CM>)sys).getExpression() == "" && (((ConstantSystem<RS,RM,CS,CM>)sys).getSymbolStack().size() >= 2)) { //$NON-NLS-1$
        systemsDeclear.append(getDeclearOfSystems((SystemOperator<RS,RM,CS,CM>)sys));
      } else {
        if ((variableList.contains(sys.getStringOfSymbol())) == false) {
          if (((ConstantSystem<RS,RM,CS,CM>)sys).isVariable()) {
            // variableList.add((ConstantSystem<RS,RM,CS,CM>)sys);
            variableList.add(sys.getStringOfSymbol());
            continue;
          }
          if (sys instanceof NegativeUnitSystem) {
            continue;
          }
          if (sys instanceof UnitSystem) {
            systemsDeclear.append("I:ident(" + ((ConstantSystem<RS,RM,CS,CM>)sys).getD().getColumnSize() + ");" + lineSeparator); //$NON-NLS-1$ //$NON-NLS-2$
          } else {
            systemsDeclear.append(createMatrixFromConstantSystem((ConstantSystem<RS,RM,CS,CM>)sys));
          }
          // variableList.add((ConstantSystem<RS,RM,CS,CM>)sys);
          variableList.add(sys.getStringOfSymbol());
        }
      }
    }
    return systemsDeclear;
  }
}