incomplete ModelBuilder java implementation

This commit is contained in:
Laurent Perron
2022-04-02 23:28:05 +02:00
parent 591f255052
commit 0223b492b3
15 changed files with 1129 additions and 1 deletions

View File

@@ -149,7 +149,7 @@ endif()
set(JAVA_SRC_PATH src/main/java/${JAVA_DOMAIN_EXTENSION}/${JAVA_DOMAIN_NAME}/${JAVA_ARTIFACT})
set(JAVA_TEST_PATH src/test/java/${JAVA_DOMAIN_EXTENSION}/${JAVA_DOMAIN_NAME}/${JAVA_ARTIFACT})
set(JAVA_RESSOURCES_PATH src/main/resources)
foreach(SUBPROJECT IN ITEMS algorithms graph init linear_solver constraint_solver sat util)
foreach(SUBPROJECT IN ITEMS algorithms graph init linear_solver model_builder constraint_solver sat util)
add_subdirectory(ortools/${SUBPROJECT}/java)
target_link_libraries(jni${JAVA_ARTIFACT} PRIVATE jni${SUBPROJECT})
endforeach()

View File

@@ -0,0 +1,60 @@
// Copyright 2010-2021 Google LLC
// 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 com.google.ortools.modelbuilder;
/** A specialized linear expression: a * x + b */
public final class AffineExpression implements LinearExpr {
private final int varIndex;
private final double coefficient;
private final double offset;
public AffineExpression(int varIndex, double coefficient, double offset) {
this.varIndex = varIndex;
this.coefficient = coefficient;
this.offset = offset;
}
// LinearArgument interface.
@Override
public LinearExpr build() {
return this;
}
// LinearExpr interface.
@Override
public int numElements() {
return 1;
}
@Override
public int getVariableIndex(int index) {
if (index != 0) {
throw new IllegalArgumentException("wrong index in LinearExpr.getIndex(): " + index);
}
return varIndex;
}
@Override
public double getCoefficient(int index) {
if (index != 0) {
throw new IllegalArgumentException("wrong index in LinearExpr.getCoefficient(): " + index);
}
return coefficient;
}
@Override
public double getOffset() {
return offset;
}
}

View File

@@ -0,0 +1,55 @@
// Copyright 2010-2021 Google LLC
// 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 com.google.ortools.modelbuilder;
/** A specialized constant linear expression. */
public final class ConstantExpression implements LinearExpr {
private final double offset;
public ConstantExpression(double offset) {
this.offset = offset;
}
// LinearArgument interface.
@Override
public LinearExpr build() {
return this;
}
// LinearExpr interface.
@Override
public int numElements() {
return 0;
}
@Override
public int getVariableIndex(int index) {
throw new IllegalArgumentException("wrong index in LinearExpr.getVariable(): " + index);
}
@Override
public double getCoefficient(int index) {
throw new IllegalArgumentException("wrong index in LinearExpr.getCoefficient(): " + index);
}
@Override
public double getOffset() {
return offset;
}
@Override
public String toString() {
return String.format("%f", offset);
}
}

View File

@@ -0,0 +1,24 @@
// Copyright 2010-2021 Google LLC
// 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 com.google.ortools.modelbuilder;
/**
* A object that can build a LinearExpr object.
*
* <p>This class is used in all modeling methods of the CpModel class.
*/
public interface LinearArgument {
/** Builds a linear expression. */
LinearExpr build();
}

View File

@@ -0,0 +1,76 @@
// Copyright 2010-2021 Google LLC
// 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 com.google.ortools.modelbuilder;
/** Wrapper around a linear constraint stored in the ModelBuilderHelper instance. */
public class LinearConstraint {
public LinearConstraint(ModelBuilderHelper helper) {
this.helper = helper;
this.index = helper.addLinearConstraint();
}
/** Returns the index of the constraint in the model. */
public int getIndex() {
return index;
}
/** Returns the constraint builder. */
public ModelBuilderHelper getHelper() {
return helper;
}
/** Returns the lower bound of the variable. */
public double getLowerBound() {
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 void setUpperBound(double ub) {
helper.setConstraintUpperBound(index, ub);
}
// 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);
return this;
}
private final ModelBuilderHelper helper;
private final int index;
}

View File

@@ -0,0 +1,59 @@
// Copyright 2010-2021 Google LLC
// 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 com.google.ortools.modelbuilder;
/** A linear expression (sum (ai * xi) + b). It specifies methods to help parsing the expression. */
public interface LinearExpr extends LinearArgument {
/** Returns the number of terms (excluding the constant one) in this expression. */
int numElements();
/** Returns the index of the ith variable. */
int getVariableIndex(int index);
/** Returns the ith coefficient. */
double getCoefficient(int index);
/** Returns the constant part of the expression. */
double getOffset();
/** Returns a builder */
static LinearExprBuilder newBuilder() {
return new LinearExprBuilder();
}
/** Shortcut for newBuilder().add(value).build() */
static LinearExpr constant(double value) {
return newBuilder().add(value).build();
}
/** Shortcut for newBuilder().addTerm(expr, coeff).build() */
static LinearExpr term(LinearArgument expr, double coeff) {
return newBuilder().addTerm(expr, coeff).build();
}
/** Shortcut for newBuilder().addTerm(expr, coeff).add(offset).build() */
static LinearExpr affine(LinearArgument expr, double coeff, double offset) {
return newBuilder().addTerm(expr, coeff).add(offset).build();
}
/** Shortcut for newBuilder().addSum(exprs).build() */
static LinearExpr sum(LinearExpr[] exprs) {
return newBuilder().addSum(exprs).build();
}
/** Shortcut for newBuilder().addWeightedSum(exprs, coeffs).build() */
static LinearExpr weightedSum(LinearArgument[] exprs, double[] coeffs) {
return newBuilder().addWeightedSum(exprs, coeffs).build();
}
}

View File

@@ -0,0 +1,107 @@
// Copyright 2010-2021 Google LLC
// 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 com.google.ortools.modelbuilder;
import java.util.Map;
import java.util.TreeMap;
/** Builder class for the LinearExpr container. */
public final class LinearExprBuilder implements LinearArgument {
private final TreeMap<Integer, Double> coefficients;
private double offset;
LinearExprBuilder() {
this.coefficients = new TreeMap<>();
this.offset = 0;
}
public LinearExprBuilder add(LinearArgument expr) {
addTerm(expr, 1);
return this;
}
public LinearExprBuilder add(double constant) {
offset = offset + constant;
return this;
}
public LinearExprBuilder addTerm(LinearArgument expr, double coeff) {
final LinearExpr e = expr.build();
final int numElements = e.numElements();
for (int i = 0; i < numElements; ++i) {
coefficients.merge(e.getVariableIndex(i), e.getCoefficient(i) * coeff, Double::sum);
}
offset = offset + e.getOffset() * coeff;
return this;
}
public LinearExprBuilder addSum(LinearArgument[] exprs) {
for (final LinearArgument expr : exprs) {
addTerm(expr, 1);
}
return this;
}
public LinearExprBuilder addWeightedSum(LinearArgument[] exprs, double[] coeffs) {
for (int i = 0; i < exprs.length; ++i) {
addTerm(exprs[i], coeffs[i]);
}
return this;
}
public LinearExprBuilder addWeightedSum(LinearArgument[] exprs, int[] coeffs) {
for (int i = 0; i < exprs.length; ++i) {
addTerm(exprs[i], coeffs[i]);
}
return this;
}
public LinearExprBuilder addWeightedSum(LinearArgument[] exprs, long[] coeffs) {
for (int i = 0; i < exprs.length; ++i) {
addTerm(exprs[i], coeffs[i]);
}
return this;
}
@Override
public LinearExpr build() {
int numElements = 0;
int lastVarIndex = -1;
double lastCoeff = 0;
for (Map.Entry<Integer, Double> entry : coefficients.entrySet()) {
if (entry.getValue() != 0) {
numElements++;
lastVarIndex = entry.getKey();
lastCoeff = entry.getValue();
}
}
if (numElements == 0) {
return new ConstantExpression(offset);
} else if (numElements == 1) {
return new AffineExpression(lastVarIndex, lastCoeff, offset);
} else {
int[] varIndices = new int[numElements];
double[] coeffs = new double[numElements];
int index = 0;
for (Map.Entry<Integer, Double> entry : coefficients.entrySet()) {
if (entry.getValue() != 0) {
varIndices[index] = entry.getKey();
coeffs[index] = entry.getValue();
index++;
}
}
return new WeightedSumExpression(varIndices, coeffs, offset);
}
}
}

View File

@@ -0,0 +1,206 @@
// Copyright 2010-2021 Google LLC
// 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 com.google.ortools.modelbuilder;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Main modeling class.
*
* <p>Proposes a factory to create all modeling objects understood by the SAT solver.
*/
public final class ModelBuilder {
static class ModelBuilderException extends RuntimeException {
public ModelBuilderException(String methodName, String msg) {
// Call constructor of parent Exception
super(methodName + ": " + msg);
}
}
/** Exception thrown when parallel arrays have mismatched lengths. */
public static class MismatchedArrayLengths extends ModelBuilderException {
public MismatchedArrayLengths(String methodName, String array1Name, String array2Name) {
super(methodName, array1Name + " and " + array2Name + " have mismatched lengths");
}
}
/** Exception thrown when an array has a wrong length. */
public static class WrongLength extends ModelBuilderException {
public WrongLength(String methodName, String msg) {
super(methodName, msg);
}
}
public ModelBuilder() {
helper = new ModelBuilderHelper();
constantMap = new LinkedHashMap<>();
}
// Integer variables.
/** Creates a variable with domain [lb, ub]. */
public Variable newVar(double lb, double ub, boolean isIntegral, String name) {
return new Variable(helper, lb, ub, isIntegral, name);
}
/** Creates an continuous variable with domain [lb, ub]. */
public Variable newNumVar(double lb, double ub, String name) {
return new Variable(helper, lb, ub, false, name);
}
/** Creates an integer variable with domain [lb, ub]. */
public Variable newIntVar(double lb, double ub, String name) {
return new Variable(helper, lb, ub, true, name);
}
/** Creates a Boolean variable with the given name. */
public Variable newBoolVar(String name) {
return new Variable(helper, 0, 1, true, name);
}
/** Creates a constant variable. */
public Variable newConstant(double value) {
if (constantMap.containsKey(value)) {
return new Variable(helper, constantMap.get(value));
}
Variable cste = new Variable(helper, value, value, false, ""); // bounds and name.
constantMap.put(value, cste.getIndex());
return cste;
}
/** Rebuilds a variable from its index. */
public Variable varFromIndex(int index) {
return new Variable(helper, index);
}
// Linear constraints.
/** Adds {@code lb <= expr <= ub}. */
public LinearConstraint addLinearConstraint(LinearArgument expr, double lb, double ub) {
LinearConstraint lin = new LinearConstraint(helper);
final LinearExpr e = expr.build();
for (int i = 0; i < e.numElements(); ++i) {
helper.addConstraintTerm(lin.getIndex(), e.getVariableIndex(i), e.getCoefficient(i));
}
double offset = e.getOffset();
if (lb == Double.NEGATIVE_INFINITY || lb == Double.POSITIVE_INFINITY) {
lin.setLowerBound(lb);
} else {
lin.setLowerBound(lb - offset);
}
if (ub == Double.NEGATIVE_INFINITY || ub == Double.POSITIVE_INFINITY) {
lin.setUpperBound(ub);
} else {
lin.setUpperBound(ub - offset);
}
return lin;
}
/** Returns the number of variables in the model. */
public int numVariables() {
return helper.numVariables();
}
/** Adds {@code expr == value}. */
public LinearConstraint addEquality(LinearArgument expr, double value) {
return addLinearConstraint(expr, value, value);
}
/** Adds {@code left == right}. */
public LinearConstraint addEquality(LinearArgument left, LinearArgument right) {
LinearExprBuilder difference = LinearExpr.newBuilder();
difference.addTerm(left, 1);
difference.addTerm(right, -1);
return addLinearConstraint(difference, 0.0, 0.0);
}
/** Adds {@code expr <= value}. */
public LinearConstraint addLessOrEqual(LinearArgument expr, double value) {
return addLinearConstraint(expr, Double.NEGATIVE_INFINITY, value);
}
/** Adds {@code left <= right}. */
public LinearConstraint addLessOrEqual(LinearArgument left, LinearArgument right) {
LinearExprBuilder difference = LinearExpr.newBuilder();
difference.addTerm(left, 1);
difference.addTerm(right, -1);
return addLinearConstraint(difference, Double.NEGATIVE_INFINITY, 0.0);
}
/** Adds {@code expr >= value}. */
public LinearConstraint addGreaterOrEqual(LinearArgument expr, double value) {
return addLinearConstraint(expr, value, Double.POSITIVE_INFINITY);
}
/** Adds {@code left >= right}. */
public LinearConstraint addGreaterOrEqual(LinearArgument left, LinearArgument right) {
LinearExprBuilder difference = LinearExpr.newBuilder();
difference.addTerm(left, 1);
difference.addTerm(right, -1);
return addLinearConstraint(difference, 0.0, Double.POSITIVE_INFINITY);
}
/** Returns the number of constraints in the model. */
public int numConstraints() {
return helper.numConstraints();
}
/** Minimize expression */
public void minimize(LinearArgument obj) {
optimize(obj, false);
}
/** Minimize expression */
public void maximize(LinearArgument obj) {
optimize(obj, true);
}
/** Sets the objective expression. */
public void optimize(LinearArgument obj, boolean maximize) {
helper.clearObjective();
LinearExpr e = obj.build();
LinkedHashMap<Integer, Double> coeffMap = new LinkedHashMap<>();
for (int i = 0; i < e.numElements(); ++i) {
coeffMap.merge(e.getVariableIndex(i), e.getCoefficient(i), Double::sum);
}
for (Map.Entry<Integer, Double> entry : coeffMap.entrySet()) {
if (entry.getValue() != 0) {
helper.setVarObjectiveCoefficient(entry.getKey(), entry.getValue());
}
}
helper.setObjectiveOffset(e.getOffset());
helper.setMaximize(maximize);
}
/**
* Write the model as a protocol buffer to 'file'.
*
* @param file file to write the model to. If the filename ends with 'txt', the model will be
* 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) {
return helper.writeModelToFile(file);
}
// Getters.
/** Returns the model builder helper. */
public ModelBuilderHelper getHelper() {
return helper;
}
private final ModelBuilderHelper helper;
private final Map<Double, Integer> constantMap;
}

View File

@@ -0,0 +1,58 @@
// Copyright 2010-2021 Google LLC
// 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 com.google.ortools.modelbuilder;
/** Model solver class */
public final class ModelSolver {
static class ModelSolverException extends RuntimeException {
public ModelSolverException(String methodName, String msg) {
// Call constructor of parent Exception
super(methodName + ": " + msg);
}
}
public ModelSolver(String solverName) {
this.helper = new ModelSolverHelper(solverName);
}
public SolveStatus solve(ModelBuilder model) {
helper.solve(model.getHelper());
if (!helper.hasResponse()) {
return SolveStatus.UNKNOWN_STATUS;
}
return helper.getStatus();
}
public double objectiveValue() {
if (!helper.hasSolution()) {
throw new ModelSolverException(
"ModelSolver.objectiveValue()", "solve() was not called or no solution was found");
}
return helper.getObjectiveValue();
}
public double value(Variable var) {
if (!helper.hasSolution()) {
throw new ModelSolverException(
"ModelSolver.value())", "solve() was not called or no solution was found");
}
return helper.getVariableValue(var.getIndex());
}
public double wallTime() {
return helper.getWallTime();
}
ModelSolverHelper helper;
}

View File

@@ -0,0 +1,83 @@
// Copyright 2010-2021 Google LLC
// 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 com.google.ortools.modelbuilder;
/** An integer variable. */
public class Variable implements LinearArgument {
Variable(ModelBuilderHelper helper, double lb, double ub, boolean isIntegral, String name) {
this.helper = helper;
this.index = helper.addVar();
this.helper.setVarName(index, name);
this.helper.setVarIntegrality(index, isIntegral);
this.helper.setVarLowerBound(index, lb);
this.helper.setVarUpperBound(index, ub);
}
Variable(ModelBuilderHelper helper, int index) {
this.helper = helper;
this.index = index;
}
/** Returns the index of the variable in the underlying ModelBuilderHelper. */
public int getIndex() {
return index;
}
// LinearArgument interface
@Override
public LinearExpr build() {
return new AffineExpression(index, 1.0, 0.0);
}
/** Returns the lower bound of the variable. */
public double getLowerBound() {
return helper.getVarLowerBound(index);
}
/** Returns the upper bound of the variable. */
public double getUpperBound() {
return helper.getVarUpperBound(index);
}
/** Returns whether the variable is integral. */
public boolean isIntegral() {
return helper.getVarIsIntegral(index);
}
/** Returns the name of the variable given upon creation. */
public String getName() {
return helper.getVarName(index);
}
/** Returns the objective coefficient of the variable. */
public double getObjectiveCoefficient() {
return helper.getVarObjectiveCoefficient(index);
}
@Override
public String toString() {
if (getName().isEmpty()) {
if (getLowerBound() == getUpperBound()) {
return String.format("%f", getLowerBound());
} else {
return String.format("var_%d(%f, %f)", getIndex(), getLowerBound(), getUpperBound());
}
} else {
return String.format("%s(%f, %f)", getName(), getLowerBound(), getUpperBound());
}
}
protected final ModelBuilderHelper helper;
protected final int index;
}

View File

@@ -0,0 +1,58 @@
// Copyright 2010-2021 Google LLC
// 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 com.google.ortools.modelbuilder;
/** A specialized linear expression: sum(ai * xi) + b. */
public final class WeightedSumExpression implements LinearExpr {
private final int[] variablesIndices;
private final double[] coefficients;
private final double offset;
public WeightedSumExpression(int[] variablesIndices, double[] coefficients, double offset) {
this.variablesIndices = variablesIndices;
this.coefficients = coefficients;
this.offset = offset;
}
@Override
public LinearExpr build() {
return this;
}
@Override
public int numElements() {
return variablesIndices.length;
}
@Override
public int getVariableIndex(int index) {
if (index < 0 || index >= variablesIndices.length) {
throw new IllegalArgumentException("wrong index in LinearExpr.getVariable(): " + index);
}
return variablesIndices[index];
}
@Override
public double getCoefficient(int index) {
if (index < 0 || index >= variablesIndices.length) {
throw new IllegalArgumentException("wrong index in LinearExpr.getCoefficient(): " + index);
}
return coefficients[index];
}
@Override
public double getOffset() {
return offset;
}
}

View File

@@ -0,0 +1,17 @@
set_property(SOURCE modelbuilder.i PROPERTY CPLUSPLUS ON)
set_property(SOURCE modelbuilder.i PROPERTY SWIG_MODULE_NAME main)
set_property(SOURCE modelbuilder.i PROPERTY COMPILE_DEFINITIONS
${OR_TOOLS_COMPILE_DEFINITIONS} ABSL_MUST_USE_RESULT)
set_property(SOURCE modelbuilder.i PROPERTY COMPILE_OPTIONS
-package ${JAVA_PACKAGE}.modelbuilder)
swig_add_library(jnimodel_builder
TYPE OBJECT
LANGUAGE java
OUTPUT_DIR ${JAVA_PROJECT_DIR}/${JAVA_SRC_PATH}/modelbuilder
SOURCES modelbuilder.i)
target_include_directories(jnimodel_builder PRIVATE ${JNI_INCLUDE_DIRS})
set_target_properties(jnimodel_builder PROPERTIES
SWIG_USE_TARGET_INCLUDE_DIRECTORIES ON
POSITION_INDEPENDENT_CODE ON)
target_link_libraries(jnimodel_builder PRIVATE ortools::ortools)

View File

@@ -0,0 +1,157 @@
// Copyright 2010-2021 Google LLC
// 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.
%include "stdint.i"
%include "ortools/base/base.i"
%include "enums.swg"
%{
#include "ortools/model_builder/wrappers/model_builder_helper.h"
%}
%module operations_research_modelbuilder
// This typemap is inspired by the constraints_solver java typemaps.
// The only difference is that the argument is not a basic type, and needs
// processing to be passed to the std::function.
//
// TODO(user): cleanup java/functions.i and move the code there.
%{
#include <memory> // std::make_shared<GlobalRefGuard>
%}
%typemap(in) std::function<void(const std::string&)> %{
// $input will be deleted once this function return.
// So we create a JNI global reference to keep it alive.
jobject $input_object = jenv->NewGlobalRef($input);
// and we wrap it in a GlobalRefGuard object which will call the
// JNI global reference deleter to avoid leak at destruction.
JavaVM* jvm;
jenv->GetJavaVM(&jvm);
auto $input_guard = std::make_shared<GlobalRefGuard>(jvm, $input_object);
jclass $input_object_class = jenv->GetObjectClass($input);
if (nullptr == $input_object_class) return $null;
jmethodID $input_method_id = jenv->GetMethodID(
$input_object_class, "accept", "(Ljava/lang/Object;)V");
assert($input_method_id != nullptr);
// When the lambda will be destroyed, input_guard's destructor will be called.
$1 = [jvm, $input_object, $input_method_id, $input_guard](
const std::string& message) -> void {
JNIEnv *jenv = NULL;
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_2;
args.name = NULL;
args.group = NULL;
jvm->AttachCurrentThread((void**)&jenv, &args);
jenv->CallVoidMethod($input_object, $input_method_id, (jenv)->NewStringUTF(message.c_str()));
jvm->DetachCurrentThread();
};
%}
%typemap(jni) std::function<void(const std::string&)> "jobject" // Type used in the JNI C.
%typemap(jtype) std::function<void(const std::string&)> "java.util.function.Consumer<String>" // Type used in the JNI.java.
%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.
%ignoreall
%unignore operations_research;
// Wrap the ModelBuilderHelper class.
%unignore operations_research::ModelBuilderHelper;
%unignore operations_research::ModelBuilderHelper::ModelBuilderHelper;
%unignore operations_research::ModelBuilderHelper::~ModelBuilderHelper;
// Var API.
%rename (addVar) operations_research::ModelBuilderHelper::AddVar;
%rename (getVarIsIntegral) operations_research::ModelBuilderHelper::VarIsIntegral;
%rename (getVarLowerBound) operations_research::ModelBuilderHelper::VarLowerBound;
%rename (getVarName) operations_research::ModelBuilderHelper::VarName;
%rename (getVarObjectiveCoefficient) operations_research::ModelBuilderHelper::VarObjectiveCoefficient;
%rename (getVarUpperBound) operations_research::ModelBuilderHelper::VarUpperBound;
%rename (numVariables) operations_research::ModelBuilderHelper::num_variables;
%rename (setVarIntegrality) operations_research::ModelBuilderHelper::SetVarIntegrality;
%rename (setVarLowerBound) operations_research::ModelBuilderHelper::SetVarLowerBound;
%rename (setVarName) operations_research::ModelBuilderHelper::SetVarName;
%rename (setVarObjectiveCoefficient) operations_research::ModelBuilderHelper::SetVarObjectiveCoefficient;
%rename (setVarUpperBound) operations_research::ModelBuilderHelper::SetVarUpperBound;
// Constraint API.
%rename (addConstraintTerm) operations_research::ModelBuilderHelper::AddConstraintTerm;
%rename (addLinearConstraint) operations_research::ModelBuilderHelper::AddLinearConstraint;
%rename (getConstraintCoefficients) operations_research::ModelBuilderHelper::ConstraintCoefficients;
%rename (getConstraintLowerBound) operations_research::ModelBuilderHelper::ConstraintLowerBound;
%rename (getConstraintName) operations_research::ModelBuilderHelper::ConstraintName;
%rename (getConstraintUpperBound) operations_research::ModelBuilderHelper::ConstraintUpperBound;
%rename (getConstraintVarIndices) operations_research::ModelBuilderHelper::ConstraintVarIndices;
%rename (numConstraints) operations_research::ModelBuilderHelper::num_constraints;
%rename (setConstraintLowerBound) operations_research::ModelBuilderHelper::SetConstraintLowerBound;
%rename (setConstraintName) operations_research::ModelBuilderHelper::SetConstraintName;
%rename (setConstraintUpperBound) operations_research::ModelBuilderHelper::SetConstraintUpperBound;
// Objective API.
%rename (clearObjective) operations_research::ModelBuilderHelper::ClearObjective;
%rename (getMaximize) operations_research::ModelBuilderHelper::maximize;
%rename (setMaximize) operations_research::ModelBuilderHelper::SetMaximize;
%rename (getObjectiveOffset) operations_research::ModelBuilderHelper::ObjectiveOffset;
%rename (setObjectiveOffset) operations_research::ModelBuilderHelper::SetObjectiveOffset;
// Model API.
%rename (getName) operations_research::ModelBuilderHelper::name;
%rename (setName) operations_research::ModelBuilderHelper::SetName;
%rename (writeModelToFile) operations_research::ModelBuilderHelper::WriteModelToFile;
%rename (importFromMpsString) operations_research::ModelBuilderHelper::ImportFromMpsString;
%rename (importFromMpsFile) operations_research::ModelBuilderHelper::ImportFromMpsFile;
%rename (importFromLpString) operations_research::ModelBuilderHelper::ImportFromLpString;
%rename (importFromLpFile) operations_research::ModelBuilderHelper::ImportFromLpFile;
%unignore operations_research::ModelSolverHelper;
%unignore operations_research::ModelSolverHelper::ModelSolverHelper(const std::string&);
%rename (solverIsSupported) operations_research::ModelSolverHelper::solverIsSupported;
%rename (solve) operations_research::ModelSolverHelper::Solve;
%rename (hasResponse) operations_research::ModelSolverHelper::has_response;
%rename (hasSolution) operations_research::ModelSolverHelper::has_solution;
%rename (getStatus) operations_research::ModelSolverHelper::status;
%rename (getObjectiveValue) operations_research::ModelSolverHelper::objective_value;
%rename (getBestObjectiveBound) operations_research::ModelSolverHelper::best_objective_bound;
%rename (getVariableValue) operations_research::ModelSolverHelper::variable_value;
%rename (getReducedCost) operations_research::ModelSolverHelper::reduced_cost;
%rename (getDualValue) operations_research::ModelSolverHelper::dual_value;
%rename (getStatusString) operations_research::ModelSolverHelper::status_string;
%rename (getWallTime) operations_research::ModelSolverHelper::wall_time;
%rename (enableOutput) operations_research::ModelSolverHelper::EnableOutput;
%unignore operations_research::SolveStatus;
%unignore operations_research::OPTIMAL;
%unignore operations_research::FEASIBLE;
%unignore operations_research::INFEASIBLE;
%unignore operations_research::UNBOUNDED;
%unignore operations_research::ABNORMAL;
%unignore operations_research::NOT_SOLVED;
%unignore operations_research::MODEL_IS_VALID;
%unignore operations_research::CANCELLED_BY_USER;
%unignore operations_research::UNKNOWN_STATUS;
%unignore operations_research::MODEL_INVALID;
%unignore operations_research::INVALID_SOLVER_PARAMETERS;
%unignore operations_research::SOLVER_TYPE_UNAVAILABLE;
%unignore operations_research::INCOMPATIBLE_OPTIONS;
// For enums
%javaconst(1);
%include "ortools/model_builder/wrappers/model_builder_helper.h"
%unignoreall

View File

@@ -0,0 +1,85 @@
// Copyright 2010-2021 Google LLC
// 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.
// Minimal example to call the GLOP solver.
// [START program]
package com.google.ortools.modelbuilder.samples;
// [START import]
import com.google.ortools.Loader;
import com.google.ortools.modelbuilder.LinearExpr;
import com.google.ortools.modelbuilder.ModelBuilder;
import com.google.ortools.modelbuilder.ModelSolver;
import com.google.ortools.modelbuilder.SolveStatus;
import com.google.ortools.modelbuilder.Variable;
// [END import]
/** Minimal Linear Programming example to showcase calling the solver. */
public final class SimpleLpProgramMb {
public static void main(String[] args) {
Loader.loadNativeLibraries();
// [START model]
// Create the linear model.
ModelBuilder model = new ModelBuilder();
// [END model]
// [START variables]
double infinity = java.lang.Double.POSITIVE_INFINITY;
// Create the variables x and y.
Variable x = model.newNumVar(0.0, infinity, "x");
Variable y = model.newNumVar(0.0, infinity, "y");
System.out.println("Number of variables = " + model.numVariables());
// [END variables]
// [START constraints]
// x + 7 * y <= 17.5.
model.addLessOrEqual(LinearExpr.newBuilder().add(x).addTerm(y, 7), 17.5).withName("c0");
// x <= 3.5.
model.addLessOrEqual(x, 3.5).withName("c1");
System.out.println("Number of constraints = " + model.numConstraints());
// [END constraints]
// [START objective]
// Maximize x + 10 * y.
model.maximize(LinearExpr.newBuilder().add(x).addTerm(y, 10.0));
// [END objective]
// [START solve]
// Solve with the GLOP LP solver.
ModelSolver solver = new ModelSolver("glop");
final SolveStatus status = solver.solve(model);
// [END solve]
// [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));
} else {
System.err.println("The problem does not have an optimal solution!");
}
// [END print_solution]
// [START advanced]
System.out.println("\nAdvanced usage:");
System.out.println("Problem solved in " + solver.wallTime() + " milliseconds");
// [END advanced]
}
private SimpleLpProgramMb() {}
}
// [END program]

View File

@@ -0,0 +1,83 @@
// Copyright 2010-2021 Google LLC
// 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.
// Minimal example to call the MIP solver.
// [START program]
package com.google.ortools.modelbuilder.samples;
// [START import]
import com.google.ortools.Loader;
import com.google.ortools.modelbuilder.LinearExpr;
import com.google.ortools.modelbuilder.ModelBuilder;
import com.google.ortools.modelbuilder.ModelSolver;
import com.google.ortools.modelbuilder.SolveStatus;
import com.google.ortools.modelbuilder.Variable;
// [END import]
/** Minimal Mixed Integer Programming example to showcase calling the solver. */
public final class SimpleMipProgramMb {
public static void main(String[] args) {
Loader.loadNativeLibraries();
// [START model]
// Create the linear model.
ModelBuilder model = new ModelBuilder();
// [END model]
// [START variables]
double infinity = java.lang.Double.POSITIVE_INFINITY;
// x and y are integer non-negative variables.
Variable x = model.newIntVar(0.0, infinity, "x");
Variable y = model.newIntVar(0.0, infinity, "y");
System.out.println("Number of variables = " + model.numVariables());
// [END variables]
// [START constraints]
// x + 7 * y <= 17.5.
model.addLessOrEqual(LinearExpr.newBuilder().add(x).addTerm(y, 7), 17.5).withName("c0");
// x <= 3.5.
model.addLessOrEqual(x, 3.5).withName("c1");
System.out.println("Number of constraints = " + model.numConstraints());
// [END constraints]
// [START objective]
// Maximize x + 10 * y.
model.maximize(LinearExpr.newBuilder().add(x).addTerm(y, 10.0));
// [END objective]
// [START solve]
// Solve with the SCIP MIP solver.
ModelSolver solver = new ModelSolver("scip");
final SolveStatus status = solver.solve(model);
// [END solve]
// [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));
} else {
System.err.println("The problem does not have an optimal solution!");
}
// [END print_solution]
// [START advanced]
System.out.println("\nAdvanced usage:");
System.out.println("Problem solved in " + solver.wallTime() + " milliseconds");
}
private SimpleMipProgramMb() {}
}
// [END program]