Implementation of soft constraint
As Erwin points out, to implement soft constraints, we need to add slack variables to our model and place them in the objective function. To do this, we add two more decision variables for each soft-constrained variable we have in our problem. These decision variables represent the slack in our variable of interest. We can then use the following formula to create our soft constraint:
x1 + x1_surplus - x1_deficit = goal
Where x1
is our decision variable, x1_surplus
and x1_deficit
are our positive and negative slack variables respectively, and goal is the number we are aiming for on our decision variable x1
.
Once we have this constraint in place, we must add an objective that minimizes the total percentage deviance which would look something like:
minimize:
(1/goal) * x1_surplus + (1/goal) * x1_deficit
Note:
We use percentage deviation because we often deal with variables that are measured in different units (e.g. kilograms vs. pounds in the example below). If we do not use percentage deviation the effect of slack in our variables will be unbalanced.
Example in Google OR Tools
Here is a basic working example in Google OR Tools. Here, we are making two products, A and B, and have a certain number of each product we would like to make. We also have a cost associated with making these products and a goal for the amount that we would like to spend on making the products (+/- 10000 in this case).
from ortools.linear_solver import pywraplp
solver = pywraplp.Solver("Soft Constraint Example", pywraplp.Solver.GLOP_LINEAR_PROGRAMMING)
product_a = solver.IntVar(0, 10000, "Pounds of Product A:")
product_b = solver.IntVar(0, 10000, "Pounds of Product B:")
product_a_surplus = solver.IntVar(0, 100, "Product A Surplus:")
product_a_deficit = solver.IntVar(0, 100, "Product A Deficit:")
product_b_surplus = solver.IntVar(0, 100, "Product B Surplus:")
product_b_deficit = solver.IntVar(0, 100, "Product B Deficit:")
cost_surplus = solver.IntVar(0, 10000, "Cost Surplus:")
cost_deficit = solver.IntVar(0, 10000, "Cost Deficit:")
product_a_goal = solver.Add(product_a - product_a_surplus + product_a_deficit == 500)
product_b_goal = solver.Add(product_b - product_b_surplus + product_b_deficit == 250)
cost_goal = solver.Add(product_a * 100 + product_b * 200 - cost_surplus + cost_deficit == 75000)
solver.Minimize(
(1/100) * product_a_surplus
+ (1/100) * product_a_deficit
+ (1/200) * product_b_surplus
+ (1/200) * product_b_deficit
+ (1/75000) * cost_surplus
+ (1/75000) * cost_deficit
)
status = solver.Solve()
print(status == solver.OPTIMAL)
final_cost = product_a.solution_value() * 100 + product_b.solution_value() * 200
print("Final Cost:", final_cost)
var = [product_a, product_b, product_a_surplus, product_a_deficit,
product_b_surplus, product_b_deficit,
cost_surplus, cost_deficit]
for v in var:
print(v.name(), v.solution_value())