examples/notebook/sat/soft_constraints_sat.ipynb
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.
First, you must install ortools package in this colab.
%pip install ortools
The sample shows multiple ways to model soft constraints in CP-SAT.
from ortools.sat.python import cp_model
def infeasible_model() -> None:
"""Base model that is infeasible."""
# Creates the model.
model = cp_model.CpModel()
# Creates the 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")
# Creates the constraints.
model.add(x > y)
model.add(y > z)
model.add(z > x)
# Creates a solver and solves.
solver = cp_model.CpSolver()
status = solver.solve(model)
# Print solution.
print(f" Status = {solver.status_name(status)}")
def model_with_enforcement_literals() -> None:
"""Adds fixed costs to violated constraints."""
# Creates the model.
model = cp_model.CpModel()
# Creates the 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")
# Creates the constraints. Adds enforcement literals to the first two
# constraints, we assume the third constraint is always enforced.
model.add(x > y).only_enforce_if(a)
model.add(y > z).only_enforce_if(b)
model.add(z > x)
# Adds an objective to maximize the number of enforced constraints.
model.maximize(a + 2 * b)
# Creates a solver and solves.
solver = cp_model.CpSolver()
status = solver.solve(model)
# 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.boolean_value(a)}")
print(f" Value of b = {solver.boolean_value(b)}")
def model_with_linear_violations() -> None:
"""Adds fixed costs to violated constraints."""
# Creates the model.
model = cp_model.CpModel()
# Creates the 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")
# Creates the constraints. Adds enforcement literals to the first two
# constraints, we assume the third constraint is always enforced.
model.add(x > y - a)
model.add(y > z - b)
model.add(z > x)
# Adds an objective to minimize the added slacks.
model.minimize(a + 2 * b)
# Creates a solver and solves.
solver = cp_model.CpSolver()
status = solver.solve(model)
# 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)}")
def model_with_quadratic_violations() -> None:
"""Adds fixed costs to violated constraints."""
# Creates the model.
model = cp_model.CpModel()
# Creates the 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")
# Creates the constraints. Adds enforcement literals to the first two
# constraints, we assume the third constraint is always enforced.
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)
# Adds an objective to minimize the added slacks.
model.minimize(square_a + 2 * square_b)
# Creates a solver and solves.
solver = cp_model.CpSolver()
status = solver.solve(model)
# 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)}")
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()
main()