Answers by Larry Snyder and Mark H have already pointed out the options of (1) constraining the absolute value of the discrepancy, or (2) including abs(discrepancy) in a "penalty function" to be added to the objective function.
These are useful methods, but depending on the problem you may wish to tweak them a bit, since they have some quirks that may not always be desirable - especially if there are several of these soft constraints in the problem.
If you rely on bounding abs(discrepancy), then you are effectively telling the solver that any discrepancy greater than X is absolutely forbidden, and any discrepancy less than or equal to X is absolutely fine. You will often get solutions that are close to the maximum discrepancy, even when it would be easy to reduce this. In some problems, that might be okay; in others, it's not.
For example, I recently worked on a problem where we needed to assign work to employees, trying to keep as close as possible to each employee's requested workload. There were a few cases where "as close as possible" was not close at all - e.g. Bob has requested 20 hours of work, but we only have 10 hours available in his region. In order to accommodate this sort of case, we have to set the cap to at least ten hours - but that doesn't mean we want 10-hour discrepancies for every employee! (And it's not practical to micro-manage the maximum discrepancy for each individual employee.)
Minimising sum(abs(discrepancy)) avoids this issue. However, it means that (e.g.) one 9-hour discrepancy is considered better than ten 1-hour discrepancies, which is probably unreasonable - you can end up with a solution that's good across most of the problem but poor in some regions.
One option, if you have an appropriate solver, is to use a penalty function based on the sum of squared discrepancies. This tends to balance discrepancies through the system - the larger any one discrepancy is, the more pressure there is to reduce it. This often gives nice solutions, but if you have an integer problem it can take a long time to solve.
The option that we ended up using is to combine these ideas:
- Define a low and high tolerance. Any discrepancy within the low tolerance will be considered "free"; any discrepancy above the high tolerance is forbidden.
- For each employee (= "group of compressors sharing a pipeline" in your problem), define variable
discrepancy
as the difference between requested and allocated hours, or between pressures.
- For each employee (etc.) define
abs_discrepancy
GE discrepancy
and GE -discrepancy
- Constraint
abs_discrepancy LE high_tolerance
- For each employee (etc.) define
nonfree_discrepancy
GE 0 and GE abs_discrepancy - low_tolerance
- Minimise sum of
nonfree_discrepancy
over all employees.
This effectively approximates a quadratic penalty function with three linear pieces: flat from 0 to low tolerance, then with a cost between low and high tolerances, then infinite gradient past high tolerance.
In our problem, this had the benefit of helping with solution time. We found that for the min(sum(abs(discrepancy))) formulation, the solver reached near-optimal solutions quickly and then spent a lot of time grinding away trying to make very small improvements, but it was difficult to quantify exactly what tolerances to set for stopping before optimality. Setting the low tolerance meant that when an employee's discrepancy was inside that tolerance, the solver didn't need to keep fine-tuning their workload.