IO.java

package org.mklab.sdpj.iocenter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Scanner;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;


/**
 * SDPJSolverの中からファイル読み込みをするときに使います。
 * 
 * @author takafumi
 */
public class IO {

  /** */
  private final static String REALNUMBER = "([+-]?\\d+[.]?\\d*[e]?[E]?[+-]?[0-9]*)"; //$NON-NLS-1$
  /** */
  private final static String SPACE = "(\\p{Space}*)"; //$NON-NLS-1$
  /** */
  private final static String INTEGER = "([+-]?\\d+)"; //$NON-NLS-1$
  /** */
  private final static String NONUMBER = "[.&&[^0-9]&&[^+-]]*"; //$NON-NLS-1$
  /** */
  private final static String OTHERSTRING_REALNUMBER = NONUMBER + REALNUMBER;
  /** */
  private final static String OTHERSTRING_INTEGER = NONUMBER + INTEGER;

  /**
   * Read an integer from the string
   * 
   * @param string a string
   * @return value
   */
  public static int readInteger(String string) {
    try {
      MatchResult result = scan(string, INTEGER);
      return Integer.parseInt(result.group(1));
    } catch (IllegalStateException e) {
      throw new IllegalArgumentException(e);
    }
  }

  /**
   * 最初のコメントを削除 read m
   * 
   * @param reader is a instance of class BufferedReader
   * @param out is a instance of class PrintStream
   * @return value
   * @throws IOException if failure, IOException is thrown.
   */
  public static int readInteger(BufferedReader reader, PrintStream out) throws IOException {
    String string;

    do {
      string = reader.readLine();
      if (string.charAt(0) == '*' || string.charAt(0) == '"') {
        //     out.printf("The description of file is : %s\n\n", string); //$NON-NLS-1$
        continue;
      }

      break;
    } while (true);

    string = string.replaceAll(SPACE, ""); //$NON-NLS-1$
    return readInteger(string);
  }

  /**
   * "%*[^0-9+-]%d"
   * 
   * @param reader Reader for string
   * @return int data
   */
  public static int readOtherStringInteger(StringBuffer reader) {
    try {
      MatchResult result = scan(reader.toString(), OTHERSTRING_INTEGER);
      reader.delete(0, reader.indexOf(result.group(0)) + result.group(0).length());
      return Integer.parseInt(result.group(1));
    } catch (IllegalStateException e) {
      throw new IllegalArgumentException(e);
    }
  }

  /**
   * pattetrnと照合してMatcherを返します
   * 
   * @param string String to scan
   * @param pattern Pattern for data
   * @return data
   * @throws IllegalStateException if failure
   */
  private static MatchResult scan(String string, String pattern) throws IllegalStateException {
    try (Scanner scanner = new Scanner(string)) {
      scanner.findInLine(Pattern.compile(pattern));
      MatchResult result = scanner.match();
      return result;
    }
  }

  /**
   * @param reader is a instance of BufferedReader
   * @param nBlock is the number of block
   * @return integer array
   * @throws IOException if failure, IOException is thrown
   */
  public static int[] readBlockStruct(BufferedReader reader, int nBlock) throws IOException {
    int[] blockStruct = new int[nBlock];
    StringBuffer buffer = new StringBuffer(reader.readLine());

    for (int i = 0; i < nBlock; ++i) {
      blockStruct[i] = readOtherStringInteger(buffer);
      if (blockStruct[i] == 1) {
        blockStruct[i] = -1;
      }
    }

    return blockStruct;
  }

  /**
   * @param reader is a instance of StringBuffer
   * @return real number
   */
  public static String readOtherStringRealNumber(StringBuffer reader) {
    try {
      MatchResult result = scan(reader.toString(), OTHERSTRING_REALNUMBER);
      reader.delete(0, reader.indexOf(result.group(0)) + result.group(0).length());
      return result.group(1);
    } catch (IllegalStateException e) {
      throw new IllegalArgumentException(e);
    }
  }

  /**
   * @param string is a instance of StringBuffer
   * @return real number
   */
  public static String readOtherStringRealNumber(String string) {
    try {
      MatchResult result = scan(string, OTHERSTRING_REALNUMBER);
      return result.group(1);
    } catch (IllegalStateException e) {
      throw new IllegalArgumentException(e);
    }
  }

  /**
   * @param reader is class BufferReader information
   * @param dimension is the dimension of vector
   * @return vector
   * @throws IOException if reading is failure, IOException is thrown.
   */
  public static String[] readVector(BufferedReader reader, int dimension) throws IOException {
    String[] vector = new String[dimension];
    StringBuffer buffer = new StringBuffer(reader.readLine());
    for (int i = 0; i < dimension; i++) {
      vector[i] = readOtherStringRealNumber(buffer);
    }
    return vector;
  }

  /**
   * データ読み込み(SparseMatrix形式)
   * 
   * @param reader is class BufferReader information
   * @param m is the number of matrix block
   * @param blockStruct is a matrix block information
   * @return data of matrix block
   * @throws IOException if reading file is failure, IOException is thrown.
   */
  public static String[][] readSparseMatrix(BufferedReader reader, int m, int[] blockStruct) throws IOException {
    int numberOfElements = getNumberOfElements(blockStruct);
    String[][] data = new String[m + 1][numberOfElements];

    for (int i = 0; i < m + 1; i++) {
      for (int j = 0; j < numberOfElements; j++) {
        data[i][j] = "0"; //$NON-NLS-1$
      }
    }

    int[] blockSizes = getBlockSizes(blockStruct);

    String line = ""; //$NON-NLS-1$
    while ((line = reader.readLine()) != null) {
      StringBuffer buffer = new StringBuffer(line);
      int i = readOtherStringInteger(buffer);
      int j = readOtherStringInteger(buffer);
      int k = readOtherStringInteger(buffer);
      int l = readOtherStringInteger(buffer);
      String value = readOtherStringRealNumber(buffer);

      if (k != l) {
        data[i][sparseMatrixIndex(blockSizes, blockStruct, j, k, l)] = value;
        data[i][sparseMatrixIndex(blockSizes, blockStruct, j, l, k)] = value;
      } else {
        data[i][sparseMatrixIndex(blockSizes, blockStruct, j, k, l)] = value;
      }
    }

    return data;
  }

  /**
   * @param blockStruct Structure of blocks
   * @return Sizes of blocks
   */
  private static int[] getBlockSizes(int[] blockStruct) {
    int nBlock = blockStruct.length;
    int[] blockSizes = new int[nBlock + 1];
    int sum = 0;
    blockSizes[0] = 0;
    blockSizes[1] = 0;
    for (int i = 2; i < nBlock + 1; i++) {
      int blockSize = blockStruct[i - 2];
      if (blockSize < 0) {
        sum += -blockSize;
      } else {
        sum += blockSize * blockSize;
      }
      blockSizes[i] = sum;
    }
    return blockSizes;
  }

  /**
   * @param blockSizes Sizes of blocks
   * @param blockStruct Structure of blocks
   * @param j j
   * @param k k
   * @param l l
   * @return Index of sparse matrix
   */
  private static int sparseMatrixIndex(int[] blockSizes, int[] blockStruct, int j, int k, int l) {
    int index = 0;
    index = blockSizes[j];
    if (blockStruct[j - 1] < 0) {
      index += (k - 1);//+(l-1);
    } else {
      index += (k - 1) * blockStruct[j - 1] + (l - 1);
    }
    return index;
  }

  /**
   * データ読み込み(DenseMatrix形式)
   * 
   * @param reader is class BufferedReader information
   * @param m is the number of matrix
   * @param blockStruct is a matrix block information
   * @return data of matrix block
   * @throws IOException is exception information
   */
  public static String[][] readDenseMatrix(BufferedReader reader, int m, int[] blockStruct) throws IOException {
    int numberOfElements = getNumberOfElements(blockStruct);
    String[][] data = new String[m + 1][numberOfElements];

    for (int i = 0; i < m + 1; i++) {
      StringBuffer buffer = new StringBuffer(reader.readLine());
      for (int j = 0; j < numberOfElements; j++) {
        String value = readOtherStringRealNumber(buffer);

        if (i == 0) {
          value = unaryMinus(value);
        }
        data[i][j] = value;
      }
    }
    return data;
  }

  /**
   * 符号を反転した値を返します。
   * 
   * @param value value
   * @return sign opposite value
   */
  private static String unaryMinus(String value) {
    StringBuffer ans = new StringBuffer(value);

    if (value.charAt(0) == '-') {
      ans.delete(0, 1);
    } else {
      ans.insert(0, '-');
    }

    return ans.toString();
  }

  /**
   * ブロックの成分の数の総和を返します。
   * 
   * @param blockStruct ブロック構造
   * @return ブロックの成分の数の総和
   */
  private static int getNumberOfElements(int[] blockStruct) {
    int sum = 0;
    for (int i = 0; i < blockStruct.length; i++) {
      if (blockStruct[i] < 0) {
        sum += -blockStruct[i];
      } else {
        sum += blockStruct[i] * blockStruct[i];
      }
    }
    return sum;
  }

}