Google OR-Tools v9.14
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
capacity_invariant.cc
Go to the documentation of this file.
1// Copyright 2010-2025 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
15
16#include <limits>
17
18#include "absl/log/check.h"
19#include "absl/log/log.h"
24
25namespace operations_research {
26
28 current_slack_ = 0.0;
29 is_selected_.assign(set_cover_model_->num_subsets(), false);
30}
31
32namespace {
33// Returns true if the addition of `q` to `sum` overflows, for q >= 0.
34bool PositiveAddOverflows(CapacityWeight sum, CapacityWeight q) {
35 DCHECK_GE(q, 0);
36 return sum > std::numeric_limits<CapacityWeight>::max() - q;
37}
38
39// Returns true if the addition of `q` to `sum` overflows, for q <= 0.
40bool NegativeAddOverflows(CapacityWeight sum, CapacityWeight q) {
41 DCHECK_LE(q, 0);
42 return sum < std::numeric_limits<CapacityWeight>::min() - q;
43}
44} // namespace
45
46CapacityWeight CapacityInvariant::ComputeSlackChange(
47 const SubsetIndex subset) const {
48 CapacityWeight slack_change = 0;
49 for (CapacityTermIndex term : model_->TermRange()) {
50 if (model_->GetTermSubsetIndex(term) == subset) {
51 // Hypothesis: GetTermSubsetIndex(term) is an element of the subset.
52 // This information is stored in a SetCoverModel instance.
53 const CapacityWeight term_weight = model_->GetTermCapacityWeight(term);
54 // Make sure that the slack change will not overflow.
55 CHECK(!PositiveAddOverflows(slack_change, term_weight));
56 slack_change += term_weight;
57 }
58 }
59 return slack_change;
60}
61
62bool CapacityInvariant::SlackChangeFitsConstraint(
63 CapacityWeight slack_change) const {
64 CHECK(!AddOverflows(current_slack_, slack_change));
65 const CapacityWeight new_slack = current_slack_ + slack_change;
66 return new_slack >= model_->GetMinimumCapacity() &&
67 new_slack <= model_->GetMaximumCapacity();
68}
69
70bool CapacityInvariant::Select(SubsetIndex subset) {
71 DVLOG(1) << "[Capacity constraint] Selecting subset " << subset;
72 DCHECK(!is_selected_[subset]);
73
74 const CapacityWeight slack_change = ComputeSlackChange(subset);
75 if (!SlackChangeFitsConstraint(slack_change)) {
76 DVLOG(1) << "[Capacity constraint] Selecting subset " << subset
77 << ": infeasible";
78 return false;
79 }
80 CHECK(!PositiveAddOverflows(current_slack_, slack_change));
81 is_selected_[subset] = true;
82 current_slack_ += slack_change;
83 DVLOG(1) << "[Capacity constraint] New slack: " << current_slack_;
84 return true;
85}
86
87bool CapacityInvariant::CanSelect(SubsetIndex subset) const {
88 DVLOG(1) << "[Capacity constraint] Can select subset " << subset << "?";
89 DCHECK(!is_selected_[subset]);
90
91 const CapacityWeight slack_change = ComputeSlackChange(subset);
92 DVLOG(1) << "[Capacity constraint] New slack if selecting: "
93 << current_slack_ + slack_change;
94 return SlackChangeFitsConstraint(slack_change);
95}
96
97bool CapacityInvariant::Deselect(SubsetIndex subset) {
98 DVLOG(1) << "[Capacity constraint] Deselecting subset " << subset;
99 DCHECK(is_selected_[subset]);
100
101 const CapacityWeight slack_change = -ComputeSlackChange(subset);
102 if (!SlackChangeFitsConstraint(slack_change)) {
103 DVLOG(1) << "[Capacity constraint] Deselecting subset " << subset
104 << ": infeasible";
105 return false;
106 }
107 CHECK(!NegativeAddOverflows(current_slack_, slack_change));
108 is_selected_[subset] = false;
109 current_slack_ += slack_change;
110 DVLOG(1) << "[Capacity constraint] New slack: " << current_slack_;
111 return true;
112}
113
114bool CapacityInvariant::CanDeselect(SubsetIndex subset) const {
115 DVLOG(1) << "[Capacity constraint] Can deselect subset " << subset << "?";
116 DCHECK(is_selected_[subset]);
117
118 const CapacityWeight slack_change = -ComputeSlackChange(subset);
119 DVLOG(1) << "[Capacity constraint] New slack if deselecting: "
120 << current_slack_ + slack_change;
121 return SlackChangeFitsConstraint(slack_change);
122}
123} // namespace operations_research
bool CanSelect(SubsetIndex subset) const
bool CanDeselect(SubsetIndex subset) const
In SWIG mode, we don't want anything besides these top-level includes.
bool AddOverflows(int64_t x, int64_t y)
int64_t CapacityWeight
Basic type for weights. For now, the same as Cost for the set covering.