Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
solution_improvement.h
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14// This file contains primal solution improvement heuristics.
15#ifndef OR_TOOLS_MATH_OPT_LABS_SOLUTION_IMPROVEMENT_H_
16#define OR_TOOLS_MATH_OPT_LABS_SOLUTION_IMPROVEMENT_H_
17
18#include <algorithm>
19#include <cmath>
20#include <vector>
21
22#include "absl/status/statusor.h"
23#include "absl/types/span.h"
25
27
28// Maximum value for `integrality_tolerance` and for RoundedLowerBound() and
29// RoundedUpperBound().
30inline constexpr double kMaxIntegralityTolerance = 0.25;
31
32// Options for MoveVariablesToTheirBestFeasibleValue.
34 // An absolute tolerance used for rounding the bounds of integer variables.
35 //
36 // It should be in [0, kMaxIntegralityTolerance] range; an error is returned
37 // if the input tolerance is outside this range.
38 //
39 // See RoundedLowerBound() and RoundedUpperBound() for details.
41};
42
43// Returns a solution that improves the objective value of the input model by
44// moving the input variables' values to the their best feasible value (as
45// defined by the objective) based on the constraints and other variables'
46// values.
47//
48// The `input_solution` has to contain a value for each variable in the
49// `model`. The input model must not be unbounded (and error is returned if this
50// is the case).
51//
52// Only the value of the variables listed in `variables` are modified. The
53// variables are considered in the order they appear in the vector. Thus the end
54// result depends on this ordering:
55//
56// - If multiple variables appear in the same constraint, the first variable may
57// use up all the constraint's slack; preventing next variables to improve the
58// objective as much as they could.
59//
60// This issue can be fixed by sorting variables by their objective
61// coefficient. But this may conflict with the order picked to solve
62// dependencies as explained below.
63//
64// - A variable improvement may be limited by another variable it depends on. If
65// it appears first and the second variable's value changes, we may end up
66// with some slack that the first variable could use.
67//
68// This issue can be solved by either:
69//
70// * Calling this function multiple times until no more variables are changed.
71//
72// * Sorting the input `variables` in a correct order so that the limiting
73// variable appear first.
74//
75// The variables' values are changed in the direction that improves the
76// objective. Variables that are not in the objective are not modified.
77//
78// This function is typically useful when solving MIP with a non-zero gap or
79// when the time limit interrupts the solve early. In those cases a MIP solver
80// can return a solution where some variables can trivially be changed to
81// improve the objective but since the solution fits in the termination criteria
82// (either the gap or the time limit) the solver did not do it.
83absl::StatusOr<VariableMap<double>> MoveVariablesToTheirBestFeasibleValue(
84 const Model& model, const VariableMap<double>& input_solution,
85 absl::Span<const Variable> variables,
87
88// Returns the lower bound of the variable, rounding it up when the variable is
89// integral and the bound's fractional value is outside the tolerance.
90//
91// For example if the lower bound of an integer variable is 1.0000000000000002
92// and the tolerance is 0.0 this function will return 2.0. If the tolerance is
93// 1e-6 though this function will return 1.0.
94//
95// Tolerance should be a non-negative value < kMaxIntegralityTolerance (usually
96// much smaller). A negative input value (or NaN) will be considered 0.0, a
97// value >= kMaxIntegralityTolerance will be considered kMaxIntegralityTolerance
98// (using a tolerance like 0.5 would lead to odd behavior for ties as integral
99// bounds could be rounded to the next integer. For example with the integer
100// 2^53 - 1, 2^53 - 1 + 0.5 = 2^53)
101inline double RoundedLowerBound(const Variable v, const double tolerance) {
102 // We use std::fmax() to treat NaN as 0.0.
103 const double offset =
104 std::min(std::fmax(0.0, tolerance), kMaxIntegralityTolerance);
105 return v.is_integer() ? std::ceil(v.lower_bound() - offset) : v.lower_bound();
106}
107
108// Same as RoundedLowerBound() but for upper-bound.
109inline double RoundedUpperBound(const Variable v, const double tolerance) {
110 // See comment in RoundedLowerBound().
111 const double offset =
112 std::min(std::fmax(0.0, tolerance), kMaxIntegralityTolerance);
113 return v.is_integer() ? std::floor(v.upper_bound() + offset)
114 : v.upper_bound();
115}
116
117} // namespace operations_research::math_opt
118
119#endif // OR_TOOLS_MATH_OPT_LABS_SOLUTION_IMPROVEMENT_H_
GRBmodel * model
An object oriented wrapper for quadratic constraints in ModelStorage.
Definition gurobi_isv.cc:28
absl::flat_hash_map< Variable, V > VariableMap
double RoundedLowerBound(const Variable v, const double tolerance)
double RoundedUpperBound(const Variable v, const double tolerance)
Same as RoundedLowerBound() but for upper-bound.
absl::StatusOr< VariableMap< double > > MoveVariablesToTheirBestFeasibleValue(const Model &model, const VariableMap< double > &input_solution, absl::Span< const Variable > variables, const MoveVariablesToTheirBestFeasibleValueOptions &options)