Commit 9f2b6c43 authored by Christoph Richter's avatar Christoph Richter
Browse files

Several Enhancements

parent de0c23d3
......@@ -23,9 +23,9 @@ public class GeneratorEMAMOpt2CPP extends GeneratorCPP implements GeneratorImpl
// fields
private OptimizationSymbolHandler executeMethodGeneratorOpt = new OptimizationSymbolHandler();
private MathOptFunctionFixer mathOptFunctionFixer = new MathOptFunctionFixer();
private Solver preferedSolver = Solver.Ipopt;
private Solver preferedSolver = Solver.none;
private boolean forceUsePreferredSolver = false;
private SolverOptions solverOptions;
private SolverOptions solverOptions = new SolverOptions();
public GeneratorEMAMOpt2CPP() {
super();
......@@ -39,7 +39,6 @@ public class GeneratorEMAMOpt2CPP extends GeneratorCPP implements GeneratorImpl
// extend ExecuteMethodGenerator
executeMethodGeneratorOpt.setSuccessor(ExecuteMethodGenerator.getInstance());
mathOptFunctionFixer.setSuccessor(MathFunctionFixer.getInstance());
setPreferedSolver(Solver.Ipopt);
}
@Override
......@@ -70,8 +69,6 @@ public class GeneratorEMAMOpt2CPP extends GeneratorCPP implements GeneratorImpl
public void setPreferedSolver(Solver preferedSolver) {
this.preferedSolver = preferedSolver;
if (preferedSolver == Solver.Ipopt)
solverOptions = SolverOptions.getIpoptDefaultOptions();
}
public SolverOptions getSolverOptions() {
......
......@@ -2,5 +2,6 @@ package de.monticore.lang.monticar.generator.cpp.optimizationSolver.solver;
public enum Solver {
Ipopt,
Cplex;
Cplex,
none;
}
......@@ -9,7 +9,7 @@ public class SolverOptions extends HashMap<String, String> {
public static SolverOptions getIpoptDefaultOptions() {
SolverOptions result = new SolverOptions();
result.solver = Solver.Ipopt;
result.put("Integer print_level", "3");
result.put("Integer print_level", "1");
result.put("String sb", "yes");
result.put("Integer max_iter", "500");
result.put("Numeric tol", "1e-6");
......
......@@ -2,6 +2,7 @@ package de.monticore.lang.monticar.generator.cpp.optimizationSolver.solver.cplex
import de.monticore.lang.monticar.generator.FileContent;
import de.monticore.lang.monticar.generator.Generator;
import de.monticore.lang.monticar.generator.cmake.CMakeConfig;
import de.monticore.lang.monticar.generator.cmake.CMakeFindModule;
import de.monticore.lang.monticar.generator.cpp.BluePrintCPP;
import de.monticore.lang.monticar.generator.cpp.GeneratorEMAMOpt2CPP;
......@@ -10,7 +11,6 @@ import de.monticore.lang.monticar.generator.cpp.optimizationSolver.problem.Probl
import de.monticore.lang.monticar.generator.cpp.optimizationSolver.problem.QPProblem;
import de.monticore.lang.monticar.generator.cpp.optimizationSolver.solver.MIQPSolverGeneratorImplementation;
import de.monticore.lang.monticar.generator.cpp.optimizationSolver.solver.QPSolverGeneratorImplementation;
import de.monticore.lang.monticar.generator.cpp.optimizationSolver.solver.ipopt.IpoptViewModel;
import de.monticore.lang.monticar.generator.cpp.template.AllTemplates;
import de.monticore.lang.monticar.generator.cpp.template.TemplateHelper;
import de.se_rwth.commons.logging.Log;
......@@ -18,9 +18,7 @@ import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
......@@ -32,6 +30,7 @@ public class CplexSolverGeneratorImplementation implements QPSolverGeneratorImpl
// static templates
private static final Template CALL_CPLEX_H;
private static final Template CPLEXMAT_H;
static {
Configuration conf = new Configuration(Configuration.VERSION_2_3_23);
......@@ -42,8 +41,9 @@ public class CplexSolverGeneratorImplementation implements QPSolverGeneratorImpl
conf.setNumberFormat("0.####E0");
try {
CALL_CPLEX_H = conf.getTemplate("CallCplexTemplate_HeaderOnly.ftl");
CPLEXMAT_H = conf.getTemplate("CplexMat.h");
} catch (IOException e) {
String msg = "could not load ipopt templates";
String msg = "could not load cplex templates";
Log.error(msg, e);
throw new RuntimeException(msg, e);
}
......@@ -98,8 +98,9 @@ public class CplexSolverGeneratorImplementation implements QPSolverGeneratorImpl
CALL_CPLEX_H.process(dataForTemplate, sw);
auxiliaryFiles.add(new FileContent(sw.toString(), "/" + viewModel.getCallSolverName() + ".h"));
// add matrix type
File sourceFile = new File("src/main/resources/template/optimizationSolver/cplex/CplexMat.h");
auxiliaryFiles.add(new FileContent(FileUtils.readFileToString(sourceFile), "/" + sourceFile.getName()));
sw = new StringWriter();
CPLEXMAT_H.process(dataForTemplate, sw);
auxiliaryFiles.add(new FileContent(sw.toString(), "/" + "CplexMat.h"));
} catch (TemplateException | IOException e) {
Log.error("CPLEX template generation failed. ", e);
}
......@@ -108,16 +109,23 @@ public class CplexSolverGeneratorImplementation implements QPSolverGeneratorImpl
protected void addCMakeDependenciesToGenerator(BluePrintCPP bluePrint) {
Generator gen = bluePrint.getGenerator();
if (gen instanceof GeneratorEMAMOpt2CPP) {
CMakeConfig cmake = ((GeneratorEMAMOpt2CPP) gen).getCMakeConfig();
List<CMakeFindModule> dependencies = getCMakeDependencies();
for (CMakeFindModule dep : dependencies)
((GeneratorEMAMOpt2CPP) gen).getCMakeConfig().addModuleDependency(dep);
cmake.addModuleDependency(dep);
// additional commands
cmake.addCMakeCommand("find_package(Threads REQUIRED)");
cmake.addCMakeCommand("set(LIBS ${LIBS} ${CMAKE_THREAD_LIBS_INIT})");
cmake.addCMakeCommand("set(LIBS ${LIBS} ${CMAKE_DL_LIBS})");
cmake.addCMakeCommand("set( CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -DIL_STD -Wno-deprecated\" )");
}
}
public List<CMakeFindModule> getCMakeDependencies() {
CMakeFindModule findIloCplex = new CMakeFindModule("ILOCPLEX", "ilocplex", "ilocplex", new ArrayList<String>(), new ArrayList<String>(), true, true, true);
CMakeFindModule findConcert = new CMakeFindModule("CONCERT", "ilomodel", "concert", new ArrayList<String>(), new ArrayList<String>(), true, true, true);
CMakeFindModule findCplex = new CMakeFindModule("CPLEX", "", "cplex", new ArrayList<String>(), new ArrayList<String>(), false, true, true);
return Arrays.asList(findIloCplex, findConcert, findCplex);
CMakeFindModule findIloCplex = new CMakeFindModule("ILOCPLEX", "ilcplex/ilocplex.h", "ilocplex", Arrays.asList("C:/Program Files/IBM/ILOG/CPLEX_Studio128/cplex/include", "/opt/ibm/ILOG/CPLEX_Studio128/cplex/include"), Arrays.asList("C:/Program Files/IBM/ILOG/CPLEX_Studio128/cplex/lib/x64_windows_vs2017/stat_mda", "/opt/ibm/ILOG/CPLEX_Studio128/cplex/lib/x86-64_linux/static_pic"), true, true, true);
CMakeFindModule findConcert = new CMakeFindModule("CONCERT", "ilconcert/ilomodel.h", "concert", Arrays.asList("C:/Program Files/IBM/ILOG/CPLEX_Studio128/concert/include", "/opt/ibm/ILOG/CPLEX_Studio128/concert/include"), Arrays.asList("C:/Program Files/IBM/ILOG/CPLEX_Studio128/concert/lib/x64_windows_vs2017/stat_mda", "/opt/ibm/ILOG/CPLEX_Studio128/concert/lib/x86-64_linux/static_pic"), true, true, true);
CMakeFindModule findCplex = new CMakeFindModule("CPLEX", "", "cplex", new ArrayList<String>(), Arrays.asList("C:/Program Files/IBM/ILOG/CPLEX_Studio128/cplex/lib/x64_windows_vs2017/stat_mda", "/opt/ibm/ILOG/CPLEX_Studio128/cplex/lib/x86-64_linux/static_pic"), false, true, true);
CMakeFindModule findM = new CMakeFindModule("M", "math.h", "m", new ArrayList<String>(), new ArrayList<String>(), true, true, true);
return Arrays.asList(findIloCplex, findConcert, findCplex, findM);
}
}
......@@ -30,31 +30,36 @@ public class SolverGeneratorFactory {
*/
public SolverGenerator createPreferredSolverForProblem(Problem problem, Solver preferredSolver, boolean forceUsePreferredSolver) {
SolverGenerator result = createDefaultSolverForProblem(problem);
if (preferredSolver == Solver.Ipopt) {
if (problem instanceof DNLPProblem || forceUsePreferredSolver) {
NLPSolverGeneratorImplementation impl = new IpoptSolverGeneratorImplementation();
result = new NLPSolverGenerator(impl);
if (!(problem instanceof DNLPProblem))
Log.warn(String.format("Prefered solver Ipopt can not handle problem of type %s.", problem.getClass().toString()));
} else {
Log.warn(String.format("Prefered solver Ipopt can not handle problem of type %s. Default solver will be returned instead.", problem.getClass().toString()));
}
} else if (preferredSolver == Solver.Cplex) {
if (problem instanceof MIQPProblem) {
MIQPSolverGeneratorImplementation impl = new CplexSolverGeneratorImplementation();
result = new MIQPSolverGenerator(impl);
} else if (problem instanceof QPProblem || forceUsePreferredSolver) {
QPSolverGeneratorImplementation impl = new CplexSolverGeneratorImplementation();
result = new QPSolverGenerator(impl);
if (!(problem instanceof DNLPProblem))
Log.warn(String.format("Prefered solver CPLEX can not handle problem of type %s.", problem.getClass().toString()));
} else {
Log.warn(String.format("Prefered solver CPLEX can not handle problem of type %s. Default solver will be returned instead.", problem.getClass().toString()));
}
} else {
Log.warn(String.format("Prefered solver %s not found. Default solver will be returned instead.", preferredSolver.toString()));
switch (preferredSolver) {
case Ipopt:
if (problem instanceof DNLPProblem || forceUsePreferredSolver) {
NLPSolverGeneratorImplementation impl = new IpoptSolverGeneratorImplementation();
result = new NLPSolverGenerator(impl);
if (!(problem instanceof DNLPProblem))
Log.warn(String.format("Prefered solver Ipopt can not handle problem of type %s.", problem.getClass().toString()));
} else {
Log.warn(String.format("Prefered solver Ipopt can not handle problem of type %s. Default solver will be returned instead.", problem.getClass().toString()));
}
break;
case Cplex:
if (problem instanceof MIQPProblem) {
MIQPSolverGeneratorImplementation impl = new CplexSolverGeneratorImplementation();
result = new MIQPSolverGenerator(impl);
} else if (problem instanceof QPProblem || forceUsePreferredSolver) {
QPSolverGeneratorImplementation impl = new CplexSolverGeneratorImplementation();
result = new QPSolverGenerator(impl);
if (!(problem instanceof DNLPProblem))
Log.warn(String.format("Prefered solver CPLEX can not handle problem of type %s.", problem.getClass().toString()));
} else {
Log.warn(String.format("Prefered solver CPLEX can not handle problem of type %s. Default solver will be returned instead.", problem.getClass().toString()));
}
break;
case none:
break;
default:
Log.warn(String.format("Prefered solver %s not found. Default solver will be returned instead.", preferredSolver.toString()));
break;
}
return result;
}
......
......@@ -17,9 +17,7 @@ import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
......@@ -33,6 +31,7 @@ import java.util.Map;
public class IpoptSolverGeneratorImplementation implements NLPSolverGeneratorImplementation {
private static final Template CALL_IPOPT_HPP;
private static final Template ADMAT_H;
static {
Configuration conf = new Configuration(Configuration.VERSION_2_3_23);
......@@ -43,6 +42,7 @@ public class IpoptSolverGeneratorImplementation implements NLPSolverGeneratorImp
conf.setNumberFormat("0.####E0");
try {
CALL_IPOPT_HPP = conf.getTemplate("CallIpoptTemplate_HeaderOnly.ftl");
ADMAT_H = conf.getTemplate("ADMat.h");
} catch (IOException e) {
String msg = "could not load ipopt templates";
Log.error(msg, e);
......@@ -65,7 +65,8 @@ public class IpoptSolverGeneratorImplementation implements NLPSolverGeneratorImp
if ((optimizationProblem instanceof NLPProblem) || (optimizationProblem instanceof DNLPProblem)) {
// create view model from problem class
IpoptViewModel vm = new IpoptViewModel(optimizationProblem);
SolverOptions options = generator.getSolverOptions();
SolverOptions options = SolverOptions.getIpoptDefaultOptions();
options.putAll(generator.getSolverOptions());
// retape if DNLP
if (optimizationProblem instanceof DNLPProblem)
options.put("Retape", "true");
......@@ -111,8 +112,9 @@ public class IpoptSolverGeneratorImplementation implements NLPSolverGeneratorImp
CALL_IPOPT_HPP.process(dataForTemplate, sw);
auxillaryFiles.add(new FileContent(sw.toString(), "/" + viewModel.getCallSolverName() + ".h"));
// add matrix type
File sourceFile = new File("src/main/resources/template/optimizationSolver/ipopt/ADMat.h");
auxillaryFiles.add(new FileContent(FileUtils.readFileToString(sourceFile), "/" + sourceFile.getName()));
sw = new StringWriter();
ADMAT_H.process(dataForTemplate, sw);
auxillaryFiles.add(new FileContent(sw.toString(), "/" + "ADMat.h"));
} catch (TemplateException | IOException e) {
Log.error("Ipopt template generation failed. ", e);
}
......
#ifndef __${viewModel.callSolverName?upper_case}_H__
#define __${viewModel.callSolverName?upper_case}_H__
#include
<ilcplex/ilocplex.h>
#include <ilcplex/ilocplex.h>
#include "armadillo.h"
#include "CplexMat.h"
......@@ -11,46 +10,75 @@ class ${viewModel.callSolverName}
{
private:
<#list viewModel.knownVariablesWithType as var>
static ${var};
</#list>
static IloNumExprArg toScalar(const CplexMat &value) { return value.at(0);}
IloNumExprArg toScalar(const CplexMat &value) { return value.at(0);}
static IloNumExprArg toScalar(const IloNumExprArg &value) { return value;}
IloNumExprArg toScalar(const CplexMat &value) { return value;}
static void addConstraint(IloRangeArray &con${viewModel.id}, const double &lower, const IloNumExprArg &expr, const double &upper) {
con${viewModel.id}.add(lower <= expr <= upper);
};
static void
populatebyrow(IloModel model, IloNumVarArray x, IloRangeArray c)
{
IloEnv env = model.getEnv();
static void addConstraint(IloRangeArray &con${viewModel.id}, const double &lower, const CplexMat &expr, const double &upper) {
for (int i = 0; i < expr.size(); i++) {
con${viewModel.id}.add(lower <= expr[i] <= upper);
}
};
<#list viewModel.xL as xl>
x.add(IloNumVar(env, xl, viewModel.xU[xl?index]));
</#list>
static void addConstraint(IloRangeArray &con${viewModel.id}, const double &lower, const CplexMat &expr, const mat &upper) {
assert(expr.size() == upper.size());
for (int i = 0; i < expr.size(); i++) {
con${viewModel.id}.add(lower <= expr[i] <= upper[i]);
}
};
// create active optimization var
<#if viewModel.optimizationVariableDimensions?size == 0>
${viewModel.optimizationVariableTypeActive} ${viewModel.optimizationVariableName} = x[0];
<#else>
${viewModel.optimizationVariableTypeActive} ${viewModel.optimizationVariableName} = ${viewModel.optimizationVariableTypeActive}(<#list viewModel.optimizationVariableDimensions as dim>${dim}<#sep>, </#list>);
for (int i${viewModel.id} = 0; i${viewModel.id} < x.size(); i${viewModel.id}++)
{
${viewModel.optimizationVariableName}(i${viewModel.id}) = x[i${viewModel.id}];
static void addConstraint(IloRangeArray &con${viewModel.id}, const mat &lower, const CplexMat &expr, const double &upper) {
assert(lower.size() == expr.size());
for (int i = 0; i < expr.size(); i++) {
con${viewModel.id}.add(lower[i] <= expr[i] <= upper);
}
</#if>
};
<#if viewModel.optimizationProblemType.name() == "MINIMIZATION">
model.add(IloMinimize(env, toScalar(${viewModel.objectiveFunction}));
<#else>
model.add(IloMaximize(env, toScalar(${viewModel.objectiveFunction}));
</#if>
static void addConstraint(IloRangeArray &con${viewModel.id}, const mat &lower, const CplexMat &expr, const mat &upper) {
assert(lower.size() == expr.size());
assert(expr.size() == upper.size());
for (int i = 0; i < expr.size(); i++) {
con${viewModel.id}.add(lower[i] <= expr[i] <= upper[i]);
}
};
<#list viewModel.constraintFunctions as g>
c.add(${viewModel.gL[g?index]} <= ${g} <= ${viewModel.gU[g?index]});
</#list>
static void addConstraint(IloRangeArray &con${viewModel.id}, const double &lower, const arma::subview_field<IloNumExprArg> &expr, const double &upper) {
for (int i = 0; i < expr.n_rows; i++) {
for (int j = 0; j < expr.n_cols; j++) {
con${viewModel.id}.add(lower <= expr[i, j] <= upper);
}
}
};
static void addConstraint(IloRangeArray &con${viewModel.id}, const mat &lower, const arma::subview_field<IloNumExprArg> &expr, const double &upper) {
assert(lower.n_cols == expr.n_cols);
assert(lower.n_rows == expr.n_rows);
for (int i = 0; i < expr.n_rows; i++) {
for (int j = 0; j < expr.n_cols; j++) {
con${viewModel.id}.add(lower[i, j] <= expr[i, j] <= upper);
}
}
};
static void addConstraint(IloRangeArray &con${viewModel.id}, const double &lower, const arma::subview_field<IloNumExprArg> &expr, const mat &upper) {
for (int i = 0; i < expr.n_rows; i++) {
for (int j = 0; j < expr.n_cols; j++) {
con${viewModel.id}.add(lower <= expr[i, j] <= upper[i, j]);
}
}
};
model.add(c);
}; // END populatebyrow
static void addConstraint(IloRangeArray &con${viewModel.id}, const mat &lower, const arma::subview_field<IloNumExprArg> &expr, const mat &upper) {
for (int i = 0; i < expr.n_rows; i++) {
for (int j = 0; j < expr.n_cols; j++) {
con${viewModel.id}.add(lower[i, j] <= expr[i, j] <= upper[i, j]);
}
}
};
public:
static bool solveOptimizationProblemCplex(
......@@ -61,19 +89,35 @@ class ${viewModel.callSolverName}
</#list>
)
{
// assign parameter variables
<#list viewModel.knownVariables as var>
${viewModel.callSolverName}::${var} = ${var};
</#list>
ILOSTLBEGIN
IloEnv env;
try {
IloModel model(env);
IloNumVarArray var(env);
IloRangeArray con(env);
populatebyrow(model, var, con);
IloNumVarArray var${viewModel.id}(env);
IloRangeArray con${viewModel.id}(env);
IloEnv env = model.getEnv();
<#list viewModel.xL as xl>
var${viewModel.id}.add(IloNumVar(env, ${xl}, ${viewModel.xU[xl?index]}));
</#list>
// create active optimization var
<#if viewModel.optimizationVariableDimensions?size == 0>
${viewModel.optimizationVariableTypeActive} ${viewModel.optimizationVariableName} = var${viewModel.id}[0];
<#else>
${viewModel.optimizationVariableTypeActive} ${viewModel.optimizationVariableName} = ${viewModel.optimizationVariableTypeActive}(<#list viewModel.optimizationVariableDimensions as dim>${dim}<#sep>, </#list>);
for (int i${viewModel.id} = 0; i${viewModel.id} < var${viewModel.id}.getSize(); i${viewModel.id}++)
{
${viewModel.optimizationVariableName}(i${viewModel.id}) = var${viewModel.id}[i${viewModel.id}];
}
</#if>
<#if viewModel.optimizationProblemType.name() == "MINIMIZATION">
model.add(IloMinimize(env, toScalar(${viewModel.objectiveFunction})));
<#else>
model.add(IloMaximize(env, toScalar(${viewModel.objectiveFunction})));
</#if>
<#list viewModel.constraintFunctions as g>
addConstraint(con${viewModel.id}, ${viewModel.gL[g?index]}, ${g}, ${viewModel.gU[g?index]});
</#list>
model.add(con${viewModel.id});
IloCplex cplex(model);
cplex.solve();
......@@ -82,9 +126,9 @@ class ${viewModel.callSolverName}
env.out() << "Solution value = " << cplex.getObjValue() << endl;
IloNumArray vals(env);
cplex.getValues(vals, var);
cplex.getValues(vals, var${viewModel.id});
env.out() << "Values = " << vals << endl;
cplex.getSlacks(vals, con);
cplex.getSlacks(vals, con${viewModel.id});
env.out() << "Slacks = " << vals << endl;
cplex.exportModel("mipex1.lp");
......
......@@ -25,7 +25,7 @@ public class AutopilotMPCTest {
if (gen instanceof GeneratorEMAMOpt2CPP) {
GeneratorEMAMOpt2CPP emamoptGen = ((GeneratorEMAMOpt2CPP) gen);
emamoptGen.setGenerateAutopilotAdapter(true);
emamoptGen.setGenerateServerWrapper(true);
emamoptGen.setGenerateServerWrapper(false);
}
}
generator.setGenerationTargetPath("./target/generated-sources-cmake/AutopilotMPCKindematicBycycle/src/");
......
Supports Markdown
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