Commit bffe7371 authored by Johannes Mey's avatar Johannes Mey
Browse files

add scip solver.

parent b43c5ddf
package de.tudresden.inf.st.mquat.benchmark;
import de.tudresden.inf.st.mquat.solving.BenchmarkableSolver;
import de.tudresden.inf.st.mquat.solving.ilp.GLPKSolver;
import de.tudresden.inf.st.mquat.solving.ilp.ILPDirectSolver;
import de.tudresden.inf.st.mquat.solving.ilp.ILPExternalSolver;
import de.tudresden.inf.st.mquat.solving.genetic.GeneticSolver;
import de.tudresden.inf.st.mquat.solving.ilp.SCIPSolver;
import de.tudresden.inf.st.mquat.solving.random.RandomSolver;
import de.tudresden.inf.st.mquat.solving.simple.SimpleSolver;
import ir.ac.ui.eng.ACOSolver;
......@@ -28,7 +29,8 @@ public class SolverFactory {
availableSolvers = Stream.of(
new ACOSolver(),
new EMFeRSolver(),
new ILPExternalSolver(),
new GLPKSolver(),
new SCIPSolver(),
new ILPDirectSolver(),
new SimpleSolver(),
new RandomSolver(0, 0),
......
......@@ -5,7 +5,8 @@
"aco",
"emfer",
"ilp-direct",
// "ilp-external",
"ilp-glpk",
"ilp-scip",
"random",
"genetic",
"simple"
......
package de.tudresden.inf.st.mquat.solving.ilp;
import de.tudresden.inf.st.mquat.jastadd.model.ILP;
import de.tudresden.inf.st.mquat.jastadd.model.IlpVariable;
import de.tudresden.inf.st.mquat.solving.SolvingException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class GLPKSolver extends ILPExternalSolver {
/**
* Create a new GLPK solver with default settings.
* Default is:
* <ul>
* <li>1 minute timeout</li>
* <li>delete temporary files on exit.</li>
* </ul>
* @see GLPKSolver#setDeleteFilesOnExit(boolean)
*/
public GLPKSolver() {
}
@Override
protected String[] getCommand(Path lp, Path solution, long remainingTimeForSolvingInMillis) {
return new String[] {"glpsol", "--lp", lp.toAbsolutePath().toString(), "--cuts",
"-o", String.valueOf(solution.toAbsolutePath())};
}
@Override
public String getName() {
return "ilp-glpk";
}
@Override
protected void readFromPlainTextSolution(ILP ilp, Path solution, ILPSolution result,
List<IlpVariable> variablesSetToOne) throws SolvingException {
List<String> varNamesSetToOne = new ArrayList<>();
String name = null;
int phase = 1;
try (Stream<String> lines = Files.lines(solution)) {
for (String line : lines.collect(Collectors.toList())) {
if (phase < 3) {
if (line.startsWith("Objective")) {
int equalsIndex = line.indexOf('=');
int bracketIndex = line.lastIndexOf('(');
result.setObjective(Double.valueOf(line.substring(equalsIndex + 1, bracketIndex).trim()));
}
if (line.startsWith("---")) {
phase += 1;
}
continue;
}
line = line.trim();
if (line.isEmpty()) {
continue;
}
String[] tokens = line.split("\\s+");
if (tokens.length == 6) {
// tokens: index, name, star, activity, lb, rb
if(Integer.valueOf(tokens[3]) == 1) {
varNamesSetToOne.add(tokens[1]);
}
phase = 3;
} else if (phase == 3) {
if(line.startsWith("Integer")) {
break;
}
// tokens: index, name
name = tokens[1];
phase = 4;
} else if (phase == 4) {
// tokens: star, activity, lb, rb
if (name == null) {
throw new SolvingException("Error in parsing solution. Name is null. Tokens: " + Arrays.toString(tokens));
}
if (Integer.valueOf(tokens[1]) == 1) {
varNamesSetToOne.add(name);
name = null;
}
phase = 3;
}
}
} catch (IOException e) {
throw new SolvingException("Could not open solution file", e);
} catch (NumberFormatException | IndexOutOfBoundsException e) {
throw new SolvingException("Could not parse solution file", e);
}
for (String varName : varNamesSetToOne) {
IlpVariable variable = ilp.resolve(varName);
if (variable == null) {
throw new SolvingException("Could not find variable with name " + varName);
}
variablesSetToOne.add(variable);
}
}
}
......@@ -19,7 +19,7 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ILPExternalSolver extends AbstractILPSolver {
public abstract class ILPExternalSolver extends AbstractILPSolver {
private boolean deleteFilesOnExit;
private Path lp, solutionReadable;
......@@ -71,12 +71,9 @@ public class ILPExternalSolver extends AbstractILPSolver {
}
protected double solve0(Root model, StopWatch watch, List<IlpVariable> variablesSetToOne) throws SolvingException {
long startOfWriteOutInMillis = watch.time(TimeUnit.MILLISECONDS);
// Create temporary files
try {
lp = Files.createTempFile("ilp", null);
lp = Files.createTempFile("ilp", ".lp");
// solution = Files.createTempFile("solution", null);
solutionReadable = Files.createTempFile("sol-read", null);
} catch (IOException e) { throw new SolvingException("Can not create lp or solution file", e); }
......@@ -84,8 +81,12 @@ public class ILPExternalSolver extends AbstractILPSolver {
logger.info("Writing ILP to {}, solving now", lp.toAbsolutePath());
}
long startOfWriteOutInMillis = watch.time(TimeUnit.MILLISECONDS);
// write out lp file
IlpString output = model.getILP().printIlp();
try (BufferedWriter writer = Files.newBufferedWriter(
lp, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
writer.write(output.toString());
......@@ -95,22 +96,18 @@ public class ILPExternalSolver extends AbstractILPSolver {
this.lastGeneration = watch.time(TimeUnit.MILLISECONDS);
long millisecondsNeededToWriteOut = watch.time(TimeUnit.MILLISECONDS) - startOfWriteOutInMillis;
long remainingTimeInMillis = this.timeoutUnit.toMillis(this.timeoutValue) - lastGeneration;
long remainingTimeForSolvingInMillis = Math.max(0, remainingTimeInMillis - 2*millisecondsNeededToWriteOut);
long remainingTimeForSolvingInMillis = Math.max(0, remainingTimeInMillis - millisecondsNeededToWriteOut);
// take twice the time to have buffer to write out solution afterwards
// start GLPK to solve the lp file just written, writing out the solution
Process process;
String command = "glpsol --lp " + lp.toAbsolutePath() +
// " -w " + solution.toAbsolutePath() +
" --tmlim " + remainingTimeForSolvingInMillis/1000 +
" --cuts" +
" -o " + solutionReadable.toAbsolutePath();
logger.debug("Call: '{}'", command);
String[] command = getCommand(lp, solutionReadable, remainingTimeForSolvingInMillis);
logger.debug("Call: '{}'", String.join(" ", command));
try {
process = Runtime.getRuntime().exec(command,null, new File("."));
} catch (IOException e) {
throw new SolvingException("Problem calling glpsol. Is it installed?", e);
throw new SolvingException("Problem calling solver. Is it installed?", e);
}
boolean finishedInTime;
try {
......@@ -149,71 +146,9 @@ public class ILPExternalSolver extends AbstractILPSolver {
return result.getObjective();
}
private static void readFromPlainTextSolution(ILP ilp, Path solution, ILPSolution result,
List<IlpVariable> variablesSetToOne) throws SolvingException {
List<String> varNamesSetToOne = new ArrayList<>();
String name = null;
int phase = 1;
try (Stream<String> lines = Files.lines(solution)) {
for (String line : lines.collect(Collectors.toList())) {
if (phase < 3) {
if (line.startsWith("Objective")) {
int equalsIndex = line.indexOf('=');
int bracketIndex = line.lastIndexOf('(');
result.setObjective(Double.valueOf(line.substring(equalsIndex + 1, bracketIndex).trim()));
}
if (line.startsWith("---")) {
phase += 1;
}
continue;
}
line = line.trim();
if (line.isEmpty()) {
continue;
}
String[] tokens = line.split("\\s+");
if (tokens.length == 6) {
// tokens: index, name, star, activity, lb, rb
if(Integer.valueOf(tokens[3]) == 1) {
varNamesSetToOne.add(tokens[1]);
}
phase = 3;
} else if (phase == 3) {
if(line.startsWith("Integer")) {
break;
}
// tokens: index, name
name = tokens[1];
phase = 4;
} else if (phase == 4) {
// tokens: star, activity, lb, rb
if (name == null) {
throw new SolvingException("Error in parsing solution. Name is null. Tokens: " + Arrays.toString(tokens));
}
if (Integer.valueOf(tokens[1]) == 1) {
varNamesSetToOne.add(name);
name = null;
}
phase = 3;
}
}
} catch (IOException e) {
throw new SolvingException("Could not open solution file", e);
} catch (NumberFormatException | IndexOutOfBoundsException e) {
throw new SolvingException("Could not parse solution file", e);
}
for (String varName : varNamesSetToOne) {
IlpVariable variable = ilp.resolve(varName);
if (variable == null) {
throw new SolvingException("Could not find variable with name " + varName);
}
variablesSetToOne.add(variable);
}
}
protected abstract void readFromPlainTextSolution(ILP ilp, Path solution, ILPSolution result,
List<IlpVariable> variablesSetToOne) throws SolvingException;
@Override
public String getName() {
return "ilp-external";
}
protected abstract String[] getCommand(Path lp, Path solution, long remainingTimeForSolvingInMillis);
}
......@@ -74,7 +74,7 @@ public class ILPMain {
}
private static void solveILPWithSolver(Root model) throws SolvingException {
ILPExternalSolver solver = new ILPExternalSolver();
ILPExternalSolver solver = new GLPKSolver().setDeleteFilesOnExit(false);
Solution solution = solver.solve(model);
System.out.println(solution);
}
......@@ -90,7 +90,7 @@ public class ILPMain {
System.out.println(version);
ScenarioGenerator gen = new ScenarioGenerator(new ScenarioDescription(1, 2, 0, 0, 0, 2, 2, 2.5, 3, 1, 0));
Root model = gen.generate();
Solver external = new ILPExternalSolver().setDeleteFilesOnExit(false);
Solver external = new GLPKSolver().setDeleteFilesOnExit(false);
Solution solution = external.solve(model);
logger.info(model.print(new MquatWriteSettings(" ")));
solution.explain();
......
package de.tudresden.inf.st.mquat.solving.ilp;
import de.tudresden.inf.st.mquat.jastadd.model.ILP;
import de.tudresden.inf.st.mquat.jastadd.model.IlpVariable;
import de.tudresden.inf.st.mquat.solving.SolvingException;
import org.apache.logging.log4j.LogManager;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class SCIPSolver extends ILPExternalSolver {
/**
* Create a new GLPK solver with default settings.
* Default is:
* <ul>
* <li>1 minute timeout</li>
* <li>delete temporary files on exit.</li>
* </ul>
* @see SCIPSolver#setDeleteFilesOnExit(boolean)
*/
public SCIPSolver() {
}
@Override
protected String[] getCommand(Path lp, Path solution, long remainingTimeForSolvingInMillis) {
String[] command = {"scip", "-c", "read " + lp.toAbsolutePath() + " set limit time " + remainingTimeForSolvingInMillis/1000 + " optimize write solution " + solution.toAbsolutePath() + " quit"};
return command;
}
@Override
protected void readFromPlainTextSolution(ILP ilp, Path solution, ILPSolution result,
List<IlpVariable> variablesSetToOne) throws SolvingException {
try (Stream<String> lines = Files.lines(solution)) {
for (String line : lines.collect(Collectors.toList())) {
if (line.startsWith("objective value:")) {
result.setObjective(Double.valueOf(line.substring(16).trim()));
logger.debug("read objective {}", Double.valueOf(line.substring(16).trim()));
} else if (line.startsWith("solution status:")) {
logger.debug("we got a solution status {}", line.substring(16).trim());
} else if (line.startsWith("no solution available")) {
logger.debug("no solution was found!");
return;
} else {
String[] tokens = line.split("\\s+");
if (tokens.length == 3) {
// tokens: name, value, objective
if (Math.round(Double.parseDouble(tokens[1])*1000000000)==1000000000) {
logger.debug("found new variable {} with value {}", tokens[0], tokens[1]);
IlpVariable variable = ilp.resolve(tokens[0]);
if (variable == null) {
throw new SolvingException("Could not find variable with name " + tokens[0]);
}
variablesSetToOne.add(variable);
}
}
}
}
} catch (IOException e) {
throw new SolvingException("Could not open solution file", e);
} catch (NumberFormatException e) {
throw new SolvingException("Could not parse solution file", e);
}
}
@Override
public String getName() {
return "ilp-scip";
}
}
package de.tudresden.inf.st.mquat.solving;
import de.tudresden.inf.st.mquat.solving.ilp.ILPExternalSolver;
import de.tudresden.inf.st.mquat.solving.ilp.GLPKSolver;
public class ILPExternalHandwrittenTest extends HandwrittenTestSuite {
public class GLPKHandwrittenTest extends HandwrittenTestSuite {
@Override
protected Solver getSolver() {
// set to false for debugging
return new ILPExternalSolver().setDeleteFilesOnExit(true);
return new GLPKSolver().setDeleteFilesOnExit(false);
}
}
......@@ -4,6 +4,7 @@ import de.tudresden.inf.st.mquat.generator.ScenarioDescription;
import de.tudresden.inf.st.mquat.generator.ScenarioGenerator;
import de.tudresden.inf.st.mquat.jastadd.model.Root;
import de.tudresden.inf.st.mquat.jastadd.model.Solution;
import de.tudresden.inf.st.mquat.solving.ilp.GLPKSolver;
import de.tudresden.inf.st.mquat.solving.ilp.ILPExternalSolver;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
......@@ -36,7 +37,7 @@ public class ILPObjectiveTest {
ScenarioGenerator generator = new ScenarioGenerator(new ScenarioDescription(tlc, iac, isd, cac, csd, dep, imp, res, req, cpu, seed));
Root model = generator.generate();
ILPExternalSolver solver = new ILPExternalSolver().setDeleteFilesOnExit(false);
ILPExternalSolver solver = new GLPKSolver().setDeleteFilesOnExit(false);
Solution solution = solver.solve(model);
Assert.assertTrue(solution.isValid());
logger.info("Solution (objective={}): {}", solution.computeObjective(), solution);
......
......@@ -2,6 +2,7 @@ package de.tudresden.inf.st.mquat.solving;
import de.tudresden.inf.st.mquat.data.TestGeneratorSettings;
import de.tudresden.inf.st.mquat.generator.ScenarioGenerator;
import de.tudresden.inf.st.mquat.solving.ilp.GLPKSolver;
import de.tudresden.inf.st.mquat.utils.TestUtils;
import de.tudresden.inf.st.mquat.jastadd.model.Root;
import de.tudresden.inf.st.mquat.jastadd.model.Solution;
......@@ -106,7 +107,7 @@ public class ILPSolveTest {
private Solver externalSolver() {
// set to false to analyse created temporary files
return new ILPExternalSolver().setDeleteFilesOnExit(true).setTimeout(10, TimeUnit.SECONDS);
return new GLPKSolver().setDeleteFilesOnExit(true).setTimeout(10, TimeUnit.SECONDS);
}
private Solver directSolver() {
......
package de.tudresden.inf.st.mquat.solving;
import de.tudresden.inf.st.mquat.solving.ilp.SCIPSolver;
public class SCIPHandwrittenTest extends HandwrittenTestSuite {
@Override
protected Solver getSolver() {
// set to false for debugging
return new SCIPSolver().setDeleteFilesOnExit(false);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment