SdpjParameters.java
/**
* Copyright (C) 2021 MKLab.org (Koga Laboratory)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mklab.sdpj.main;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.regex.Pattern;
import org.mklab.sdpj.algorithm.ParameterType;
import org.mklab.sdpj.convert.Sedumi;
import org.mklab.sdpj.iocenter.IO;
import org.mklab.sdpj.tool.Tools;
/**
* Parameters of SDPJ.
*
* @author koga
* @version $Revision$, 2021/10/04
*/
public class SdpjParameters {
/** */
int precision;
/** */
String dataType;
/** */
boolean isInitFile;
/** */
boolean isInitSparse;
/** */
boolean isDataSparse;
/** */
boolean isParameter;
/** */
String dataFile;
/** */
String initFile;
/** */
String outFile;
/** */
String paraFile;
/** */
String kappaString;
ParameterType parameterType;
PrintStream fpOut;
/**
* Creates {@link SdpjParameters}.
*/
public SdpjParameters() {
this.isInitFile = false;
this.isInitSparse = false;
this.isDataSparse = false;
this.isParameter = false;
this.dataFile = null;
this.initFile = null;
this.outFile = null;
this.paraFile = null;
this.kappaString = null;
this.dataType = ""; //$NON-NLS-1$
this.precision = 77;
}
/**
* This is a solver of SdpjMain, which can compute a optimal solution of SDP problem, is an entry of solving a SDP problem.
*
* @param arguments a command line string
* @throws IOException If I/O exception occurs
*/
public void parseArguments(String[] arguments) throws IOException {
if (arguments.length < 2) {
showMessage("sdpj"); //$NON-NLS-1$
System.exit(0);
}
if (arguments[0].toLowerCase().equals("sedumi")) { //$NON-NLS-1$
sedumi(arguments);
}
int argc = arguments.length;
StringBuffer buff = new StringBuffer();
buff.append("SdpjMain start at " + new java.util.Date() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
this.parameterType = ParameterType.PARAMETER_DEFAULT;
if (argc == 1) {
showMessage(arguments[0]);
}
if (arguments[0].charAt(0) == '-') {
for (int i = 0; i < argc; ++i) {
String target = arguments[i];
if (target.equals("-dd") && i + 1 < argc) { //$NON-NLS-1$
this.dataFile = arguments[i + 1];
i++;
continue;
}
if (target.equals("-ds") && i + 1 < argc) { //$NON-NLS-1$
this.dataFile = arguments[i + 1];
i++;
this.isDataSparse = true;
continue;
}
if (target.equals("-id") && i + 1 < argc) { //$NON-NLS-1$
this.initFile = arguments[i + 1];
i++;
this.isInitFile = true;
continue;
}
if (target.equals("-is") && i + 1 < argc) { //$NON-NLS-1$
this.initFile = arguments[i + 1];
i++;
this.isInitFile = true;
this.isInitSparse = true;
continue;
}
if (target.equals("-o") && i + 1 < argc) { //$NON-NLS-1$
this.outFile = arguments[i + 1];
i++;
continue;
}
if (target.equals("-p") && i + 1 < argc) { //$NON-NLS-1$
this.paraFile = arguments[i + 1];
i++;
this.isParameter = true;
continue;
}
if (target.equals("-k") && i + 1 < argc) { //$NON-NLS-1$
this.kappaString = arguments[i + 1];
Tools.message("Kappa = " + this.kappaString); //$NON-NLS-1$
i++;
continue;
}
if (target.equals("-pt") && i + 1 < argc) { //$NON-NLS-1$
int tmp = atoi(arguments[i + 1]);
switch (tmp) {
case 0:
this.parameterType = ParameterType.PARAMETER_DEFAULT;
break;
case 1:
this.parameterType = ParameterType.PARAMETER_AGGRESSIVE;
break;
case 2:
this.parameterType = ParameterType.PARAMETER_STABLE;
break;
case 3:
this.parameterType = ParameterType.PARAMETER_MP115_DEFAULT;
break;
case 4:
this.parameterType = ParameterType.PARAMETER_MP115_STABLE;
break;
default:
this.parameterType = ParameterType.PARAMETER_DEFAULT;
}
if (tmp == 3 || tmp == 4) {
this.dataType = "mpfloat"; //$NON-NLS-1$
} else {
this.dataType = "double"; //$NON-NLS-1$
}
i++;
this.paraFile = null;
this.isParameter = false;
continue;
}
}
} else { // SDPA argument
this.dataFile = arguments[0];
int len = this.dataFile.length();
if (this.dataFile.charAt(len - 1) == 's' && this.dataFile.charAt(len - 2) == '-') {
this.isDataSparse = true;
}
this.outFile = arguments[1];
for (int i = 2; i < arguments.length; ++i) {
if (arguments[i].equals("-pt") && i + 1 < argc) { //$NON-NLS-1$
int tmp = atoi(arguments[i + 1]);
switch (tmp) {
case 0:
this.parameterType = ParameterType.PARAMETER_DEFAULT;
break;
case 1:
this.parameterType = ParameterType.PARAMETER_AGGRESSIVE;
break;
case 2:
this.parameterType = ParameterType.PARAMETER_STABLE;
break;
case 3:
this.parameterType = ParameterType.PARAMETER_MP115_DEFAULT;
break;
case 4:
this.parameterType = ParameterType.PARAMETER_MP115_STABLE;
break;
default:
this.parameterType = ParameterType.PARAMETER_DEFAULT;
}
if (tmp == 3 || tmp == 4) {
this.dataType = "mpfloat"; //$NON-NLS-1$
} else {
this.dataType = "double"; //$NON-NLS-1$
}
i++;
this.paraFile = null;
this.isParameter = false;
} else {
if (arguments[i].equals("-p") && i + 1 < argc) { //$NON-NLS-1$
this.paraFile = arguments[i + 1];
i++;
this.isParameter = true;
} else {
this.initFile = arguments[i];
this.isInitFile = true;
len = this.initFile.length();
if (this.initFile.charAt(len - 1) == 's' && this.initFile.charAt(len - 2) == '-') {
this.isInitSparse = true;
}
}
}
}
}
if (this.dataType.equals("")) { //$NON-NLS-1$
if (this.paraFile == null) {
this.paraFile = "param/param.sdpj"; //$NON-NLS-1$
}
creatDataType(this.paraFile);
this.isParameter = true;
}
if (this.dataFile == null || this.outFile == null) {
showMessage(arguments[0]);
}
buff.append("data is " + this.dataFile); //$NON-NLS-1$
if (this.isDataSparse) {
buff.append(" : sparse\n"); //$NON-NLS-1$
} else {
buff.append(" : dense\n"); //$NON-NLS-1$
}
if (this.paraFile != null) {
buff.append("parameter is " + this.paraFile + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
}
if (this.outFile != null) {
buff.append("out is " + this.outFile + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
}
if (this.initFile != null) {
buff.append("initial is " + this.initFile); //$NON-NLS-1$
}
if (this.isInitFile) {
if (this.isInitSparse) {
buff.append(" : sparse\n"); //$NON-NLS-1$
} else {
buff.append(" : dense\n"); //$NON-NLS-1$
}
} else {
buff.append("\n"); //$NON-NLS-1$
}
if (this.paraFile == null) {
if (this.parameterType == ParameterType.PARAMETER_DEFAULT) {
buff.append("set is Double DEFAULT\n");// << endl; //$NON-NLS-1$
} else if (this.parameterType == ParameterType.PARAMETER_AGGRESSIVE) {
buff.append("set is Double AGGRESSIVE\n");// << endl; //$NON-NLS-1$
} else if (this.parameterType == ParameterType.PARAMETER_STABLE) {
buff.append("set is Double STABLE\n");// << endl; //$NON-NLS-1$
} else if (this.parameterType == ParameterType.PARAMETER_MP115_DEFAULT) {
buff.append("set is MPFloat DEFAULT\n");// << endl; //$NON-NLS-1$
} else if (this.parameterType == ParameterType.PARAMETER_MP115_STABLE) {
buff.append("set is MPFloat STABLE\n");// << endl; //$NON-NLS-1$
}
}
Tools.message(buff.toString(), System.out);
try (PrintStream fp = new PrintStream(new FileOutputStream(new File(this.outFile)))) {
this.fpOut = fp;
Tools.message(buff.toString(), fp);
}
}
/**
* the purpose of this method is show how to use <code>SdpjMain</code> when users make a mistake in using <code>SdpjMain</code>.
*
* @param argv0 a string, which is "<code>sdpj</code>"
*/
private void showMessage(String argv0) {
StringBuffer buff = new StringBuffer();
buff.append("\n"); //$NON-NLS-1$
buff.append("************* Please assign data file and output file.*************\n"); //$NON-NLS-1$
buff.append("\n"); //$NON-NLS-1$
buff.append("------------------- option type 1 --------------------\n"); //$NON-NLS-1$
buff.append(argv0 + " DataFile OutputFile [InitialPtFile]" + " [-pt parameters] [-p InitialParamFile]\n"); //$NON-NLS-1$ //$NON-NLS-2$
buff.append("parameters = 0 default, 1 aggressive," + " 2 stable, 3 MPFloat default, 4 MPFlaot stable\n"); //$NON-NLS-1$ //$NON-NLS-2$
buff.append("example1-1: " + argv0 + " example.dat example.result\n"); //$NON-NLS-1$ //$NON-NLS-2$
buff.append("example1-2: " + argv0 + " example.dat-s example.result\n"); //$NON-NLS-1$ //$NON-NLS-2$
buff.append("example1-3: " + argv0 + " example.dat example.result example.ini\n"); //$NON-NLS-1$ //$NON-NLS-2$
buff.append("example1-4: " + argv0 + " example.dat example.result -pt 2\n"); //$NON-NLS-1$ //$NON-NLS-2$
buff.append("example1-5: " + argv0 + " example.dat example.result -p param.sdpj\n"); //$NON-NLS-1$ //$NON-NLS-2$
buff.append("\n"); //$NON-NLS-1$
buff.append("------------------- option type 2 --------------------\n"); //$NON-NLS-1$
buff.append(argv0 + " [option filename]+ \n"); //$NON-NLS-1$
buff.append(" -dd : data dense :: -ds : data sparse \n"); //$NON-NLS-1$
buff.append(" -id : init dense :: -is : init sparse \n"); //$NON-NLS-1$
buff.append(" -o : output :: -p : parameter \n"); //$NON-NLS-1$
buff.append(" -pt : parameters , 0 default, 1 aggressive, 2 stable,\n"); //$NON-NLS-1$
buff.append(" 3 MPFloat default, 4 MPFlaot stable\n"); //$NON-NLS-1$
buff.append("example2-1: " + argv0 + " -o example.result -dd example.dat\n"); //$NON-NLS-1$ //$NON-NLS-2$
buff.append("example2-2: " + argv0 + " -ds example.dat-s -o example.result " + "-p param.sdpj\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
buff.append("example2-3: " + argv0 + " -ds example.dat-s -o example.result " + "-pt 2\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
buff.append("\nNote:if you run program by command line mode,please refer to option type1\n"); //$NON-NLS-1$
buff.append("or type2.Otherwise,you must give parameter args some information about \n"); //$NON-NLS-1$
buff.append("DataFile & OutputFile,etc.If you do not input the InitialParamFile in Type1,\n"); //$NON-NLS-1$
buff.append("the datatype will be used by default. And Type2 is also the same. Otherwise,\n"); //$NON-NLS-1$
buff.append("the datatype is appointed based on the InitialParamFile. To run the program \n"); //$NON-NLS-1$
buff.append("correctly,you must appoint datafile and outputfile.\n"); //$NON-NLS-1$
buff.append("For example: args[0] = \"example.dat-s\", args[1] = \"example.result\"\n"); //$NON-NLS-1$
buff.append("Recommedation:if you want to appoint a datatype, input a InitialParamFile.\n"); //$NON-NLS-1$
buff.append("\n******************************************************************\n"); //$NON-NLS-1$
System.out.println(new String(buff));
}
/**
* The program is to change an inputting style of solver <code>sedumi</code> into the style of solver <code>sdpj</code>
*
* @param arguments a command line string
*/
private void sedumi(String[] arguments) {
final Sedumi sedumi = new Sedumi();
final String writeFile = arguments[1];
final String fileFormat = writeFile.substring(writeFile.lastIndexOf(".")); //$NON-NLS-1$
final String datsFile = writeFile.replaceAll(Pattern.quote(fileFormat), ".dat-s"); //$NON-NLS-1$
System.out.println(datsFile + " is building..."); //$NON-NLS-1$
sedumi.SedumiLoad(writeFile, datsFile);
System.out.println("Done"); //$NON-NLS //$NON-NLS-1$
System.out.println("please input command:% sdpj " + datsFile + " outputfile" + " [options]\n"); //$NON-NLS //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
System.exit(0);
}
/**
* Create a specific data type from a parameter file. Users can freely specify a data type, which can be used in <code>SdpjMain</code>.
*
* @param parameterFile Parameter file
* @throws FileNotFoundException If no file found exception occurs
* @throws IOException If I/O exception occurs
*/
private void creatDataType(String parameterFile) throws FileNotFoundException, IOException {
BufferedReader reader = new BufferedReader(new FileReader(new File(parameterFile)));
while (this.dataType.equals("double") == false && this.dataType.equals("mpfloat") == false) { //$NON-NLS-1$//$NON-NLS-2$
String string = reader.readLine();
if (string == null) {
break;
}
String type = string.toLowerCase();
if (type.contains("double")) { //$NON-NLS-1$
this.dataType = "double"; //$NON-NLS-1$
} else if (type.contains("mpfloat")) { //$NON-NLS-1$
this.dataType = "mpfloat"; //$NON-NLS-1$
} else {
this.dataType = type;
}
}
if (this.dataType.equals("mpfloat")) { //$NON-NLS-1$
this.precision = IO.readInteger(reader.readLine());
}
}
/**
* This program is to change a <code>string</code> into a <code>integer</code>, which can only change a <code>char</code> of the string. And if the char is not a <code>number</code> char, maybe it
* occurs an exception. <br>文字列の最初に数字きたらその整数を返します。 本来は文字列の先頭から走査していき、数字以外が来たらそこまでの整数を返すというもの。 今回は引数の判別で、一桁のものしかないため、最初の数字しか考えていない。
*
* @param str a integer string
* @return a integer
*/
private int atoi(String str) {
switch (str.charAt(0)) {
case '0':
return 0;
case '1':
return 1;
case '2':
return 2;
case '3':
return 3;
case '4':
return 4;
case '5':
return 5;
case '6':
return 6;
case '7':
return 7;
case '8':
return 8;
case '9':
return 9;
case '-':
return -atoi(str.substring(1));
}
return 0;
}
/**
* Returns string of kappa.
*
* @return string of kappa
*/
public String getKappaString() {
return this.kappaString;
}
}