sample: Rework MultipleKnapsack[Sat|Mip]
This commit is contained in:
committed by
Mizux Seiha
parent
db96176998
commit
e4da164368
@@ -17,7 +17,6 @@ using System;
|
||||
using Google.OrTools.LinearSolver;
|
||||
// [END import]
|
||||
|
||||
// [START program_part1]
|
||||
public class MultipleKnapsackMip
|
||||
{
|
||||
// [START data_model]
|
||||
@@ -30,57 +29,61 @@ public class MultipleKnapsackMip
|
||||
public int NumBins = 5;
|
||||
}
|
||||
// [END data_model]
|
||||
|
||||
public static void Main()
|
||||
{
|
||||
// [START data]
|
||||
DataModel data = new DataModel();
|
||||
// [END data]
|
||||
// [END program_part1]
|
||||
|
||||
// [START solver]
|
||||
// Create the linear solver with the SCIP backend.
|
||||
Solver solver = Solver.CreateSolver("SCIP");
|
||||
// [END solver]
|
||||
|
||||
// [START program_part2]
|
||||
// Variables
|
||||
// [START variables]
|
||||
Variable[,] x = new Variable[data.NumItems, data.NumBins];
|
||||
for (int i = 0; i < data.NumItems; i++)
|
||||
{
|
||||
for (int j = 0; j < data.NumBins; j++)
|
||||
for (int b = 0; b < data.NumBins; b++)
|
||||
{
|
||||
x[i, j] = solver.MakeIntVar(0, 1, $"x_{i}_{j}");
|
||||
x[i, b] = solver.MakeBoolVar($"x_{i}_{b}");
|
||||
}
|
||||
}
|
||||
// [END variables]
|
||||
|
||||
// Constraints
|
||||
// [START constraints]
|
||||
// Each item is assigned to at most one bin.
|
||||
for (int i = 0; i < data.NumItems; ++i)
|
||||
{
|
||||
Constraint constraint = solver.MakeConstraint(0, 1, "");
|
||||
for (int j = 0; j < data.NumBins; ++j)
|
||||
for (int b = 0; b < data.NumBins; ++b)
|
||||
{
|
||||
constraint.SetCoefficient(x[i, j], 1);
|
||||
constraint.SetCoefficient(x[i, b], 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < data.NumBins; ++j)
|
||||
// The amount packed in each bin cannot exceed its capacity.
|
||||
for (int b = 0; b < data.NumBins; ++b)
|
||||
{
|
||||
Constraint constraint = solver.MakeConstraint(0, data.BinCapacities[j], "");
|
||||
Constraint constraint = solver.MakeConstraint(0, data.BinCapacities[b], "");
|
||||
for (int i = 0; i < data.NumItems; ++i)
|
||||
{
|
||||
constraint.SetCoefficient(x[i, j], DataModel.Weights[i]);
|
||||
constraint.SetCoefficient(x[i, b], DataModel.Weights[i]);
|
||||
}
|
||||
}
|
||||
// [END constraints]
|
||||
|
||||
// Objective
|
||||
// [START objective]
|
||||
Objective objective = solver.Objective();
|
||||
for (int i = 0; i < data.NumItems; ++i)
|
||||
{
|
||||
for (int j = 0; j < data.NumBins; ++j)
|
||||
for (int b = 0; b < data.NumBins; ++b)
|
||||
{
|
||||
objective.SetCoefficient(x[i, j], DataModel.Values[i]);
|
||||
objective.SetCoefficient(x[i, b], DataModel.Values[i]);
|
||||
}
|
||||
}
|
||||
objective.SetMaximization();
|
||||
@@ -92,34 +95,35 @@ public class MultipleKnapsackMip
|
||||
|
||||
// [START print_solution]
|
||||
// Check that the problem has an optimal solution.
|
||||
if (resultStatus != Solver.ResultStatus.OPTIMAL)
|
||||
if (resultStatus == Solver.ResultStatus.OPTIMAL)
|
||||
{
|
||||
Console.WriteLine($"Total packed value: {solver.Objective().Value()}");
|
||||
double TotalWeight = 0.0;
|
||||
for (int b = 0; b < data.NumBins; ++b)
|
||||
{
|
||||
double BinWeight = 0.0;
|
||||
double BinValue = 0.0;
|
||||
Console.WriteLine("Bin " + b);
|
||||
for (int i = 0; i < data.NumItems; ++i)
|
||||
{
|
||||
if (x[i, b].SolutionValue() == 1)
|
||||
{
|
||||
Console.WriteLine($"Item {i} weight: {DataModel.Weights[i]} values: {DataModel.Values[i]}");
|
||||
BinWeight += DataModel.Weights[i];
|
||||
BinValue += DataModel.Values[i];
|
||||
}
|
||||
}
|
||||
Console.WriteLine("Packed bin weight: " + BinWeight);
|
||||
Console.WriteLine("Packed bin value: " + BinValue);
|
||||
TotalWeight += BinWeight;
|
||||
}
|
||||
Console.WriteLine("Total packed weight: " + TotalWeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("The problem does not have an optimal solution!");
|
||||
return;
|
||||
}
|
||||
Console.WriteLine("Total packed value: " + solver.Objective().Value());
|
||||
double TotalWeight = 0.0;
|
||||
for (int j = 0; j < data.NumBins; ++j)
|
||||
{
|
||||
double BinWeight = 0.0;
|
||||
double BinValue = 0.0;
|
||||
Console.WriteLine("Bin " + j);
|
||||
for (int i = 0; i < data.NumItems; ++i)
|
||||
{
|
||||
if (x[i, j].SolutionValue() == 1)
|
||||
{
|
||||
Console.WriteLine($"Item {i} weight: {DataModel.Weights[i]} values: {DataModel.Values[i]}");
|
||||
BinWeight += DataModel.Weights[i];
|
||||
BinValue += DataModel.Values[i];
|
||||
}
|
||||
}
|
||||
Console.WriteLine("Packed bin weight: " + BinWeight);
|
||||
Console.WriteLine("Packed bin value: " + BinValue);
|
||||
TotalWeight += BinWeight;
|
||||
}
|
||||
Console.WriteLine("Total packed weight: " + TotalWeight);
|
||||
// [END print_solution]
|
||||
}
|
||||
}
|
||||
// [END program_part2]
|
||||
// [END program]
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// MIP example that solves a multiple knapsack problem.
|
||||
// [START program]
|
||||
// MIP example that solves a multiple knapsack problem.
|
||||
package com.google.ortools.linearsolver.samples;
|
||||
// [START import]
|
||||
import com.google.ortools.Loader;
|
||||
@@ -24,7 +24,6 @@ import com.google.ortools.linearsolver.MPVariable;
|
||||
|
||||
/** Multiple knapsack problem. */
|
||||
public class MultipleKnapsackMip {
|
||||
// [START program_part1]
|
||||
// [START data_model]
|
||||
static class DataModel {
|
||||
public final double[] weights = {48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36};
|
||||
@@ -40,7 +39,6 @@ public class MultipleKnapsackMip {
|
||||
// [START data]
|
||||
final DataModel data = new DataModel();
|
||||
// [END data]
|
||||
// [END program_part1]
|
||||
|
||||
// [START solver]
|
||||
// Create the linear solver with the SCIP backend.
|
||||
@@ -51,36 +49,41 @@ public class MultipleKnapsackMip {
|
||||
}
|
||||
// [END solver]
|
||||
|
||||
// [START program_part2]
|
||||
// Variables.
|
||||
// [START variables]
|
||||
MPVariable[][] x = new MPVariable[data.numItems][data.numBins];
|
||||
for (int i = 0; i < data.numItems; ++i) {
|
||||
for (int j = 0; j < data.numBins; ++j) {
|
||||
x[i][j] = solver.makeIntVar(0, 1, "");
|
||||
for (int b = 0; b < data.numBins; ++b) {
|
||||
x[i][b] = solver.makeBoolVar("x_" + i + "_" + b);
|
||||
}
|
||||
}
|
||||
// [END variables]
|
||||
|
||||
// Constraints.
|
||||
// [START constraints]
|
||||
// Each item is assigned to at most one bin.
|
||||
for (int i = 0; i < data.numItems; ++i) {
|
||||
MPConstraint constraint = solver.makeConstraint(0, 1, "");
|
||||
for (int j = 0; j < data.numBins; ++j) {
|
||||
constraint.setCoefficient(x[i][j], 1);
|
||||
for (int b = 0; b < data.numBins; ++b) {
|
||||
constraint.setCoefficient(x[i][b], 1);
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < data.numBins; ++j) {
|
||||
MPConstraint constraint = solver.makeConstraint(0, data.binCapacities[j], "");
|
||||
|
||||
// The amount packed in each bin cannot exceed its capacity.
|
||||
for (int b = 0; b < data.numBins; ++b) {
|
||||
MPConstraint constraint = solver.makeConstraint(0, data.binCapacities[b], "");
|
||||
for (int i = 0; i < data.numItems; ++i) {
|
||||
constraint.setCoefficient(x[i][j], data.weights[i]);
|
||||
constraint.setCoefficient(x[i][b], data.weights[i]);
|
||||
}
|
||||
}
|
||||
// [END constraints]
|
||||
|
||||
// Objective.
|
||||
// [START objective]
|
||||
MPObjective objective = solver.objective();
|
||||
for (int i = 0; i < data.numItems; ++i) {
|
||||
for (int j = 0; j < data.numBins; ++j) {
|
||||
objective.setCoefficient(x[i][j], data.values[i]);
|
||||
for (int b = 0; b < data.numBins; ++b) {
|
||||
objective.setCoefficient(x[i][b], data.values[i]);
|
||||
}
|
||||
}
|
||||
objective.setMaximization();
|
||||
@@ -93,22 +96,22 @@ public class MultipleKnapsackMip {
|
||||
// [START print_solution]
|
||||
// Check that the problem has an optimal solution.
|
||||
if (resultStatus == MPSolver.ResultStatus.OPTIMAL) {
|
||||
System.out.println("Total packed value: " + objective.value() + "\n");
|
||||
System.out.println("Total packed value: " + objective.value());
|
||||
double totalWeight = 0;
|
||||
for (int j = 0; j < data.numBins; ++j) {
|
||||
for (int b = 0; b < data.numBins; ++b) {
|
||||
double binWeight = 0;
|
||||
double binValue = 0;
|
||||
System.out.println("Bin " + j + "\n");
|
||||
System.out.println("Bin " + b);
|
||||
for (int i = 0; i < data.numItems; ++i) {
|
||||
if (x[i][j].solutionValue() == 1) {
|
||||
if (x[i][b].solutionValue() == 1) {
|
||||
System.out.println(
|
||||
"Item " + i + " - weight: " + data.weights[i] + " value: " + data.values[i]);
|
||||
"Item " + i + " weight: " + data.weights[i] + " value: " + data.values[i]);
|
||||
binWeight += data.weights[i];
|
||||
binValue += data.values[i];
|
||||
}
|
||||
}
|
||||
System.out.println("Packed bin weight: " + binWeight);
|
||||
System.out.println("Packed bin value: " + binValue + "\n");
|
||||
System.out.println("Packed bin value: " + binValue);
|
||||
totalWeight += binWeight;
|
||||
}
|
||||
System.out.println("Total packed weight: " + totalWeight);
|
||||
@@ -120,5 +123,4 @@ public class MultipleKnapsackMip {
|
||||
|
||||
private MultipleKnapsackMip() {}
|
||||
}
|
||||
// [END program_part2]
|
||||
// [END program]
|
||||
|
||||
@@ -12,38 +12,37 @@
|
||||
// limitations under the License.
|
||||
|
||||
// [START program]
|
||||
// Solve a multiple knapsack problem using a MIP solver.
|
||||
// [START import]
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "ortools/linear_solver/linear_expr.h"
|
||||
#include "ortools/linear_solver/linear_solver.h"
|
||||
// [END import]
|
||||
|
||||
// [START program_part1]
|
||||
namespace operations_research {
|
||||
// [START data_model]
|
||||
struct DataModel {
|
||||
const std::vector<int> weights = {48, 30, 42, 36, 36, 48, 42, 42,
|
||||
36, 24, 30, 30, 42, 36, 36};
|
||||
const std::vector<int> values = {10, 30, 25, 50, 35, 30, 15, 40,
|
||||
30, 35, 45, 10, 20, 30, 25};
|
||||
const int num_items = weights.size();
|
||||
const int total_value = std::accumulate(values.begin(), values.end(), 0);
|
||||
const std::vector<int> bin_capacities = {{100, 100, 100, 100, 100}};
|
||||
const int num_bins = 5;
|
||||
};
|
||||
// [END data_model]
|
||||
|
||||
void MultipleKnapsackMip() {
|
||||
// [START data]
|
||||
DataModel data;
|
||||
// [END data]
|
||||
// [END program_part1]
|
||||
const std::vector<int> weights = {
|
||||
{48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36}};
|
||||
const std::vector<int> values = {
|
||||
{10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25}};
|
||||
const int num_items = weights.size();
|
||||
std::vector<int> all_items(num_items);
|
||||
std::iota(all_items.begin(), all_items.end(), 0);
|
||||
|
||||
const std::vector<int> bin_capacities = {{100, 100, 100, 100, 100}};
|
||||
const int num_bins = bin_capacities.size();
|
||||
std::vector<int> all_bins(num_bins);
|
||||
std::iota(all_bins.begin(), all_bins.end(), 0);
|
||||
// [END data]
|
||||
|
||||
// [START solver]
|
||||
// Create the mip solver with the SCIP backend.
|
||||
// [START solver]
|
||||
std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("SCIP"));
|
||||
if (!solver) {
|
||||
LOG(WARNING) << "SCIP solver unavailable.";
|
||||
@@ -51,48 +50,51 @@ void MultipleKnapsackMip() {
|
||||
}
|
||||
// [END solver]
|
||||
|
||||
// [START program_part2]
|
||||
// Variables.
|
||||
// [START variables]
|
||||
// x[i][b] = 1 if item i is packed in bin b.
|
||||
std::vector<std::vector<const MPVariable*>> x(
|
||||
data.num_items, std::vector<const MPVariable*>(data.num_bins));
|
||||
for (int i = 0; i < data.num_items; ++i) {
|
||||
for (int j = 0; j < data.num_bins; ++j) {
|
||||
x[i][j] = solver->MakeIntVar(0.0, 1.0, "");
|
||||
num_items, std::vector<const MPVariable*>(num_bins));
|
||||
for (int i : all_items) {
|
||||
for (int b : all_bins) {
|
||||
x[i][b] = solver->MakeBoolVar(
|
||||
absl::StrFormat("x_%d_%d", i, b));
|
||||
}
|
||||
}
|
||||
// [END variables]
|
||||
|
||||
// Constraints.
|
||||
// [START constraints]
|
||||
// Create the constraints.
|
||||
// Each item is in at most one bin.
|
||||
for (int i = 0; i < data.num_items; ++i) {
|
||||
// Each item is assigned to at most one bin.
|
||||
for (int i : all_items) {
|
||||
LinearExpr sum;
|
||||
for (int j = 0; j < data.num_bins; ++j) {
|
||||
sum += x[i][j];
|
||||
for (int b : all_bins) {
|
||||
sum += x[i][b];
|
||||
}
|
||||
solver->MakeRowConstraint(sum <= 1.0);
|
||||
}
|
||||
// For each bin that is used, the total packed weight can be at most
|
||||
// the bin capacity.
|
||||
for (int j = 0; j < data.num_bins; ++j) {
|
||||
LinearExpr weight;
|
||||
for (int i = 0; i < data.num_items; ++i) {
|
||||
weight += data.weights[i] * LinearExpr(x[i][j]);
|
||||
|
||||
// The amount packed in each bin cannot exceed its capacity.
|
||||
for (int b : all_bins) {
|
||||
LinearExpr bin_weight;
|
||||
for (int i : all_items) {
|
||||
bin_weight += LinearExpr(x[i][b]) * weights[i];
|
||||
}
|
||||
solver->MakeRowConstraint(weight <= data.bin_capacities[j]);
|
||||
solver->MakeRowConstraint(bin_weight <= bin_capacities[b]);
|
||||
}
|
||||
// [END constraints]
|
||||
|
||||
// Objective.
|
||||
// [START objective]
|
||||
// Create the objective function.
|
||||
// Maximize total value of packed items.
|
||||
MPObjective* const objective = solver->MutableObjective();
|
||||
LinearExpr value;
|
||||
for (int i = 0; i < data.num_items; ++i) {
|
||||
for (int j = 0; j < data.num_bins; ++j) {
|
||||
value += data.values[i] * LinearExpr(x[i][j]);
|
||||
LinearExpr objective_value;
|
||||
for (int i : all_items) {
|
||||
for (int b : all_bins) {
|
||||
objective_value += LinearExpr(x[i][b]) * values[i];
|
||||
}
|
||||
}
|
||||
objective->MaximizeLinearExpr(value);
|
||||
objective->MaximizeLinearExpr(objective_value);
|
||||
// [END objective]
|
||||
|
||||
// [START solve]
|
||||
@@ -100,29 +102,30 @@ void MultipleKnapsackMip() {
|
||||
// [END solve]
|
||||
|
||||
// [START print_solution]
|
||||
// Check that the problem has an optimal solution.
|
||||
if (result_status != MPSolver::OPTIMAL) {
|
||||
std::cerr << "The problem does not have an optimal solution!";
|
||||
}
|
||||
std::cout << "Total packed value: " << objective->Value() << "\n\n";
|
||||
double total_weight = 0;
|
||||
for (int j = 0; j < data.num_bins; ++j) {
|
||||
double bin_weight = 0;
|
||||
double bin_value = 0;
|
||||
std::cout << "Bin " << j << std::endl << std::endl;
|
||||
for (int i = 0; i < data.num_items; ++i) {
|
||||
if (x[i][j]->solution_value() == 1) {
|
||||
std::cout << "Item " << i << " - weight: " << data.weights[i]
|
||||
<< " value: " << data.values[i] << std::endl;
|
||||
bin_weight += data.weights[i];
|
||||
bin_value += data.values[i];
|
||||
if (result_status == MPSolver::OPTIMAL) {
|
||||
LOG(INFO) << "Total packed value: " << objective->Value();
|
||||
double total_weight = 0.0;
|
||||
for (int b : all_bins) {
|
||||
LOG(INFO) << "Bin " << b;
|
||||
double bin_weight = 0.0;
|
||||
double bin_value = 0.0;
|
||||
for (int i : all_items) {
|
||||
if (x[i][b]->solution_value() > 0) {
|
||||
LOG(INFO) << "Item " << i
|
||||
<< " weight: " << weights[i]
|
||||
<< " value: " << values[i];
|
||||
bin_weight += weights[i];
|
||||
bin_value += values[i];
|
||||
}
|
||||
}
|
||||
LOG(INFO) << "Packed bin weight: " << bin_weight;
|
||||
LOG(INFO) << "Packed bin value: " << bin_value;
|
||||
total_weight += bin_weight;
|
||||
}
|
||||
std::cout << "Packed bin weight: " << bin_weight << std::endl;
|
||||
std::cout << "Packed bin value: " << bin_value << std::endl << std::endl;
|
||||
total_weight += bin_weight;
|
||||
LOG(INFO) << "Total packed weight: " << total_weight;
|
||||
} else {
|
||||
LOG(INFO) << "The problem does not have an optimal solution.";
|
||||
}
|
||||
std::cout << "Total packed weight: " << total_weight << std::endl;
|
||||
// [END print_solution]
|
||||
}
|
||||
} // namespace operations_research
|
||||
@@ -131,5 +134,4 @@ int main(int argc, char** argv) {
|
||||
operations_research::MultipleKnapsackMip();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
// [END program_part2]
|
||||
// [END program]
|
||||
|
||||
@@ -22,41 +22,18 @@ from ortools.linear_solver import pywraplp
|
||||
def create_data_model():
|
||||
"""Create the data for the example."""
|
||||
data = {}
|
||||
weights = [48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36]
|
||||
values = [10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25]
|
||||
data['weights'] = weights
|
||||
data['values'] = values
|
||||
data['num_items'] = len(weights)
|
||||
data['weights'] = [48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36]
|
||||
data['values'] = [10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25]
|
||||
assert len(data['weights']) == len(data['values'])
|
||||
data['num_items'] = len(data['weights'])
|
||||
data['all_items'] = range(data['num_items'])
|
||||
data['bin_capacities'] = [100, 100, 100, 100, 100]
|
||||
data['num_bins'] = len(data['bin_capacities'])
|
||||
data['all_bins'] = range(data['num_bins'])
|
||||
return data
|
||||
|
||||
# [END data_model]
|
||||
|
||||
|
||||
# [START solution_printer]
|
||||
def print_solutions(data, objective, x):
|
||||
"""Display the solution."""
|
||||
print('Total packed value:', objective.Value())
|
||||
total_weight = 0
|
||||
for b in data['all_bins']:
|
||||
print(f'Bin {b}\n')
|
||||
bin_weight = 0
|
||||
bin_value = 0
|
||||
for idx, weight in enumerate(data['weights']):
|
||||
if x[idx, b].solution_value() > 0:
|
||||
print(f"Item {idx} - weight: {weight} value: {data['values'][idx]}")
|
||||
bin_weight += weight
|
||||
bin_value += data['values'][idx]
|
||||
print(f'Packed bin weight: {bin_weight}')
|
||||
print(f'Packed bin value: {bin_value}\n')
|
||||
total_weight += bin_weight
|
||||
print(f'Total packed weight: {total_weight}')
|
||||
# [END solution_printer]
|
||||
|
||||
|
||||
def main():
|
||||
# [START data]
|
||||
data = create_data_model()
|
||||
@@ -65,23 +42,25 @@ def main():
|
||||
# Create the mip solver with the SCIP backend.
|
||||
# [START solver]
|
||||
solver = pywraplp.Solver.CreateSolver('SCIP')
|
||||
if solver == None:
|
||||
print('SCIP solver unavailable.')
|
||||
return
|
||||
# [END solver]
|
||||
|
||||
# Main variables.
|
||||
# Variables.
|
||||
# [START variables]
|
||||
# Variables
|
||||
# x[i, j] = 1 if item i is packed in bin j.
|
||||
# x[i, b] = 1 if item i is packed in bin b.
|
||||
x = {}
|
||||
for idx in data['all_items']:
|
||||
for i in data['all_items']:
|
||||
for b in data['all_bins']:
|
||||
x[idx, b] = solver.IntVar(0, 1, f'x_{idx}_{b}')
|
||||
x[i, b] = solver.BoolVar(f'x_{i}_{b}')
|
||||
# [END variables]
|
||||
|
||||
# Constraints
|
||||
# Constraints.
|
||||
# [START constraints]
|
||||
# Each item can be in at most one bin.
|
||||
for idx in data['all_items']:
|
||||
solver.Add(sum(x[idx, b] for b in data['all_bins']) <= 1)
|
||||
# Each item is assigned to at most one bin.
|
||||
for i in data['all_items']:
|
||||
solver.Add(sum(x[i, b] for b in data['all_bins']) <= 1)
|
||||
|
||||
# The amount packed in each bin cannot exceed its capacity.
|
||||
for b in data['all_bins']:
|
||||
@@ -90,7 +69,7 @@ def main():
|
||||
for i in data['all_items']) <= data['bin_capacities'][b])
|
||||
# [END constraints]
|
||||
|
||||
# Objective
|
||||
# Objective.
|
||||
# [START objective]
|
||||
# Maximize total value of packed items.
|
||||
objective = solver.Objective()
|
||||
@@ -106,7 +85,21 @@ def main():
|
||||
|
||||
# [START print_solution]
|
||||
if status == pywraplp.Solver.OPTIMAL:
|
||||
print_solutions(data, objective, x)
|
||||
print(f'Total packed value: {objective.Value()}')
|
||||
total_weight = 0
|
||||
for b in data['all_bins']:
|
||||
print(f'Bin {b}')
|
||||
bin_weight = 0
|
||||
bin_value = 0
|
||||
for i in data['all_items']:
|
||||
if x[i, b].solution_value() > 0:
|
||||
print(f"Item {i} weight: {data['weights'][i]} value: {data['values'][i]}")
|
||||
bin_weight += data['weights'][i]
|
||||
bin_value += data['values'][i]
|
||||
print(f'Packed bin weight: {bin_weight}')
|
||||
print(f'Packed bin value: {bin_value}')
|
||||
total_weight += bin_weight
|
||||
print(f'Total packed weight: {total_weight}')
|
||||
else:
|
||||
print('The problem does not have an optimal solution.')
|
||||
# [END print_solution]
|
||||
|
||||
141
ortools/sat/samples/MultipleKnapsackSat.cs
Normal file
141
ortools/sat/samples/MultipleKnapsackSat.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
// 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.
|
||||
|
||||
// [START program]
|
||||
// [START import]
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Google.OrTools.Sat;
|
||||
// [START import]
|
||||
|
||||
public class MultipleKnapsackSat
|
||||
{
|
||||
public static void Main(String[] args)
|
||||
{
|
||||
// [START data]
|
||||
long[] Weights = { 48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36 };
|
||||
long[] Values = { 10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25 };
|
||||
int NumItems = Weights.Length;
|
||||
int[] allItems = Enumerable.Range(0, NumItems).ToArray();
|
||||
long[] BinCapacities = { 100, 100, 100, 100, 100 };
|
||||
int NumBins = BinCapacities.Length;
|
||||
int[] allBins = Enumerable.Range(0, NumBins).ToArray();
|
||||
// [END data]
|
||||
|
||||
// Model.
|
||||
// [START model]
|
||||
CpModel model = new CpModel();
|
||||
// [END model]
|
||||
|
||||
// Variables
|
||||
// [START variables]
|
||||
IntVar[,] x = new IntVar[NumItems, NumBins];
|
||||
for (int i = 0; i < NumItems; ++i)
|
||||
{
|
||||
for (int j = 0; j < NumBins; ++j)
|
||||
{
|
||||
x[i, j] = model.NewBoolVar($"x_{i}_{j}");
|
||||
}
|
||||
}
|
||||
// [END variables]
|
||||
|
||||
// Constraints
|
||||
// [START constraints]
|
||||
// Each item is assigned to at most one bin.
|
||||
for (int i = 0; i < NumItems; ++i)
|
||||
{
|
||||
IntVar[] vars = new IntVar[NumBins];
|
||||
for (int b = 0; b < NumBins; ++b)
|
||||
{
|
||||
vars[b] = x[i, b];
|
||||
}
|
||||
model.Add(LinearExpr.Sum(vars) <= 1);
|
||||
}
|
||||
|
||||
// The amount packed in each bin cannot exceed its capacity.
|
||||
for (int b = 0; b < NumBins; ++b)
|
||||
{
|
||||
LinearExpr[] exprs = new LinearExpr[NumItems];
|
||||
for (int i = 0; i < NumItems; ++i)
|
||||
{
|
||||
exprs[i] = LinearExpr.Affine(x[i, b], /*coeff=*/Weights[i], /*offset=*/0);
|
||||
}
|
||||
model.Add(LinearExpr.Sum(exprs) <= 1);
|
||||
}
|
||||
// [END constraints]
|
||||
|
||||
// Objective
|
||||
// [START objective]
|
||||
LinearExpr[] obj = new LinearExpr[NumItems * NumBins];
|
||||
for (int i = 0; i < NumItems; ++i)
|
||||
{
|
||||
for (int b = 0; b < NumBins; ++b)
|
||||
{
|
||||
int k = i * NumBins + b;
|
||||
obj[i] = LinearExpr.Affine(x[i, b], /*coeff=*/Values[i], /*offset=*/0);
|
||||
}
|
||||
}
|
||||
model.Maximize(LinearExpr.Sum(obj));
|
||||
// [END objective]
|
||||
|
||||
// Solve
|
||||
// [START solve]
|
||||
CpSolver solver = new CpSolver();
|
||||
CpSolverStatus status = solver.Solve(model);
|
||||
Console.WriteLine($"Solve status: {status}");
|
||||
// [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 packed value: {solver.ObjectiveValue}");
|
||||
double TotalWeight = 0.0;
|
||||
for (int b = 0; b < NumBins; ++b)
|
||||
{
|
||||
double BinWeight = 0.0;
|
||||
double BinValue = 0.0;
|
||||
Console.WriteLine($"Bin {b}");
|
||||
for (int i = 0; i < NumItems; ++i)
|
||||
{
|
||||
if (solver.Value(x[i, b]) == 1)
|
||||
{
|
||||
Console.WriteLine($"Item {i} weight: {Weights[i]} values: {Values[i]}");
|
||||
BinWeight += Weights[i];
|
||||
BinValue += Values[i];
|
||||
}
|
||||
}
|
||||
Console.WriteLine("Packed bin weight: " + BinWeight);
|
||||
Console.WriteLine("Packed bin value: " + BinValue);
|
||||
TotalWeight += BinWeight;
|
||||
}
|
||||
Console.WriteLine("Total packed weight: " + TotalWeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("No solution found.");
|
||||
}
|
||||
// [END print_solution]
|
||||
|
||||
// [START statistics]
|
||||
Console.WriteLine("Statistics");
|
||||
Console.WriteLine($" conflicts: {solver.NumConflicts()}");
|
||||
Console.WriteLine($" branches : {solver.NumBranches()}");
|
||||
Console.WriteLine($" wall time: {solver.WallTime()}s");
|
||||
// [END statistics]
|
||||
}
|
||||
}
|
||||
|
||||
// [END program]
|
||||
25
ortools/sat/samples/MultipleKnapsackSat.csproj
Normal file
25
ortools/sat/samples/MultipleKnapsackSat.csproj
Normal file
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<EnableDefaultItems>false</EnableDefaultItems>
|
||||
<!-- see https://github.com/dotnet/docs/issues/12237 -->
|
||||
<RollForward>LatestMajor</RollForward>
|
||||
<RestoreSources>../../../temp_dotnet/packages;$(RestoreSources);https://api.nuget.org/v3/index.json</RestoreSources>
|
||||
<AssemblyName>Google.OrTools.MultipleKnapsackSat</AssemblyName>
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<GenerateTailCalls>true</GenerateTailCalls>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="MultipleKnapsackSat.cs" />
|
||||
<PackageReference Include="Google.OrTools" Version="9.1.*" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -13,119 +13,94 @@
|
||||
|
||||
// [START program]
|
||||
// [START import]
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "ortools/sat/cp_model.h"
|
||||
// [END import]
|
||||
|
||||
namespace operations_research {
|
||||
namespace sat {
|
||||
|
||||
// [START data_model]
|
||||
struct DataModel {
|
||||
const std::vector<int> weights = {{
|
||||
48,
|
||||
30,
|
||||
42,
|
||||
36,
|
||||
36,
|
||||
48,
|
||||
42,
|
||||
42,
|
||||
36,
|
||||
24,
|
||||
30,
|
||||
30,
|
||||
42,
|
||||
36,
|
||||
36,
|
||||
}};
|
||||
const std::vector<int> values = {
|
||||
{10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25}};
|
||||
const int num_items = weights.size();
|
||||
const int total_value = std::accumulate(values.begin(), values.end(), 0);
|
||||
const std::vector<int> kBinCapacities = {{100, 100, 100, 100, 100}};
|
||||
const int kNumBins = 5;
|
||||
};
|
||||
// [END data_model]
|
||||
|
||||
// [START solution_printer]
|
||||
void PrintSolution(const DataModel data,
|
||||
const std::vector<std::vector<IntVar>> x,
|
||||
const std::vector<IntVar> load,
|
||||
const std::vector<IntVar> value,
|
||||
const CpSolverResponse response) {
|
||||
for (int b = 0; b < data.kNumBins; ++b) {
|
||||
LOG(INFO) << "Bin " << b;
|
||||
LOG(INFO);
|
||||
for (int i = 0; i < data.num_items; ++i) {
|
||||
if (SolutionIntegerValue(response, x[i][b]) > 0) {
|
||||
LOG(INFO) << "Item " << i << " - Weight: " << data.weights[i]
|
||||
<< " Value: " << data.values[i];
|
||||
}
|
||||
}
|
||||
LOG(INFO) << "Packed bin weight: "
|
||||
<< SolutionIntegerValue(response, load[b]);
|
||||
LOG(INFO) << "Packed bin value: "
|
||||
<< SolutionIntegerValue(response, value[b]);
|
||||
LOG(INFO);
|
||||
}
|
||||
LOG(INFO) << "Total packed weight: "
|
||||
<< SolutionIntegerValue(response, LinearExpr::Sum(load));
|
||||
LOG(INFO) << "Total packed value: "
|
||||
<< SolutionIntegerValue(response, LinearExpr::Sum(value));
|
||||
}
|
||||
// [END solution_printer]
|
||||
|
||||
void MultipleKnapsackSat() {
|
||||
// [START data]
|
||||
DataModel data;
|
||||
const std::vector<int> weights = {
|
||||
{48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36}};
|
||||
const std::vector<int> values = {
|
||||
{10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25}};
|
||||
const int total_value = std::accumulate(values.begin(), values.end(), 0);
|
||||
const int num_items = weights.size();
|
||||
std::vector<int> all_items(num_items);
|
||||
std::iota(all_items.begin(), all_items.end(), 0);
|
||||
|
||||
const std::vector<int> bin_capacities = {{100, 100, 100, 100, 100}};
|
||||
const int num_bins = bin_capacities.size();
|
||||
std::vector<int> all_bins(num_bins);
|
||||
std::iota(all_bins.begin(), all_bins.end(), 0);
|
||||
// [END data]
|
||||
|
||||
// [START model]
|
||||
CpModelBuilder cp_model;
|
||||
// [END model]
|
||||
|
||||
// Variables.
|
||||
// [START variables]
|
||||
// Main variables.
|
||||
std::vector<std::vector<IntVar>> x(data.num_items);
|
||||
for (int i = 0; i < data.num_items; ++i) {
|
||||
for (int b = 0; b < data.kNumBins; ++b) {
|
||||
x[i].push_back(cp_model.NewIntVar({0, 1}));
|
||||
// x[i, b] = 1 if item i is packed in bin b.
|
||||
std::map<std::tuple<int, int>, IntVar> x;
|
||||
for (int i : all_items) {
|
||||
for (int b : all_bins) {
|
||||
auto key = std::make_tuple(i, b);
|
||||
x[key] = cp_model.NewBoolVar().WithName(
|
||||
absl::StrFormat("x_%d_%d", i, b));
|
||||
}
|
||||
}
|
||||
|
||||
// Load variables.
|
||||
std::vector<IntVar> load(data.kNumBins);
|
||||
std::vector<IntVar> value(data.kNumBins);
|
||||
for (int b = 0; b < data.kNumBins; ++b) {
|
||||
load[b] = cp_model.NewIntVar({0, data.kBinCapacities[b]});
|
||||
value[b] = cp_model.NewIntVar({0, data.total_value});
|
||||
}
|
||||
|
||||
// Links load and x.
|
||||
for (int b = 0; b < data.kNumBins; ++b) {
|
||||
LinearExpr weightsExpr;
|
||||
LinearExpr valuesExpr;
|
||||
for (int i = 0; i < data.num_items; ++i) {
|
||||
weightsExpr.AddTerm(x[i][b], data.weights[i]);
|
||||
valuesExpr.AddTerm(x[i][b], data.values[i]);
|
||||
}
|
||||
cp_model.AddEquality(weightsExpr, load[b]);
|
||||
cp_model.AddEquality(valuesExpr, value[b]);
|
||||
std::vector<IntVar> load(num_bins);
|
||||
std::vector<IntVar> value(num_bins);
|
||||
for (int b : all_bins) {
|
||||
load[b] = cp_model.NewIntVar({0, bin_capacities[b]});
|
||||
value[b] = cp_model.NewIntVar({0, total_value});
|
||||
}
|
||||
// [END variables]
|
||||
|
||||
// Constraints.
|
||||
// [START constraints]
|
||||
// Each item can be in at most one bin.
|
||||
for (int i = 0; i < data.num_items; ++i) {
|
||||
// Each item is assigned to at most one bin.
|
||||
for (int i : all_items) {
|
||||
LinearExpr expr;
|
||||
for (int b = 0; b < data.kNumBins; ++b) {
|
||||
expr.AddTerm(x[i][b], 1);
|
||||
for (int b : all_bins) {
|
||||
auto key = std::make_tuple(i, b);
|
||||
expr.AddTerm(x[key], 1);
|
||||
}
|
||||
cp_model.AddLessOrEqual(expr, 1);
|
||||
}
|
||||
|
||||
// The amount packed in each bin cannot exceed its capacity.
|
||||
for (int b : all_bins) {
|
||||
LinearExpr bin_weight;
|
||||
for (int i : all_items) {
|
||||
auto key = std::make_tuple(i, b);
|
||||
bin_weight.AddTerm(x[key], weights[i]);
|
||||
}
|
||||
cp_model.AddLessOrEqual(bin_weight, bin_capacities[b]);
|
||||
}
|
||||
// [END constraints]
|
||||
// Maximize sum of load.
|
||||
|
||||
// Objective.
|
||||
// [START objective]
|
||||
cp_model.Maximize(LinearExpr::Sum(value));
|
||||
// Maximize total value of packed items.
|
||||
LinearExpr objective;
|
||||
for (int i : all_items) {
|
||||
for (int b : all_bins) {
|
||||
auto key = std::make_tuple(i, b);
|
||||
objective.AddTerm(x[key], values[i]);
|
||||
}
|
||||
}
|
||||
cp_model.Maximize(objective);
|
||||
// [END objective]
|
||||
|
||||
// [START solve]
|
||||
@@ -133,16 +108,45 @@ void MultipleKnapsackSat() {
|
||||
// [END solve]
|
||||
|
||||
// [START print_solution]
|
||||
PrintSolution(data, x, load, value, response);
|
||||
if (response.status() == CpSolverStatus::OPTIMAL ||
|
||||
response.status() == CpSolverStatus::FEASIBLE) {
|
||||
LOG(INFO) << "Total packed value: " << response.objective_value();
|
||||
double total_weight = 0.0;
|
||||
for (int b : all_bins) {
|
||||
LOG(INFO) << "Bin " << b;
|
||||
double bin_weight = 0.0;
|
||||
double bin_value = 0.0;
|
||||
for (int i : all_items) {
|
||||
auto key = std::make_tuple(i, b);
|
||||
if (SolutionIntegerValue(response, x[key]) > 0) {
|
||||
LOG(INFO) << "Item " << i
|
||||
<< " weight: " << weights[i]
|
||||
<< " value: " << values[i];
|
||||
bin_weight += weights[i];
|
||||
bin_value += values[i];
|
||||
}
|
||||
}
|
||||
LOG(INFO) << "Packed bin weight: " << bin_weight;
|
||||
LOG(INFO) << "Packed bin value: " << bin_value;
|
||||
total_weight += bin_weight;
|
||||
}
|
||||
LOG(INFO) << "Total packed weight: " << total_weight;
|
||||
} else {
|
||||
LOG(INFO) << "The problem does not have an optimal solution.";
|
||||
}
|
||||
// [END print_solution]
|
||||
}
|
||||
|
||||
// Statistics.
|
||||
// [START statistics]
|
||||
LOG(INFO) << "Statistics";
|
||||
LOG(INFO) << CpSolverResponseStats(response);
|
||||
// [END statistics]
|
||||
}
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
int main() {
|
||||
operations_research::sat::MultipleKnapsackSat();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
// [END program]
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# limitations under the License.
|
||||
# [START program]
|
||||
"""Solves a multiple knapsack problem using the CP-SAT solver."""
|
||||
|
||||
# [START import]
|
||||
from ortools.sat.python import cp_model
|
||||
# [END import]
|
||||
@@ -23,45 +22,18 @@ from ortools.sat.python import cp_model
|
||||
def create_data_model():
|
||||
"""Create the data for the example."""
|
||||
data = {}
|
||||
weights = [48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36]
|
||||
values = [10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25]
|
||||
data['num_items'] = len(weights)
|
||||
data['weights'] = [48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36]
|
||||
data['values'] = [10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25]
|
||||
assert len(data['weights']) == len(data['values'])
|
||||
data['num_items'] = len(data['weights'])
|
||||
data['all_items'] = range(data['num_items'])
|
||||
data['weights'] = weights
|
||||
data['values'] = values
|
||||
data['bin_capacities'] = [100, 100, 100, 100, 100]
|
||||
data['num_bins'] = len(data['bin_capacities'])
|
||||
data['all_bins'] = range(data['num_bins'])
|
||||
return data
|
||||
|
||||
# [END data_model]
|
||||
|
||||
|
||||
# [START solution_printer]
|
||||
def print_solutions(data, solver, x):
|
||||
"""Display the solution."""
|
||||
total_weight = 0
|
||||
total_value = 0
|
||||
for b in data['all_bins']:
|
||||
print('Bin', b, '\n')
|
||||
bin_weight = 0
|
||||
bin_value = 0
|
||||
for idx, val in enumerate(data['weights']):
|
||||
if solver.Value(x[(idx, b)]) > 0:
|
||||
print('Item', idx, '- Weight:', val, ' Value:',
|
||||
data['values'][idx])
|
||||
bin_weight += val
|
||||
bin_value += data['values'][idx]
|
||||
print('Packed bin weight:', bin_weight)
|
||||
print('Packed bin value:', bin_value, '\n')
|
||||
total_weight += bin_weight
|
||||
total_value += bin_value
|
||||
print('Total packed weight:', total_weight)
|
||||
print('Total packed value:', total_value)
|
||||
|
||||
# [END solution_printer]
|
||||
|
||||
|
||||
def main():
|
||||
# [START data]
|
||||
data = create_data_model()
|
||||
@@ -71,12 +43,12 @@ def main():
|
||||
model = cp_model.CpModel()
|
||||
# [END model]
|
||||
|
||||
# Main variables.
|
||||
# Variables.
|
||||
# [START variables]
|
||||
x = {}
|
||||
for idx in data['all_items']:
|
||||
for i in data['all_items']:
|
||||
for b in data['all_bins']:
|
||||
x[(idx, b)] = model.NewIntVar(0, 1, 'x_%i_%i' % (idx, b))
|
||||
x[i, b] = model.NewBoolVar(f'x_{i}_{b}')
|
||||
max_value = sum(data['values'])
|
||||
# value[b] is the value of bin b when packed.
|
||||
value = [
|
||||
@@ -84,18 +56,19 @@ def main():
|
||||
]
|
||||
for b in data['all_bins']:
|
||||
model.Add(value[b] == sum(
|
||||
x[(i, b)] * data['values'][i] for i in data['all_items']))
|
||||
x[i, b] * data['values'][i] for i in data['all_items']))
|
||||
# [END variables]
|
||||
|
||||
# Constraints.
|
||||
# [START constraints]
|
||||
# Each item can be in at most one bin.
|
||||
for idx in data['all_items']:
|
||||
model.Add(sum(x[idx, b] for b in data['all_bins']) <= 1)
|
||||
for i in data['all_items']:
|
||||
model.Add(sum(x[i, b] for b in data['all_bins']) <= 1)
|
||||
|
||||
# The amount packed in each bin cannot exceed its capacity.
|
||||
for b in data['all_bins']:
|
||||
model.Add(
|
||||
sum(x[(i, b)] * data['weights'][i]
|
||||
sum(x[i, b] * data['weights'][i]
|
||||
for i in data['all_items']) <= data['bin_capacities'][b])
|
||||
# [END constraints]
|
||||
|
||||
@@ -114,7 +87,24 @@ def main():
|
||||
|
||||
# [START print_solution]
|
||||
if status == cp_model.OPTIMAL:
|
||||
print_solutions(data, solver, x)
|
||||
total_weight = 0
|
||||
total_value = 0
|
||||
for b in data['all_bins']:
|
||||
print('Bin', b, '\n')
|
||||
bin_weight = 0
|
||||
bin_value = 0
|
||||
for idx, val in enumerate(data['weights']):
|
||||
if solver.Value(x[(idx, b)]) > 0:
|
||||
print('Item', idx, '- Weight:', val, ' Value:',
|
||||
data['values'][idx])
|
||||
bin_weight += val
|
||||
bin_value += data['values'][idx]
|
||||
print('Packed bin weight:', bin_weight)
|
||||
print('Packed bin value:', bin_value, '\n')
|
||||
total_weight += bin_weight
|
||||
total_value += bin_value
|
||||
print('Total packed weight:', total_weight)
|
||||
print('Total packed value:', total_value)
|
||||
# [END solutions_printer]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user