more work on ModelBuilder java

This commit is contained in:
Laurent Perron
2022-04-03 23:22:02 +02:00
parent 7baa5626cf
commit f54350c578
8 changed files with 227 additions and 37 deletions

View File

@@ -275,6 +275,11 @@ test_java_linear_solver_samples: \
rjava_SimpleMipProgram \
rjava_StiglerDiet
.PHONY: test_java_model_builder_samples # Build and Run all Java MB Samples (located in ortools/model_builder/samples)
test_java_model_builder_samples: \
rjava_SimpleLpProgramMb \
rjava_SimpleMipProgramMb
.PHONY: test_java_sat_samples # Build and Run all Java SAT Samples (located in ortools/sat/samples)
test_java_sat_samples: \
rjava_AssignmentSat \
@@ -305,6 +310,7 @@ check_java: \
test_java_constraint_solver_samples \
test_java_graph_samples \
test_java_linear_solver_samples \
test_java_model_builder_samples \
test_java_sat_samples \
\
rjava_LinearProgramming \

View File

@@ -35,36 +35,36 @@ public class LinearConstraint {
return helper.getConstraintLowerBound(index);
}
/** Returns the upper bound of the variable. */
public double getUpperBound() {
return helper.getConstraintUpperBound(index);
}
/** Returns the name of the variable given upon creation. */
public String getName() {
return helper.getConstraintName(index);
}
/** Returns the lower bound of the variable. */
public void setLowerBound(double lb) {
helper.setConstraintLowerBound(index, lb);
}
/** Returns the upper bound of the variable. */
public double getUpperBound() {
return helper.getConstraintUpperBound(index);
}
/** Returns the upper bound of the variable. */
public void setUpperBound(double ub) {
helper.setConstraintUpperBound(index, ub);
}
/** Returns the name of the variable given upon creation. */
public String getName() {
return helper.getConstraintName(index);
}
// Sets the name of the variable. */
public void setName(String name) {
helper.setConstraintName(index, name);
}
// Adds var * coeff to the constraint.
public void addTerm(Variable var, double coeff) {
helper.addConstraintTerm(index, var.getIndex(), coeff);
}
/** Returns the name of the variable given upon creation. */
public void setName(String name) {
helper.setConstraintName(index, name);
}
/** Inline setter */
public LinearConstraint withName(String name) {
setName(name);

View File

@@ -184,6 +184,18 @@ public final class ModelBuilder {
helper.setMaximize(maximize);
}
// Model getters, import, export.
/** Returns the name of the model. */
public String getName() {
return helper.getName();
}
/** Sets the name of the model. */
public void setName(String name) {
helper.setName(name);
}
/**
* Write the model as a protocol buffer to 'file'.
*
@@ -191,10 +203,34 @@ public final class ModelBuilder {
* written as a text file, otherwise, the binary format will be used.
* @return true if the model was correctly written.
*/
public Boolean exportToFile(String file) {
public boolean exportToFile(String file) {
return helper.writeModelToFile(file);
}
public String exportToMpsString(boolean obfuscate) {
return helper.exportToMpsString(obfuscate);
}
public String exportToLpString(boolean obfuscate) {
return helper.exportToLpString(obfuscate);
}
public boolean importFromMpsString(String mpsString) {
return helper.importFromMpsString(mpsString);
}
public boolean importFromMpsFile(String mpsFile) {
return helper.importFromMpsString(mpsFile);
}
public boolean importFromLpString(String lpString) {
return helper.importFromLpString(lpString);
}
public boolean importFromLpFile(String lpFile) {
return helper.importFromMpsString(lpFile);
}
// Getters.
/** Returns the model builder helper. */
public ModelBuilderHelper getHelper() {

View File

@@ -13,6 +13,8 @@
package com.google.ortools.modelbuilder;
import java.util.function.Consumer;
/** Model solver class */
public final class ModelSolver {
static class ModelSolverException extends RuntimeException {
@@ -22,11 +24,15 @@ public final class ModelSolver {
}
}
/** Creates the solver with the supplied solver backend. */
public ModelSolver(String solverName) {
this.helper = new ModelSolverHelper(solverName);
this.logCallback = null;
}
/** Solves given model, and returns the status of the response. */
public SolveStatus solve(ModelBuilder model) {
helper.setLogCallback(logCallback);
helper.solve(model.getHelper());
if (!helper.hasResponse()) {
return SolveStatus.UNKNOWN_STATUS;
@@ -34,25 +40,100 @@ public final class ModelSolver {
return helper.getStatus();
}
public double objectiveValue() {
/** Enables or disables the underlying solver output. */
public void enableOutput(boolean enable) {
helper.enableOutput(enable);
}
/** Sets the time limit for the solve in seconds. */
public void setTimeLimitInSeconds(double limit) {
helper.setTimeLimitInSeconds(limit);
}
/** Sets solver specific parameters as string. */
public void setSolverSpecificParameters(String parameters) {
helper.setSolverSpecificParameters(parameters);
}
/** Returns whether solver specified during the ctor was found and correctly installed. */
public boolean solverIsSupported() {
return helper.solverIsSupported();
}
/** Tries to interrupt the solve. Returns true if the feature is supported. */
public boolean interruptSolve() {
return helper.interruptSolve();
}
/** Returns true if solve() was called, and a response was returned. */
public boolean hasResponse() {
return helper.hasResponse();
}
/** Returns true if solve() was called, and a solution was returned. */
public boolean hasSolution() {
return helper.hasSolution();
}
/** Checks that the solver has found a solution, and returns the objective value. */
public double getObjectiveValue() {
if (!helper.hasSolution()) {
throw new ModelSolverException(
"ModelSolver.objectiveValue()", "solve() was not called or no solution was found");
"ModelSolver.getObjectiveValue()", "solve() was not called or no solution was found");
}
return helper.getObjectiveValue();
}
public double value(Variable var) {
/** Checks that the solver has found a solution, and returns the objective value. */
public double getBestObjectiveBound() {
if (!helper.hasSolution()) {
throw new ModelSolverException(
"ModelSolver.value())", "solve() was not called or no solution was found");
"ModelSolver.getBestObjectiveBound()", "solve() was not called or no solution was found");
}
return helper.getBestObjectiveBound();
}
/** Checks that the solver has found a solution, and value of the given variable. */
public double getValue(Variable var) {
if (!helper.hasSolution()) {
throw new ModelSolverException(
"ModelSolver.getValue())", "solve() was not called or no solution was found");
}
return helper.getVariableValue(var.getIndex());
}
/** Checks that the solver has found a solution, and reduced cost of the given variable. */
public double getReducedCost(Variable var) {
if (!helper.hasSolution()) {
throw new ModelSolverException(
"ModelSolver.getReducedCost())", "solve() was not called or no solution was found");
}
return helper.getReducedCost(var.getIndex());
}
public double wallTime() {
/** Checks that the solver has found a solution, and dual value of the given constraint. */
public double getDualValue(LinearConstraint ct) {
if (!helper.hasSolution()) {
throw new ModelSolverException(
"ModelSolver.getDualValue())", "solve() was not called or no solution was found");
}
return helper.getDualValue(ct.getIndex());
}
/** Sets the log callback for the solver. */
public void setLogCallback(Consumer<String> cb) {
this.logCallback = cb;
}
/** Returns the elapsed time since the creation of the solver. */
public double getWallTime() {
return helper.getWallTime();
}
ModelSolverHelper helper;
/** Returns the user time since the creation of the solver. */
public double getUserTime() {
return helper.getUserTime();
}
private final ModelSolverHelper helper;
private Consumer<String> logCallback;
}

View File

@@ -45,14 +45,39 @@ public class Variable implements LinearArgument {
return helper.getVarLowerBound(index);
}
/** Sets the lower bound of the variable. */
public void setLowerBound(double lowerBound) {
helper.setVarLowerBound(index, lowerBound);
}
/** Returns the upper bound of the variable. */
public double getUpperBound() {
return helper.getVarUpperBound(index);
}
/** Sets the upper bound of the variable. */
public void setUpperBound(double upperBound) {
helper.setVarUpperBound(index, upperBound);
}
/** Returns whether the variable is integral. */
public boolean isIntegral() {
return helper.getVarIsIntegral(index);
public boolean getVarIntegrality() {
return helper.getVarIntegrality(index);
}
/** Sets the integrality of the variable. */
public void setVarIntegrality(boolean isIntegral) {
helper.setVarIntegrality(index, isIntegral);
}
/** Returns the objective coefficient of the variable. */
public double getObjectiveCoefficient() {
return helper.getVarObjectiveCoefficient(index);
}
/** Sets the objective coefficient of the variable in the objective. */
public void setObjectiveCoefficient(double objectiveCoefficient) {
helper.setVarObjectiveCoefficient(index, objectiveCoefficient);
}
/** Returns the name of the variable given upon creation. */
@@ -60,9 +85,8 @@ public class Variable implements LinearArgument {
return helper.getVarName(index);
}
/** Returns the objective coefficient of the variable. */
public double getObjectiveCoefficient() {
return helper.getVarObjectiveCoefficient(index);
public void setName(String name) {
helper.setVarName(index, name);
}
@Override

View File

@@ -29,6 +29,27 @@
// TODO(user): cleanup java/functions.i and move the code there.
%{
#include <memory> // std::make_shared<GlobalRefGuard>
/* Global JNI reference deleter. Instantiate it via std::make_shared<> */
class GlobalRefGuard {
JavaVM *jvm_;
jobject jref_;
// non-copyable
GlobalRefGuard(const GlobalRefGuard &) = delete;
GlobalRefGuard &operator=(const GlobalRefGuard &) = delete;
public:
GlobalRefGuard(JavaVM *jvm, jobject jref): jvm_(jvm), jref_(jref) {}
~GlobalRefGuard() {
JNIEnv *jenv = NULL;
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_2;
args.name = NULL;
args.group = NULL;
jvm_->AttachCurrentThread((void**)&jenv, &args);
jenv->DeleteGlobalRef(jref_);
jvm_->DetachCurrentThread();
}
};
%}
%typemap(in) std::function<void(const std::string&)> %{
@@ -65,6 +86,20 @@
%typemap(jstype) std::function<void(const std::string&)> "java.util.function.Consumer<String>" // Type used in the Proxy class.
%typemap(javain) std::function<void(const std::string&)> "$javainput" // passing the Callback to JNI java class.
%extend operations_research::ModelBuilderHelper {
std::string exportToMpsString(bool obfuscate) {
operations_research::MPModelExportOptions options;
options.obfuscate = obfuscate;
return $self->ExportToMpsString(options);
}
std::string exportToLpString(bool obfuscate) {
operations_research::MPModelExportOptions options;
options.obfuscate = obfuscate;
return $self->ExportToLpString(options);
}
} // Extend operations_research::ModelBuilderHelper
%ignoreall
%unignore operations_research;
@@ -76,7 +111,7 @@
// Var API.
%rename (addVar) operations_research::ModelBuilderHelper::AddVar;
%rename (getVarIsIntegral) operations_research::ModelBuilderHelper::VarIsIntegral;
%rename (getVarIntegrality) operations_research::ModelBuilderHelper::VarIsIntegral;
%rename (getVarLowerBound) operations_research::ModelBuilderHelper::VarLowerBound;
%rename (getVarName) operations_research::ModelBuilderHelper::VarName;
%rename (getVarObjectiveCoefficient) operations_research::ModelBuilderHelper::VarObjectiveCoefficient;
@@ -116,11 +151,14 @@
%rename (importFromMpsFile) operations_research::ModelBuilderHelper::ImportFromMpsFile;
%rename (importFromLpString) operations_research::ModelBuilderHelper::ImportFromLpString;
%rename (importFromLpFile) operations_research::ModelBuilderHelper::ImportFromLpFile;
%unignore operations_research::ModelBuilderHelper::exportToMpsString;
%unignore operations_research::ModelBuilderHelper::exportToLpString;
%unignore operations_research::ModelSolverHelper;
%unignore operations_research::ModelSolverHelper::ModelSolverHelper(const std::string&);
%rename (solverIsSupported) operations_research::ModelSolverHelper::solverIsSupported;
%rename (solverIsSupported) operations_research::ModelSolverHelper::SolverIsSupported;
%rename (solve) operations_research::ModelSolverHelper::Solve;
%rename (interruptSolve) operations_research::ModelSolverHelper::InterruptSolve;
%rename (hasResponse) operations_research::ModelSolverHelper::has_response;
%rename (hasSolution) operations_research::ModelSolverHelper::has_solution;
%rename (getStatus) operations_research::ModelSolverHelper::status;
@@ -131,7 +169,11 @@
%rename (getDualValue) operations_research::ModelSolverHelper::dual_value;
%rename (getStatusString) operations_research::ModelSolverHelper::status_string;
%rename (getWallTime) operations_research::ModelSolverHelper::wall_time;
%rename (getUserTime) operations_research::ModelSolverHelper::user_time;
%rename (enableOutput) operations_research::ModelSolverHelper::EnableOutput;
%rename (setLogCallback) operations_research::ModelSolverHelper::SetLogCallback;
%rename (setTimeLimitInSeconds) operations_research::ModelSolverHelper::SetTimeLimitInSeconds;
%rename (setSolverSpecificParameters) operations_research::ModelSolverHelper::SetSolverSpecificParameters;
%unignore operations_research::SolveStatus;
%unignore operations_research::OPTIMAL;

View File

@@ -66,9 +66,9 @@ public final class SimpleLpProgramMb {
// [START print_solution]
if (status == SolveStatus.OPTIMAL) {
System.out.println("Solution:");
System.out.println("Objective value = " + solver.objectiveValue());
System.out.println("x = " + solver.value(x));
System.out.println("y = " + solver.value(y));
System.out.println("Objective value = " + solver.getObjectiveValue());
System.out.println("x = " + solver.getValue(x));
System.out.println("y = " + solver.getValue(y));
} else {
System.err.println("The problem does not have an optimal solution!");
}
@@ -76,7 +76,7 @@ public final class SimpleLpProgramMb {
// [START advanced]
System.out.println("\nAdvanced usage:");
System.out.println("Problem solved in " + solver.wallTime() + " milliseconds");
System.out.println("Problem solved in " + solver.getWallTime() + " seconds");
// [END advanced]
}

View File

@@ -65,9 +65,9 @@ public final class SimpleMipProgramMb {
// [START print_solution]
if (status == SolveStatus.OPTIMAL) {
System.out.println("Solution:");
System.out.println("Objective value = " + solver.objectiveValue());
System.out.println("x = " + solver.value(x));
System.out.println("y = " + solver.value(y));
System.out.println("Objective value = " + solver.getObjectiveValue());
System.out.println("x = " + solver.getValue(x));
System.out.println("y = " + solver.getValue(y));
} else {
System.err.println("The problem does not have an optimal solution!");
}
@@ -75,7 +75,8 @@ public final class SimpleMipProgramMb {
// [START advanced]
System.out.println("\nAdvanced usage:");
System.out.println("Problem solved in " + solver.wallTime() + " milliseconds");
System.out.println("Problem solved in " + solver.getWallTime() + " seconds");
// [END advanced]
}
private SimpleMipProgramMb() {}