[CP-SAT] add soft constraint examples
This commit is contained in:
committed by
Corentin Le Molgat
parent
993ac168d6
commit
1623b1cb18
@@ -4382,6 +4382,7 @@ cc_binary(
|
||||
"//ortools/base",
|
||||
"//ortools/base:file",
|
||||
"//ortools/base:path",
|
||||
"//ortools/base:zipfile",
|
||||
"//ortools/util:file_util",
|
||||
"//ortools/util:logging",
|
||||
"//ortools/util:sigint",
|
||||
|
||||
@@ -879,6 +879,13 @@ cc_test(
|
||||
],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "soft_constraints_sat_py3",
|
||||
srcs = ["soft_constraints_sat.py"],
|
||||
main = "soft_constraints_sat.py",
|
||||
deps = ["//ortools/sat/python:cp_model"],
|
||||
)
|
||||
|
||||
go_binary(
|
||||
name = "solution_hinting_sample_sat_go",
|
||||
srcs = ["solution_hinting_sample_sat.go"],
|
||||
|
||||
219
ortools/sat/samples/soft_constraints_sat.py
Normal file
219
ortools/sat/samples/soft_constraints_sat.py
Normal file
@@ -0,0 +1,219 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2010-2025 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.
|
||||
|
||||
"""The sample shows multiple ways to model soft constraints in CP-SAT."""
|
||||
|
||||
# [START program]
|
||||
# [START import]
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
# [END import]
|
||||
|
||||
|
||||
def infeasible_model() -> None:
|
||||
"""Base model that is infeasible."""
|
||||
# Creates the model.
|
||||
# [START infeasible_model]
|
||||
model = cp_model.CpModel()
|
||||
# [END infeasible_model]
|
||||
|
||||
# Creates the variables.
|
||||
# [START infeasible_model_variables]
|
||||
x = model.new_int_var(0, 10, "x")
|
||||
y = model.new_int_var(0, 10, "y")
|
||||
z = model.new_int_var(0, 10, "z")
|
||||
# [END infeasible_model_variables]
|
||||
|
||||
# Creates the constraints.
|
||||
# [START infeasible_model_constraints]
|
||||
model.add(x > y)
|
||||
model.add(y > z)
|
||||
model.add(z > x)
|
||||
# [END infeasible_model_constraints]
|
||||
|
||||
# Creates a solver and solves.
|
||||
# [START infeasible_model_solve]
|
||||
solver = cp_model.CpSolver()
|
||||
status = solver.solve(model)
|
||||
# [END infeasible_model_solve]
|
||||
|
||||
# Print solution.
|
||||
# [START infeasible_model_print_solution]
|
||||
print(f" Status = {solver.status_name(status)}")
|
||||
# [END infeasible_model_print_solution]
|
||||
|
||||
|
||||
def model_with_enforcement_literals() -> None:
|
||||
"""Adds fixed costs to violated constraints."""
|
||||
# Creates the model.
|
||||
# [START model_with_enforcement_literals]
|
||||
model = cp_model.CpModel()
|
||||
# [END model_with_enforcement_literals]
|
||||
|
||||
# Creates the variables.
|
||||
# [START model_with_enforcement_literals_variables]
|
||||
x = model.new_int_var(0, 10, "x")
|
||||
y = model.new_int_var(0, 10, "y")
|
||||
z = model.new_int_var(0, 10, "z")
|
||||
a = model.new_bool_var("a")
|
||||
b = model.new_bool_var("b")
|
||||
# [END variables_with_enforcement_literals]
|
||||
|
||||
# Creates the constraints. Adds enforcement literals to the first two
|
||||
# constraints, we assume the third constraint is always enforced.
|
||||
# [START constraints_with_enforcement_literals]
|
||||
model.add(x > y).only_enforce_if(a)
|
||||
model.add(y > z).only_enforce_if(b)
|
||||
model.add(z > x)
|
||||
# [END constraints_with_enforcement_literals]
|
||||
|
||||
# Adds an objective to maximize the number of enforced constraints.
|
||||
# [START objective_with_enforcement_literals]
|
||||
model.maximize(a + 2 * b)
|
||||
# [END objective_with_enforcement_literals]
|
||||
|
||||
# Creates a solver and solves.
|
||||
# [START solve_with_enforcement_literals]
|
||||
solver = cp_model.CpSolver()
|
||||
status = solver.solve(model)
|
||||
# [END solve_with_enforcement_literals]
|
||||
|
||||
# Print solution.
|
||||
# [START print_solution_with_enforcement_literals]
|
||||
print(f" Status = {solver.status_name(status)}")
|
||||
if status == cp_model.OPTIMAL:
|
||||
print(f" Objective value = {solver.objective_value}")
|
||||
print(f" Value of x = {solver.value(x)}")
|
||||
print(f" Value of y = {solver.value(y)}")
|
||||
print(f" Value of z = {solver.value(z)}")
|
||||
print(f" Value of a = {solver.boolean_value(a)}")
|
||||
print(f" Value of b = {solver.boolean_value(b)}")
|
||||
# [END print_solution_with_enforcement_literals]
|
||||
|
||||
|
||||
def model_with_linear_violations() -> None:
|
||||
"""Adds fixed costs to violated constraints."""
|
||||
# Creates the model.
|
||||
# [START model_with_linear_violations]
|
||||
model = cp_model.CpModel()
|
||||
# [END model_with_linear_violations]
|
||||
|
||||
# Creates the variables.
|
||||
# [START model_with_linear_violations_variables]
|
||||
x = model.new_int_var(0, 10, "x")
|
||||
y = model.new_int_var(0, 10, "y")
|
||||
z = model.new_int_var(0, 10, "z")
|
||||
a = model.new_int_var(0, 10, "a")
|
||||
b = model.new_int_var(0, 10, "b")
|
||||
# [END model_with_linear_violations_variables]
|
||||
|
||||
# Creates the constraints. Adds enforcement literals to the first two
|
||||
# constraints, we assume the third constraint is always enforced.
|
||||
# [START model_with_linear_violations_constraints]
|
||||
model.add(x > y - a)
|
||||
model.add(y > z - b)
|
||||
model.add(z > x)
|
||||
# [END model_with_linear_violations_constraints]
|
||||
|
||||
# Adds an objective to minimize the added slacks.
|
||||
# [START model_with_linear_violations_objective]
|
||||
model.minimize(a + 2 * b)
|
||||
# [END model_with_linear_violations_objective]
|
||||
|
||||
# Creates a solver and solves.
|
||||
# [START model_with_linear_violations_solve]
|
||||
solver = cp_model.CpSolver()
|
||||
status = solver.solve(model)
|
||||
# [END model_with_linear_violations_solve]
|
||||
|
||||
# Print solution.
|
||||
# [START model_with_linear_violations_print_solution]
|
||||
print(f" Status = {solver.status_name(status)}")
|
||||
if status == cp_model.OPTIMAL:
|
||||
print(f" Objective value = {solver.objective_value}")
|
||||
print(f" Value of x = {solver.value(x)}")
|
||||
print(f" Value of y = {solver.value(y)}")
|
||||
print(f" Value of z = {solver.value(z)}")
|
||||
print(f" Value of a = {solver.value(a)}")
|
||||
print(f" Value of b = {solver.value(b)}")
|
||||
# [END model_with_linear_violations_print_solution]
|
||||
|
||||
|
||||
def model_with_quadratic_violations() -> None:
|
||||
"""Adds fixed costs to violated constraints."""
|
||||
# Creates the model.
|
||||
# [START model_with_quadratic_violations]
|
||||
model = cp_model.CpModel()
|
||||
# [END model_with_quadratic_violations]
|
||||
|
||||
# Creates the variables.
|
||||
# [START model_with_quadratic_violations_variables]
|
||||
x = model.new_int_var(0, 10, "x")
|
||||
y = model.new_int_var(0, 10, "y")
|
||||
z = model.new_int_var(0, 10, "z")
|
||||
a = model.new_int_var(0, 10, "a")
|
||||
b = model.new_int_var(0, 10, "b")
|
||||
square_a = model.new_int_var(0, 100, "square_a")
|
||||
square_b = model.new_int_var(0, 100, "square_b")
|
||||
# [END model_with_quadratic_violations_variables]
|
||||
|
||||
# Creates the constraints. Adds enforcement literals to the first two
|
||||
# constraints, we assume the third constraint is always enforced.
|
||||
# [START model_with_quadratic_violations_constraints]
|
||||
model.add(x > y - a)
|
||||
model.add(y > z - b)
|
||||
model.add(z > x)
|
||||
|
||||
model.add_multiplication_equality(square_a, a, a)
|
||||
model.add_multiplication_equality(square_b, b, b)
|
||||
# [END constraints_with_quadratic_violations]
|
||||
|
||||
# Adds an objective to minimize the added slacks.
|
||||
# [START model_with_quadratic_violations_objective]
|
||||
model.minimize(square_a + 2 * square_b)
|
||||
# [END model_with_quadratic_violations_objective]
|
||||
|
||||
# Creates a solver and solves.
|
||||
# [START model_with_quadratic_violations_solve]
|
||||
solver = cp_model.CpSolver()
|
||||
status = solver.solve(model)
|
||||
# [END model_with_quadratic_violations_solve]
|
||||
|
||||
# Print solution.
|
||||
# [START print_solution_with_quadratic_violations]
|
||||
print(f" Status = {solver.status_name(status)}")
|
||||
if status == cp_model.OPTIMAL:
|
||||
print(f" Objective value = {solver.objective_value}")
|
||||
print(f" Value of x = {solver.value(x)}")
|
||||
print(f" Value of y = {solver.value(y)}")
|
||||
print(f" Value of z = {solver.value(z)}")
|
||||
print(f" Value of a = {solver.value(a)}")
|
||||
print(f" Value of b = {solver.value(b)}")
|
||||
# [END print_solution_with_quadratic_violations]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Infeasible model:")
|
||||
infeasible_model()
|
||||
print("Model with enforcement literals:")
|
||||
model_with_enforcement_literals()
|
||||
print("Model with linear violations:")
|
||||
model_with_linear_violations()
|
||||
print("Model with quadratic violations:")
|
||||
model_with_quadratic_violations()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
# [END program]
|
||||
@@ -245,7 +245,7 @@ void SolutionCrush::SetOrUpdateVarToDomain(
|
||||
const int64_t old_value = GetVarValue(var);
|
||||
if (domain.Contains(old_value)) return;
|
||||
int64_t new_value = old_value;
|
||||
if (push_down_when_repairing_hints) {
|
||||
if (push_down_when_repairing_hints && old_value >= domain.Min()) {
|
||||
new_value = domain.ValueAtOrBefore(old_value);
|
||||
} else {
|
||||
new_value = domain.ValueAtOrAfter(old_value);
|
||||
|
||||
Reference in New Issue
Block a user