diff --git a/ortools/java/com/google/ortools/modelbuilder/LinearConstraint.java b/ortools/java/com/google/ortools/modelbuilder/LinearConstraint.java index 104c72ced1..a7f2d522b7 100644 --- a/ortools/java/com/google/ortools/modelbuilder/LinearConstraint.java +++ b/ortools/java/com/google/ortools/modelbuilder/LinearConstraint.java @@ -20,6 +20,11 @@ public class LinearConstraint { this.index = helper.addLinearConstraint(); } + LinearConstraint(ModelBuilderHelper helper, int index) { + this.helper = helper; + this.index = index; + } + /** Returns the index of the constraint in the model. */ public int getIndex() { return index; diff --git a/ortools/java/com/google/ortools/modelbuilder/ModelBuilder.java b/ortools/java/com/google/ortools/modelbuilder/ModelBuilder.java index 0753017e56..52ce6a0a99 100644 --- a/ortools/java/com/google/ortools/modelbuilder/ModelBuilder.java +++ b/ortools/java/com/google/ortools/modelbuilder/ModelBuilder.java @@ -43,11 +43,20 @@ public final class ModelBuilder { } } + /** Main constructor */ public ModelBuilder() { helper = new ModelBuilderHelper(); constantMap = new LinkedHashMap<>(); } + /** Returns a cloned model */ + public ModelBuilder clone() { + ModelBuilder clonedModel = new ModelBuilder(); + clonedModel.getHelper().overwriteModel(helper); + clonedModel.constantMap.putAll(constantMap); + return clonedModel; + } + // Integer variables. /** Creates a variable with domain [lb, ub]. */ @@ -55,7 +64,7 @@ public final class ModelBuilder { return new Variable(helper, lb, ub, isIntegral, name); } - /** Creates an continuous variable with domain [lb, ub]. */ + /** Creates a continuous variable with domain [lb, ub]. */ public Variable newNumVar(double lb, double ub, String name) { return new Variable(helper, lb, ub, false, name); } @@ -157,6 +166,11 @@ public final class ModelBuilder { return helper.numConstraints(); } + /** Rebuilds a linear constraint from its index. */ + public LinearConstraint constraintFromIndex(int index) { + return new LinearConstraint(helper, index); + } + /** Minimize expression */ public void minimize(LinearArgument obj) { optimize(obj, false); diff --git a/ortools/linear_solver/java/modelbuilder.i b/ortools/linear_solver/java/modelbuilder.i index 9ec019831d..e8581b15f3 100644 --- a/ortools/linear_solver/java/modelbuilder.i +++ b/ortools/linear_solver/java/modelbuilder.i @@ -154,6 +154,7 @@ class GlobalRefGuard { %rename (importFromLpFile) operations_research::ModelBuilderHelper::ImportFromLpFile; %unignore operations_research::ModelBuilderHelper::exportToMpsString; %unignore operations_research::ModelBuilderHelper::exportToLpString; +%rename (overwriteModel) operations_research::ModelBuilderHelper::OverwriteModel; %unignore operations_research::ModelSolverHelper; %unignore operations_research::ModelSolverHelper::ModelSolverHelper(const std::string&); diff --git a/ortools/linear_solver/samples/BUILD.bazel b/ortools/linear_solver/samples/BUILD.bazel index a5a2574982..a89996f707 100644 --- a/ortools/linear_solver/samples/BUILD.bazel +++ b/ortools/linear_solver/samples/BUILD.bazel @@ -36,6 +36,8 @@ code_sample_cc(name = "stigler_diet") # Model Builder +code_sample_java(name = "CloneModelMb") + code_sample_java(name = "SimpleLpProgramMb") code_sample_java(name = "SimpleMipProgramMb") diff --git a/ortools/linear_solver/samples/CloneModelMb.java b/ortools/linear_solver/samples/CloneModelMb.java new file mode 100644 index 0000000000..b1445374f6 --- /dev/null +++ b/ortools/linear_solver/samples/CloneModelMb.java @@ -0,0 +1,101 @@ +// Copyright 2010-2022 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.linearsolver.samples; + +// [START import] +import com.google.ortools.Loader; +import com.google.ortools.modelbuilder.LinearConstraint; +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 cloning a model. */ +public final class CloneModelMb { + 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"); + // [END variables] + + // [START constraints] + // x + 7 * y <= 17.5. + LinearConstraint unusedC1 = + model.addLessOrEqual(LinearExpr.newBuilder().add(x).addTerm(y, 7), 17.5).withName("c0"); + + // x <= 3.5. + LinearConstraint c2 = model.addLessOrEqual(x, 3.5).withName("c1"); + // [END constraints] + + // [START objective] + // Maximize x + 10 * y. + model.maximize(LinearExpr.newBuilder().add(x).addTerm(y, 10.0)); + // [END objective] + + // Deep copy + System.out.println("Cloning the model"); + ModelBuilder modelCopy = model.clone(); + Variable xCopy = modelCopy.varFromIndex(x.getIndex()); + Variable yCopy = modelCopy.varFromIndex(y.getIndex()); + Variable zCopy = modelCopy.newBoolVar("z"); + LinearConstraint c2Copy = modelCopy.constraintFromIndex(c2.getIndex()); + + // Add new constraint. + LinearConstraint c3Copy = modelCopy.addGreaterOrEqual(xCopy, 1); + + // Modify a constraint. + c2Copy.addTerm(zCopy, 2.0); + + System.out.println("Number of constraints in the original model = " + model.numConstraints()); + System.out.println("Number of constraints in the cloned model = " + modelCopy.numConstraints()); + + // [START solve] + // Solve with the SCIP MIP solver. + ModelSolver solver = new ModelSolver("scip"); + final SolveStatus status = solver.solve(modelCopy); + // [END solve] + + // [START print_solution] + if (status == SolveStatus.OPTIMAL) { + System.out.println("Solution:"); + System.out.println("Objective value = " + solver.getObjectiveValue()); + System.out.println("x = " + solver.getValue(xCopy)); + System.out.println("y = " + solver.getValue(yCopy)); + System.out.println("z = " + solver.getValue(zCopy)); + } 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.getWallTime() + " seconds"); + // [END advanced] + } + + private CloneModelMb() {} +} +// [END program]