diff --git a/makefiles/Makefile.cpp.mk b/makefiles/Makefile.cpp.mk
index 4a7890e3cd..ecc9989da6 100644
--- a/makefiles/Makefile.cpp.mk
+++ b/makefiles/Makefile.cpp.mk
@@ -334,6 +334,7 @@ test_cc_graph_samples: \
.PHONY: test_cc_linear_solver_samples # Build and Run all C++ LP Samples (located in ortools/linear_solver/samples)
test_cc_linear_solver_samples: \
+ rcc_assignment_mip \
rcc_bin_packing_mip \
rcc_integer_programming_example \
rcc_linear_programming_example \
diff --git a/makefiles/Makefile.dotnet.mk b/makefiles/Makefile.dotnet.mk
index f125ea41db..03a075f4a2 100644
--- a/makefiles/Makefile.dotnet.mk
+++ b/makefiles/Makefile.dotnet.mk
@@ -520,6 +520,7 @@ test_dotnet_graph_samples: ;
.PHONY: test_dotnet_linear_solver_samples # Build and Run all .Net LP Samples (located in ortools/linear_solver/samples)
test_dotnet_linear_solver_samples:
+ $(MAKE) run SOURCE=ortools/linear_solver/samples/AssignmentMip.cs
$(MAKE) run SOURCE=ortools/linear_solver/samples/BinPackingMip.cs
$(MAKE) run SOURCE=ortools/linear_solver/samples/LinearProgrammingExample.cs
$(MAKE) run SOURCE=ortools/linear_solver/samples/MipVarArray.cs
diff --git a/makefiles/Makefile.java.mk b/makefiles/Makefile.java.mk
index 31aa4c9783..3f62b70b67 100644
--- a/makefiles/Makefile.java.mk
+++ b/makefiles/Makefile.java.mk
@@ -461,6 +461,7 @@ test_java_graph_samples: \
.PHONY: test_java_linear_solver_samples # Build and Run all Java LP Samples (located in ortools/linear_solver/samples)
test_java_linear_solver_samples: \
+ rjava_AssignmentMip \
rjava_BinPackingMip \
rjava_LinearProgrammingExample \
rjava_MipVarArray \
diff --git a/makefiles/Makefile.python.mk b/makefiles/Makefile.python.mk
index b2e3073bb1..dbcfa92105 100644
--- a/makefiles/Makefile.python.mk
+++ b/makefiles/Makefile.python.mk
@@ -591,6 +591,7 @@ test_python_graph_samples: \
.PHONY: test_python_linear_solver_samples # Run all Python LP Samples (located in ortools/linear_solver/samples)
test_python_linear_solver_samples: \
+ rpy_assignment_mip \
rpy_bin_packing_mip \
rpy_integer_programming_example \
rpy_linear_programming_example \
diff --git a/ortools/linear_solver/samples/AssignmentMip.cs b/ortools/linear_solver/samples/AssignmentMip.cs
new file mode 100644
index 0000000000..fd890e6504
--- /dev/null
+++ b/ortools/linear_solver/samples/AssignmentMip.cs
@@ -0,0 +1,116 @@
+// Copyright 2010-2018 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.
+
+using System;
+using Google.OrTools.LinearSolver;
+
+public class AssignmentMip
+{
+ static void Main()
+ {
+ // Data.
+ // [START data_model]
+ int[,] costs = {
+ {90, 80, 75, 70},
+ {35, 85, 55, 65},
+ {125, 95, 90, 95},
+ {45, 110, 95, 115},
+ {50, 100, 90, 100},
+ };
+ int numWorkers = costs.GetLength(0);
+ int numTasks = costs.GetLength(1);
+ // [END data_model]
+
+ // Model.
+ // [START model]
+ Solver solver = Solver.CreateSolver("AssignmentMip", "CBC_MIXED_INTEGER_PROGRAMMING");
+ // [END model]
+
+ // Variables.
+ // [START variables]
+ // x[i, j] is an array of 0-1 variables, which will be 1
+ // if worker i is assigned to task j.
+ Variable[,] x = new Variable[data.NumItems, data.NumBins];
+ for (int i = 0; i < numWorkers; ++i)
+ {
+ for (int j = 0; j < numTasks; ++j)
+ {
+ x[i, j] = solver.MakeIntVar(0, 1, $"worker_{i}_task_{j}");
+ }
+ }
+ // [END variables]
+
+ // Constraints
+ // [START constraints]
+ // Each worker is assigned to at most one task.
+ for (int i = 0; i < numWorkers; ++i)
+ {
+ Constraint constraint = solver.MakeConstraint(0, 1, "");
+ for (int j = 0; j < numTasks; ++j)
+ {
+ constraint.SetCoefficient(x[i, j], 1);
+ }
+ }
+ // Each task is assigned to exactly one worker.
+ for (int j = 0; j < numTasks; ++j)
+ {
+ Constraint constraint = solver.MakeConstraint(1, 1, "");
+ for (int i = 0; i < numWorkers; ++i)
+ {
+ constraint.SetCoefficient(x[i, j], 1);
+ }
+ }
+ // [END constraints]
+
+ // Objective
+ // [START objective]
+ Objective objective = solver.Objective();
+ for (int i = 0; i < numWorkers; ++i)
+ {
+ for (int j = 0; j < numTasks; ++j)
+ {
+ objective.SetCoefficient(x[i, j], 1);
+ }
+ }
+ objective.SetMinimization();
+ // [END objective]
+
+ // Solve
+ // [START solve]
+ Solver.ResultStatus resultStatus = solver.Solve();
+ // [END solve]
+
+ // Print solution.
+ // [START print_solution]
+ // Check that the problem has a feasible solution.
+ if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible)
+ {
+ Console.WriteLine($"Total cost: {solver.ObjectiveValue}\n");
+ for (int i = 0; i < numWorkers; ++i)
+ {
+ for (int j = 0; j < numTasks; ++j)
+ {
+ // Test if x[i, j] is 0 or 1 (with tolerance for floating point
+ // arithmetic).
+ if (x[i, j].SolutionValue() > 0.5)
+ {
+ Console.WriteLine($"Worker {i} assigned to task {j}. Cost: {costs[i, j]}");
+ }
+ }
+ }
+ } else {
+ Console.WriteLine("No solution found.");
+ }
+ // [END print_solution]
+ }
+}
diff --git a/ortools/linear_solver/samples/AssignmentMip.csproj b/ortools/linear_solver/samples/AssignmentMip.csproj
new file mode 100644
index 0000000000..1413a8fe3d
--- /dev/null
+++ b/ortools/linear_solver/samples/AssignmentMip.csproj
@@ -0,0 +1,24 @@
+
+
+ Exe
+ 7.3
+ netcoreapp2.1
+ false
+
+ LatestMajor
+ ../../../packages;$(RestoreSources);https://api.nuget.org/v3/index.json
+ Google.OrTools.AssignmentMip
+ true
+
+
+
+ full
+ true
+ true
+
+
+
+
+
+
+
diff --git a/ortools/linear_solver/samples/AssignmentMip.java b/ortools/linear_solver/samples/AssignmentMip.java
new file mode 100644
index 0000000000..4e260d8181
--- /dev/null
+++ b/ortools/linear_solver/samples/AssignmentMip.java
@@ -0,0 +1,120 @@
+// Copyright 2010-2018 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.
+
+// [START program]
+package com.google.ortools.linearsolver.samples;
+// [START import]
+import com.google.ortools.linearsolver.MPConstraint;
+import com.google.ortools.linearsolver.MPObjective;
+import com.google.ortools.linearsolver.MPSolver;
+import com.google.ortools.linearsolver.MPVariable;
+// [END import]
+
+/** MIP example that solves an assignment problem. */
+public class AssignmentMip {
+ static {
+ System.loadLibrary("jniortools");
+ }
+
+ public static void main(String[] args) {
+ // Data
+ // [START data_model]
+ double[][] costs = {
+ {90, 80, 75, 70},
+ {35, 85, 55, 65},
+ {125, 95, 90, 95},
+ {45, 110, 95, 115},
+ {50, 100, 90, 100},
+ };
+ int numWorkers = costs.length;
+ int numTasks = costs[0].length;
+ // [END data_model]
+
+ // Solver
+ // [START solver]
+ // Create the linear solver with the CBC backend.
+ MPSolver solver = new MPSolver(
+ "AssignmentMip", MPSolver.OptimizationProblemType.CBC_MIXED_INTEGER_PROGRAMMING);
+ // [END solver]
+
+ // Variables
+ // [START variables]
+ // x[i][j] is an array of 0-1 variables, which will be 1
+ // if worker i is assigned to task j.
+ MPVariable[][] x = new MPVariable[numWorkers][numTasks];
+ for (int i = 0; i < numWorkers; ++i) {
+ for (int j = 0; j < numTasks; ++j) {
+ x[i][j] = solver.makeIntVar(0, 1, "");
+ }
+ }
+ // [END variables]
+
+ // Constraints
+ // [START constraints]
+ // Each worker is assigned to at most one task.
+ for (int i = 0; i < numWorkers; ++i) {
+ MPConstraint constraint = solver.makeConstraint(0, 1, "");
+ for (int j = 0; j < numTasks; ++j) {
+ constraint.setCoefficient(x[i][j], 1);
+ }
+ }
+ // Each task is assigned to exactly one worker.
+ for (int j = 0; j < numTasks; ++j) {
+ MPConstraint constraint = solver.makeConstraint(1, 1, "");
+ for (int i = 0; i < numWorkers; ++i) {
+ constraint.setCoefficient(x[i][j], 1);
+ }
+ }
+ // [END constraints]
+
+ // Objective
+ // [START objective]
+ MPObjective objective = solver.objective();
+ for (int i = 0; i < numWorkers; ++i) {
+ for (int j = 0; j < numTasks; ++j) {
+ objective.setCoefficient(x[i][j], costs[i][j]);
+ }
+ }
+ objective.setMinimization();
+ // [END objective]
+
+ // Solve
+ // [START solve]
+ MPSolver.ResultStatus resultStatus = solver.solve();
+ // [END solve]
+
+ // Print solution.
+ // [START print_solution]
+ // Check that the problem has a feasible solution.
+ if (resultStatus == MPSolver.ResultStatus.OPTIMAL
+ || resultStatus == MPSolver.ResultStatus.FEASIBLE) {
+ System.out.println("Total cost: " + objective.value() + "\n");
+ for (int i = 0; i < numWorkers; ++i) {
+ for (int j = 0; j < numTasks; ++j) {
+ // Test if x[i][j] is 0 or 1 (with tolerance for floating point
+ // arithmetic).
+ if (x[i][j].solutionValue() > 0.5) {
+ System.out.println(
+ "Worker " + i + " assigned to task " + j + ". Cost = " + costs[i][j]);
+ }
+ }
+ }
+ } else {
+ System.err.println("No solution found.");
+ }
+ // [END print_solution]
+ }
+
+ private AssignmentMip() {}
+}
+// [END program]
diff --git a/ortools/linear_solver/samples/assignment_mip.cc b/ortools/linear_solver/samples/assignment_mip.cc
new file mode 100644
index 0000000000..76340f9c76
--- /dev/null
+++ b/ortools/linear_solver/samples/assignment_mip.cc
@@ -0,0 +1,118 @@
+// Copyright 2010-2018 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.
+
+// [START program]
+// [START import]
+#include
+
+#include "ortools/base/logging.h"
+#include "ortools/linear_solver/linear_solver.h"
+// [END import]
+
+namespace operations_research {
+void IntegerProgrammingExample() {
+ // Data
+ // [START data_model]
+ const std::vector> costs{
+ {90, 80, 75, 70}, {35, 85, 55, 65}, {125, 95, 90, 95},
+ {45, 110, 95, 115}, {50, 100, 90, 100},
+ };
+ const int num_workers = costs.size();
+ const int num_tasks = costs[0].size();
+ // [END data_model]
+
+ // Solver
+ // [START solver]
+ // Create the mip solver with the CBC backend.
+ MPSolver solver("simple_mip_program",
+ MPSolver::CBC_MIXED_INTEGER_PROGRAMMING);
+ // [END solver]
+
+ // Variables
+ // [START variables]
+ // x[i][j] is an array of 0-1 variables, which will be 1
+ // if worker i is assigned to task j.
+ std::vector> x(
+ num_workers, std::vector(num_tasks));
+ for (int i = 0; i < num_workers; ++i) {
+ for (int j = 0; j < num_tasks; ++j) {
+ x[i][j] = solver.MakeIntVar(0, 1, "");
+ }
+ }
+ // [END variables]
+
+ // Constraints
+ // [START constraints]
+ // Each worker is assigned to at most one task.
+ for (int i = 0; i < num_workers; ++i) {
+ LinearExpr worker_sum;
+ for (int j = 0; j < num_tasks; ++j) {
+ worker_sum += x[i][j];
+ }
+ solver.MakeRowConstraint(worker_sum <= 1.0);
+ }
+ // Each task is assigned to exactly one worker.
+ for (int j = 0; j < num_tasks; ++j) {
+ LinearExpr task_sum;
+ for (int i = 0; i < num_workers; ++i) {
+ task_sum += x[i][j];
+ }
+ solver.MakeRowConstraint(task_sum == 1.0);
+ }
+ // [END constraints]
+
+ // Objective.
+ // [START objective]
+ MPObjective* const objective = solver.MutableObjective();
+ for (int i = 0; i < num_workers; ++i) {
+ for (int j = 0; j < num_tasks; ++j) {
+ objective->SetCoefficient(x[i][j], costs[i][j]);
+ }
+ }
+ objective->SetMinimization();
+ // [END objective]
+
+ // Solve
+ // [START solve]
+ const MPSolver::ResultStatus result_status = solver.Solve();
+ // [END solve]
+
+ // Print solution.
+ // [START print_solution]
+ // Check that the problem has a feasible solution.
+ if (result_status != MPSolver::OPTIMAL &
+ result_status != MPSolver::FEASIBLE) {
+ LOG(FATAL) << "No solution found.";
+ }
+
+ LOG(INFO) << "Total cost = " << objective->Value() << "\n\n";
+
+ for (int i = 0; i < num_workers; ++i) {
+ for (int j = 0; j < num_tasks; ++j) {
+ // Test if x[i][j] is 0 or 1 (with tolerance for floating point
+ // arithmetic).
+ if (x[i][j]->solution_value() > 0.5) {
+ LOG(INFO) << "Worker " << i << " assigned to task " << j
+ << ". Cost = " << costs[i][j];
+ }
+ }
+ }
+ // [END print_solution]
+}
+} // namespace operations_research
+
+int main(int argc, char** argv) {
+ operations_research::IntegerProgrammingExample();
+ return EXIT_SUCCESS;
+}
+// [END program]
diff --git a/ortools/linear_solver/samples/assignment_mip.py b/ortools/linear_solver/samples/assignment_mip.py
new file mode 100644
index 0000000000..667b7a665c
--- /dev/null
+++ b/ortools/linear_solver/samples/assignment_mip.py
@@ -0,0 +1,91 @@
+# Copyright 2010-2018 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.
+"""MIP example that solves an assignment problem."""
+# [START program]
+# [START import]
+from ortools.linear_solver import pywraplp
+# [END import]
+
+
+def main():
+ # Data
+ # [START data_model]
+ costs = [
+ [90, 80, 75, 70],
+ [35, 85, 55, 65],
+ [125, 95, 90, 95],
+ [45, 110, 95, 115],
+ [50, 100, 90, 100],
+ ]
+ num_workers = len(costs)
+ num_tasks = len(costs[0])
+ # [END data_model]
+
+ # Solver
+ # [START solver]
+ # Create the mip solver with the CBC backend.
+ solver = pywraplp.Solver('simple_mip_program',
+ pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)
+ # [END solver]
+
+ # Variables
+ # [START variables]
+ # x[i, j] is an array of 0-1 variables, which will be 1
+ # if worker i is assigned to task j.
+ x = {}
+ for i in range(num_workers):
+ for j in range(num_tasks):
+ x[i, j] = solver.IntVar(0, 1, '')
+ # [END variables]
+
+ # Constraints
+ # [START constraints]
+ # Each worker is assigned to at most 1 task.
+ for i in range(num_workers):
+ solver.Add(solver.Sum([x[i, j] for j in range(num_tasks)]) <= 1)
+
+ # Each task is assigned to exactly one worker.
+ for j in range(num_tasks):
+ solver.Add(solver.Sum([x[i, j] for i in range(num_workers)]) == 1)
+ # [END constraints]
+
+ # Objective
+ # [START objective]
+ objective_terms = []
+ for i in range(num_workers):
+ for j in range(num_tasks):
+ objective_terms.append(costs[i][j] * x[i, j])
+ solver.Minimize(solver.Sum(objective_terms))
+ # [END objective]
+
+ # Solve
+ # [START solve]
+ status = solver.Solve()
+ # [END solve]
+
+ # Print solution.
+ # [START print_solution]
+ if status == pywraplp.Solver.OPTIMAL or status == pywraplp.Solver.FEASIBLE:
+ print('Total cost = ', solver.Objective().Value(), '\n')
+ for i in range(num_workers):
+ for j in range(num_tasks):
+ # Test if x[i,j] is 1 (with tolerance for floating point arithmetic).
+ if x[i, j].solution_value() > 0.5:
+ print('Worker %d assigned to task %d. Cost = %d' %
+ (i, j, costs[i][j]))
+ # [END print_solution]
+
+
+if __name__ == '__main__':
+ main()
+# [END program]