Files
ortools-clone/ortools/constraint_solver/pack.cc

1617 lines
54 KiB
C++
Raw Normal View History

2025-01-10 11:35:44 +01:00
// Copyright 2010-2025 Google LLC
2010-09-15 12:42:33 +00:00
// 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.
// Packing constraints
2011-09-21 15:16:48 +00:00
#include <algorithm>
#include <cstddef>
2021-04-01 12:13:35 +02:00
#include <cstdint>
#include <memory>
2011-09-21 15:16:48 +00:00
#include <string>
#include <utility>
2011-09-21 15:16:48 +00:00
#include <vector>
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/types/span.h"
#include "ortools/base/logging.h"
2023-08-18 16:14:58 +02:00
#include "ortools/base/types.h"
#include "ortools/constraint_solver/constraint_solver.h"
#include "ortools/constraint_solver/constraint_solveri.h"
2010-09-15 12:42:33 +00:00
namespace operations_research {
// ---------- Dimension ----------
class Dimension : public BaseObject {
2020-10-22 23:36:58 +02:00
public:
2020-10-29 14:25:39 +01:00
explicit Dimension(Solver* const s, Pack* const pack)
2010-09-15 12:42:33 +00:00
: solver_(s), pack_(pack) {}
~Dimension() override {}
2010-09-15 12:42:33 +00:00
virtual void Post() = 0;
2020-10-29 14:25:39 +01:00
virtual void InitialPropagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& undecided) = 0;
2020-10-22 23:36:58 +02:00
virtual void InitialPropagateUnassigned(
2020-10-29 14:25:39 +01:00
const std::vector<int>& assigned, const std::vector<int>& unassigned) = 0;
2010-09-15 12:42:33 +00:00
virtual void EndInitialPropagate() = 0;
2020-10-29 14:25:39 +01:00
virtual void Propagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& removed) = 0;
virtual void PropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) = 0;
2010-09-15 12:42:33 +00:00
virtual void EndPropagate() = 0;
std::string DebugString() const override { return "Dimension"; }
2023-05-31 14:27:08 +02:00
virtual void Accept(ModelVisitor* visitor) const = 0;
2010-09-15 12:42:33 +00:00
2020-10-29 14:25:39 +01:00
Solver* solver() const { return solver_; }
2010-09-15 12:42:33 +00:00
bool IsUndecided(int var_index, int bin_index) const {
2010-09-15 12:42:33 +00:00
return pack_->IsUndecided(var_index, bin_index);
}
bool IsPossible(int var_index, int bin_index) const {
return pack_->IsPossible(var_index, bin_index);
}
2020-10-29 14:25:39 +01:00
IntVar* AssignVar(int var_index, int bin_index) const {
return pack_->AssignVar(var_index, bin_index);
}
void SetImpossible(int var_index, int bin_index) {
2010-09-15 12:42:33 +00:00
pack_->SetImpossible(var_index, bin_index);
}
void Assign(int var_index, int bin_index) {
2010-09-15 12:42:33 +00:00
pack_->Assign(var_index, bin_index);
}
bool IsAssignedStatusKnown(int var_index) const {
2010-09-15 12:42:33 +00:00
return pack_->IsAssignedStatusKnown(var_index);
}
void SetAssigned(int var_index) { pack_->SetAssigned(var_index); }
2010-09-15 12:42:33 +00:00
void SetUnassigned(int var_index) { pack_->SetUnassigned(var_index); }
2010-09-15 12:42:33 +00:00
void RemoveAllPossibleFromBin(int bin_index) {
2010-09-15 12:42:33 +00:00
pack_->RemoveAllPossibleFromBin(bin_index);
}
void AssignAllPossibleToBin(int bin_index) {
2010-09-15 12:42:33 +00:00
pack_->AssignAllPossibleToBin(bin_index);
}
void AssignFirstPossibleToBin(int bin_index) {
2010-09-15 12:42:33 +00:00
pack_->AssignFirstPossibleToBin(bin_index);
}
void AssignAllRemainingItems() { pack_->AssignAllRemainingItems(); }
2010-09-15 12:42:33 +00:00
void UnassignAllRemainingItems() { pack_->UnassignAllRemainingItems(); }
2011-07-11 20:13:14 +00:00
2020-10-22 23:36:58 +02:00
private:
2020-10-29 14:25:39 +01:00
Solver* const solver_;
Pack* const pack_;
2010-09-15 12:42:33 +00:00
};
// ----- Pack -----
2020-10-29 14:25:39 +01:00
Pack::Pack(Solver* const s, const std::vector<IntVar*>& vars,
2016-11-29 13:40:04 +01:00
int number_of_bins)
2020-10-22 23:36:58 +02:00
: Constraint(s),
vars_(vars),
bins_(number_of_bins),
unprocessed_(new RevBitMatrix(bins_ + 1, vars_.size())),
2020-10-22 23:36:58 +02:00
forced_(bins_ + 1),
removed_(bins_ + 1),
holes_(vars_.size()),
stamp_(uint64_t{0}),
2020-10-22 23:36:58 +02:00
demon_(nullptr),
in_process_(false) {
for (int i = 0; i < vars_.size(); ++i) {
2010-09-15 12:42:33 +00:00
holes_[i] = vars_[i]->MakeHoleIterator(true);
}
}
Pack::~Pack() {}
void Pack::Post() {
for (int i = 0; i < vars_.size(); ++i) {
2020-10-29 14:25:39 +01:00
IntVar* const var = vars_[i];
2010-09-15 12:42:33 +00:00
if (!var->Bound()) {
2020-10-29 14:25:39 +01:00
Demon* const d = MakeConstraintDemon1(solver(), this, &Pack::OneDomain,
"OneDomain", i);
2010-09-15 12:42:33 +00:00
var->WhenDomain(d);
}
}
for (int i = 0; i < dims_.size(); ++i) {
dims_[i]->Post();
}
demon_ = solver()->RegisterDemon(MakeDelayedConstraintDemon0(
solver(), this, &Pack::Propagate, "Propagate"));
2010-09-15 12:42:33 +00:00
}
void Pack::ClearAll() {
for (int bin_index = 0; bin_index <= bins_; ++bin_index) {
forced_[bin_index].clear();
removed_[bin_index].clear();
}
to_set_.clear();
to_unset_.clear();
in_process_ = false;
stamp_ = solver()->fail_stamp();
}
void Pack::PropagateDelayed() {
for (int i = 0; i < to_set_.size(); ++i) {
vars_[to_set_[i].first]->SetValue(to_set_[i].second);
}
for (int i = 0; i < to_unset_.size(); ++i) {
vars_[to_unset_[i].first]->RemoveValue(to_unset_[i].second);
}
}
// A reversibly-allocable container for the data needed in
// Pack::InitialPropagate()
namespace {
class InitialPropagateData : public BaseObject {
2020-10-22 23:36:58 +02:00
public:
explicit InitialPropagateData(size_t num_bins)
: BaseObject(), undecided_(num_bins) {}
void PushAssigned(int index) { assigned_.push_back(index); }
void PushUnassigned(int index) { unassigned_.push_back(index); }
void PushUndecided(int bin, int index) {
undecided_.at(bin).push_back(index);
}
2020-10-29 14:25:39 +01:00
const std::vector<int>& undecided(int bin) const {
2016-11-29 13:40:04 +01:00
return undecided_.at(bin);
}
2020-10-29 14:25:39 +01:00
const std::vector<int>& assigned() const { return assigned_; }
const std::vector<int>& unassigned() const { return unassigned_; }
std::string DebugString() const override { return "InitialPropagateData"; }
2020-10-22 23:36:58 +02:00
private:
std::vector<std::vector<int>> undecided_;
std::vector<int> unassigned_;
std::vector<int> assigned_;
};
2020-10-22 23:36:58 +02:00
} // namespace
2010-09-15 12:42:33 +00:00
void Pack::InitialPropagate() {
const bool need_context = solver()->InstrumentsVariables();
2011-04-08 15:13:24 +00:00
ClearAll();
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
2010-09-15 12:42:33 +00:00
in_process_ = true;
2020-10-29 14:25:39 +01:00
InitialPropagateData* data = s->RevAlloc(new InitialPropagateData(bins_));
for (int var_index = 0; var_index < vars_.size(); ++var_index) {
2020-10-29 14:25:39 +01:00
IntVar* const var = vars_[var_index];
2020-10-22 23:36:58 +02:00
var->SetRange(0, bins_); // bins_ -> item is not assigned to a bin.
2010-09-15 12:42:33 +00:00
if (var->Bound()) {
2021-04-01 12:13:35 +02:00
const int64_t value = var->Min();
2010-09-15 12:42:33 +00:00
if (value < bins_) {
forced_[value].push_back(var_index);
data->PushAssigned(var_index);
2010-09-15 12:42:33 +00:00
} else {
data->PushUnassigned(var_index);
2010-09-15 12:42:33 +00:00
}
} else {
DCHECK_GT(bins_, var->Min())
<< "The variable maximum should be at most " << bins_
<< ", and it should be unbound, so its min is expected to be less "
<< "than " << bins_;
2010-09-15 12:42:33 +00:00
if (var->Max() < bins_) {
data->PushAssigned(var_index);
2010-09-15 12:42:33 +00:00
}
std::unique_ptr<IntVarIterator> it(var->MakeDomainIterator(false));
2021-04-01 12:13:35 +02:00
for (const int64_t value : InitAndGetValues(it.get())) {
2010-09-15 12:42:33 +00:00
if (value >= 0 && value <= bins_) {
unprocessed_->SetToOne(s, value, var_index);
2010-09-15 12:42:33 +00:00
if (value != bins_) {
data->PushUndecided(value, var_index);
2010-09-15 12:42:33 +00:00
}
}
}
}
}
for (int bin_index = 0; bin_index < bins_; ++bin_index) {
if (need_context) {
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
solver()->GetPropagationMonitor()->PushContext(
absl::StrFormat("Pack(bin %d, forced = [%s], undecided = [%s])",
bin_index, absl::StrJoin(forced_[bin_index], ", "),
absl::StrJoin(data->undecided(bin_index), ", ")));
}
2010-09-15 12:42:33 +00:00
for (int dim_index = 0; dim_index < dims_.size(); ++dim_index) {
if (need_context) {
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
solver()->GetPropagationMonitor()->PushContext(absl::StrFormat(
"InitialProgateDimension(%s)", dims_[dim_index]->DebugString()));
}
dims_[dim_index]->InitialPropagate(bin_index, forced_[bin_index],
data->undecided(bin_index));
if (need_context) {
solver()->GetPropagationMonitor()->PopContext();
}
}
if (need_context) {
solver()->GetPropagationMonitor()->PopContext();
2010-09-15 12:42:33 +00:00
}
}
if (need_context) {
solver()->GetPropagationMonitor()->PushContext(
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
absl::StrFormat("Pack(assigned = [%s], unassigned = [%s])",
absl::StrJoin(data->assigned(), ", "),
absl::StrJoin(data->unassigned(), ", ")));
}
2010-09-15 12:42:33 +00:00
for (int dim_index = 0; dim_index < dims_.size(); ++dim_index) {
if (need_context) {
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
solver()->GetPropagationMonitor()->PushContext(absl::StrFormat(
"InitialProgateDimension(%s)", dims_[dim_index]->DebugString()));
}
2020-10-22 23:36:58 +02:00
dims_[dim_index]->InitialPropagateUnassigned(data->assigned(),
data->unassigned());
2010-09-15 12:42:33 +00:00
dims_[dim_index]->EndInitialPropagate();
if (need_context) {
solver()->GetPropagationMonitor()->PopContext();
}
}
if (need_context) {
solver()->GetPropagationMonitor()->PopContext();
2010-09-15 12:42:33 +00:00
}
2010-09-15 12:42:33 +00:00
PropagateDelayed();
ClearAll();
}
void Pack::Propagate() {
const bool need_context = solver()->InstrumentsVariables();
2010-09-15 12:42:33 +00:00
in_process_ = true;
DCHECK_EQ(stamp_, solver()->fail_stamp());
for (int bin_index = 0; bin_index < bins_; ++bin_index) {
if (!removed_[bin_index].empty() || !forced_[bin_index].empty()) {
if (need_context) {
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
solver()->GetPropagationMonitor()->PushContext(
absl::StrFormat("Pack(bin %d, forced = [%s], removed = [%s])",
bin_index, absl::StrJoin(forced_[bin_index], ", "),
absl::StrJoin(removed_[bin_index], ", ")));
}
2010-09-15 12:42:33 +00:00
for (int dim_index = 0; dim_index < dims_.size(); ++dim_index) {
if (need_context) {
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
solver()->GetPropagationMonitor()->PushContext(absl::StrFormat(
"ProgateDimension(%s)", dims_[dim_index]->DebugString()));
}
2020-10-22 23:36:58 +02:00
dims_[dim_index]->Propagate(bin_index, forced_[bin_index],
removed_[bin_index]);
if (need_context) {
solver()->GetPropagationMonitor()->PopContext();
}
}
if (need_context) {
solver()->GetPropagationMonitor()->PopContext();
2010-09-15 12:42:33 +00:00
}
}
}
if (!removed_[bins_].empty() || !forced_[bins_].empty()) {
if (need_context) {
2020-10-22 23:36:58 +02:00
solver()->GetPropagationMonitor()->PushContext(
absl::StrFormat("Pack(removed = [%s], forced = [%s])",
absl::StrJoin(removed_[bins_], ", "),
absl::StrJoin(forced_[bins_], ", ")));
}
2010-09-15 12:42:33 +00:00
for (int dim_index = 0; dim_index < dims_.size(); ++dim_index) {
if (need_context) {
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
solver()->GetPropagationMonitor()->PushContext(absl::StrFormat(
"ProgateDimension(%s)", dims_[dim_index]->DebugString()));
}
2010-09-15 12:42:33 +00:00
dims_[dim_index]->PropagateUnassigned(removed_[bins_], forced_[bins_]);
if (need_context) {
solver()->GetPropagationMonitor()->PopContext();
}
}
if (need_context) {
solver()->GetPropagationMonitor()->PopContext();
2010-09-15 12:42:33 +00:00
}
}
for (int dim_index = 0; dim_index < dims_.size(); ++dim_index) {
dims_[dim_index]->EndPropagate();
}
PropagateDelayed();
ClearAll();
}
void Pack::OneDomain(int var_index) {
// TODO(user): We know var ranges from 0 to bins_. There are lots
// of simplifications possible.
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
2021-04-01 12:13:35 +02:00
const uint64_t current_stamp = s->fail_stamp();
2010-09-15 12:42:33 +00:00
if (stamp_ < current_stamp) {
stamp_ = current_stamp;
ClearAll();
}
2020-10-29 14:25:39 +01:00
IntVar* const var = vars_[var_index];
2010-09-15 12:42:33 +00:00
bool bound = var->Bound();
2021-04-01 12:13:35 +02:00
const int64_t oldmin = var->OldMin();
const int64_t oldmax = var->OldMax();
const int64_t vmin = var->Min();
const int64_t vmax = var->Max();
for (int64_t value = std::max(oldmin, int64_t{0});
value < std::min(vmin, bins_ + int64_t{1}); ++value) {
if (unprocessed_->IsSet(value, var_index)) {
unprocessed_->SetToZero(s, value, var_index);
2010-09-15 12:42:33 +00:00
removed_[value].push_back(var_index);
}
}
if (!bound) {
2021-04-01 12:13:35 +02:00
for (const int64_t value : InitAndGetValues(holes_[var_index])) {
if (value >= std::max(int64_t{0}, vmin) &&
value <= std::min(static_cast<int64_t>(bins_), vmax)) {
DCHECK(unprocessed_->IsSet(value, var_index));
unprocessed_->SetToZero(s, value, var_index);
2010-09-15 12:42:33 +00:00
removed_[value].push_back(var_index);
}
}
}
2021-04-01 12:13:35 +02:00
for (int64_t value = std::max(vmax + 1, int64_t{0});
value <= std::min(oldmax, static_cast<int64_t>(bins_)); ++value) {
if (unprocessed_->IsSet(value, var_index)) {
unprocessed_->SetToZero(s, value, var_index);
2010-09-15 12:42:33 +00:00
removed_[value].push_back(var_index);
}
}
if (bound) {
unprocessed_->SetToZero(s, var->Min(), var_index);
2010-09-15 12:42:33 +00:00
forced_[var->Min()].push_back(var_index);
}
EnqueueDelayedDemon(demon_);
2010-09-15 12:42:33 +00:00
}
std::string Pack::DebugString() const {
std::string result = "Pack([";
for (int i = 0; i < vars_.size(); ++i) {
result += vars_[i]->DebugString() + " ";
2010-09-15 12:42:33 +00:00
}
result += "], dimensions = [";
for (int i = 0; i < dims_.size(); ++i) {
result += dims_[i]->DebugString() + " ";
2010-09-15 12:42:33 +00:00
}
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
absl::StrAppendFormat(&result, "], bins = %d)", bins_);
2010-09-15 12:42:33 +00:00
return result;
}
2020-10-29 14:25:39 +01:00
void Pack::Accept(ModelVisitor* const visitor) const {
2011-07-11 20:13:14 +00:00
visitor->BeginVisitConstraint(ModelVisitor::kPack, this);
visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
vars_);
visitor->VisitIntegerArgument(ModelVisitor::kSizeArgument, bins_);
for (int i = 0; i < dims_.size(); ++i) {
2011-07-14 23:42:49 +00:00
dims_[i]->Accept(visitor);
}
visitor->EndVisitConstraint(ModelVisitor::kPack, this);
2011-07-11 20:13:14 +00:00
}
bool Pack::IsUndecided(int var_index, int bin_index) const {
return unprocessed_->IsSet(bin_index, var_index);
}
void Pack::SetImpossible(int var_index, int bin_index) {
2010-09-15 12:42:33 +00:00
if (IsInProcess()) {
to_unset_.push_back(std::make_pair(var_index, bin_index));
2010-09-15 12:42:33 +00:00
} else {
vars_[var_index]->RemoveValue(bin_index);
}
}
void Pack::Assign(int var_index, int bin_index) {
2010-09-15 12:42:33 +00:00
if (IsInProcess()) {
to_set_.push_back(std::make_pair(var_index, bin_index));
2010-09-15 12:42:33 +00:00
} else {
vars_[var_index]->SetValue(bin_index);
}
}
bool Pack::IsAssignedStatusKnown(int var_index) const {
return !unprocessed_->IsSet(bins_, var_index);
2010-09-15 12:42:33 +00:00
}
bool Pack::IsPossible(int var_index, int bin_index) const {
return vars_[var_index]->Contains(bin_index);
}
2020-10-29 14:25:39 +01:00
IntVar* Pack::AssignVar(int var_index, int bin_index) const {
return solver()->MakeIsEqualCstVar(vars_[var_index], bin_index);
}
void Pack::SetAssigned(int var_index) {
2010-09-15 12:42:33 +00:00
if (IsInProcess()) {
to_unset_.push_back(std::make_pair(var_index, bins_));
2010-09-15 12:42:33 +00:00
} else {
vars_[var_index]->RemoveValue(bins_);
}
}
void Pack::SetUnassigned(int var_index) {
2010-09-15 12:42:33 +00:00
if (IsInProcess()) {
to_set_.push_back(std::make_pair(var_index, bins_));
2010-09-15 12:42:33 +00:00
} else {
vars_[var_index]->SetValue(bins_);
}
}
bool Pack::IsInProcess() const {
return in_process_ && (solver()->fail_stamp() == stamp_);
}
void Pack::RemoveAllPossibleFromBin(int bin_index) {
int var_index = unprocessed_->GetFirstBit(bin_index, 0);
while (var_index != -1 && var_index < vars_.size()) {
2010-09-15 12:42:33 +00:00
SetImpossible(var_index, bin_index);
var_index = var_index == vars_.size() - 1
? -1
: unprocessed_->GetFirstBit(bin_index, var_index + 1);
2010-09-15 12:42:33 +00:00
}
}
void Pack::AssignAllPossibleToBin(int bin_index) {
int var_index = unprocessed_->GetFirstBit(bin_index, 0);
while (var_index != -1 && var_index < vars_.size()) {
2010-09-15 12:42:33 +00:00
Assign(var_index, bin_index);
var_index = var_index == vars_.size() - 1
? -1
: unprocessed_->GetFirstBit(bin_index, var_index + 1);
2010-09-15 12:42:33 +00:00
}
}
void Pack::AssignFirstPossibleToBin(int bin_index) {
int var_index = unprocessed_->GetFirstBit(bin_index, 0);
if (var_index != -1 && var_index < vars_.size()) {
2010-09-15 12:42:33 +00:00
Assign(var_index, bin_index);
}
}
void Pack::AssignAllRemainingItems() {
int var_index = unprocessed_->GetFirstBit(bins_, 0);
while (var_index != -1 && var_index < vars_.size()) {
2010-09-15 12:42:33 +00:00
SetAssigned(var_index);
2020-10-22 23:36:58 +02:00
var_index = var_index == vars_.size() - 1
? -1
: unprocessed_->GetFirstBit(bins_, var_index + 1);
2010-09-15 12:42:33 +00:00
}
}
void Pack::UnassignAllRemainingItems() {
int var_index = unprocessed_->GetFirstBit(bins_, 0);
while (var_index != -1 && var_index < vars_.size()) {
2010-09-15 12:42:33 +00:00
SetUnassigned(var_index);
2020-10-22 23:36:58 +02:00
var_index = var_index == vars_.size() - 1
? -1
: unprocessed_->GetFirstBit(bins_, var_index + 1);
2010-09-15 12:42:33 +00:00
}
}
// ----- Dimension -----
// ----- Class Dimension Less Than Constant -----
namespace {
struct WeightContainer {
int index;
2021-04-01 12:13:35 +02:00
int64_t weight;
WeightContainer(int i, int64_t w) : index(i), weight(w) {}
2020-10-29 14:25:39 +01:00
bool operator<(const WeightContainer& c) const { return (weight < c.weight); }
2010-09-15 12:42:33 +00:00
};
2020-10-29 14:25:39 +01:00
void SortWeightVector(std::vector<int>* const indices,
std::vector<WeightContainer>* const to_sort) {
std::sort(to_sort->begin(), to_sort->end());
for (int index = 0; index < to_sort->size(); ++index) {
(*indices)[index] = (*to_sort)[index].index;
}
indices->resize(to_sort->size());
}
2020-10-29 14:25:39 +01:00
void SortIndexByWeight(std::vector<int>* const indices,
absl::Span<const int64_t> weights) {
std::vector<WeightContainer> to_sort;
for (int index = 0; index < indices->size(); ++index) {
2010-09-15 12:42:33 +00:00
if (weights[index] != 0) {
to_sort.push_back(WeightContainer((*indices)[index], weights[index]));
2010-09-15 12:42:33 +00:00
}
}
SortWeightVector(indices, &to_sort);
}
2020-10-29 14:25:39 +01:00
void SortIndexByWeight(std::vector<int>* const indices,
const Solver::IndexEvaluator1& weights) {
std::vector<WeightContainer> to_sort;
for (int index = 0; index < indices->size(); ++index) {
const int w = weights(index);
if (w != 0) {
to_sort.push_back(WeightContainer((*indices)[index], w));
}
2010-09-15 12:42:33 +00:00
}
SortWeightVector(indices, &to_sort);
}
2020-10-29 14:25:39 +01:00
void SortIndexByWeight(std::vector<int>* const indices,
const Solver::IndexEvaluator2& weights, int bin_index) {
std::vector<WeightContainer> to_sort;
for (int index = 0; index < indices->size(); ++index) {
const int w = weights(index, bin_index);
if (w != 0) {
to_sort.push_back(WeightContainer((*indices)[index], w));
}
2010-09-15 12:42:33 +00:00
}
SortWeightVector(indices, &to_sort);
2010-09-15 12:42:33 +00:00
}
class DimensionLessThanConstant : public Dimension {
2020-10-22 23:36:58 +02:00
public:
2020-10-29 14:25:39 +01:00
DimensionLessThanConstant(Solver* const s, Pack* const p,
2021-04-01 12:13:35 +02:00
const std::vector<int64_t>& weights,
const std::vector<int64_t>& upper_bounds)
2020-10-22 23:36:58 +02:00
: Dimension(s, p),
vars_count_(weights.size()),
weights_(weights),
bins_count_(upper_bounds.size()),
upper_bounds_(upper_bounds),
first_unbound_backward_vector_(bins_count_, 0),
2020-10-22 23:36:58 +02:00
sum_of_bound_variables_vector_(bins_count_, 0LL),
ranked_(vars_count_) {
2010-09-15 12:42:33 +00:00
for (int i = 0; i < vars_count_; ++i) {
ranked_[i] = i;
}
SortIndexByWeight(&ranked_, weights_);
2010-09-15 12:42:33 +00:00
}
~DimensionLessThanConstant() override {}
2010-09-15 12:42:33 +00:00
void Post() override {}
2010-09-15 12:42:33 +00:00
void PushFromTop(int bin_index) {
2021-04-01 12:13:35 +02:00
const int64_t slack =
upper_bounds_[bin_index] - sum_of_bound_variables_vector_[bin_index];
2010-09-15 12:42:33 +00:00
if (slack < 0) {
solver()->Fail();
}
int last_unbound = first_unbound_backward_vector_[bin_index];
2010-09-15 12:42:33 +00:00
for (; last_unbound >= 0; --last_unbound) {
const int var_index = ranked_[last_unbound];
2010-09-15 12:42:33 +00:00
if (IsUndecided(var_index, bin_index)) {
if (weights_[var_index] > slack) {
SetImpossible(var_index, bin_index);
} else {
break;
}
}
}
first_unbound_backward_vector_.SetValue(solver(), bin_index, last_unbound);
2010-09-15 12:42:33 +00:00
}
2020-10-29 14:25:39 +01:00
void InitialPropagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& undecided) override {
Solver* const s = solver();
2021-04-01 12:13:35 +02:00
int64_t sum = 0LL;
for (const int value : forced) {
sum += weights_[value];
2010-09-15 12:42:33 +00:00
}
sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
first_unbound_backward_vector_.SetValue(s, bin_index, ranked_.size() - 1);
2010-09-15 12:42:33 +00:00
PushFromTop(bin_index);
}
void EndInitialPropagate() override {}
2010-09-15 12:42:33 +00:00
2020-10-29 14:25:39 +01:00
void Propagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& removed) override {
2017-04-19 16:20:56 +02:00
if (!forced.empty()) {
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
2021-04-01 12:13:35 +02:00
int64_t sum = sum_of_bound_variables_vector_[bin_index];
for (const int value : forced) {
sum += weights_[value];
2010-09-15 12:42:33 +00:00
}
sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
2010-09-15 12:42:33 +00:00
PushFromTop(bin_index);
}
}
2020-10-29 14:25:39 +01:00
void InitialPropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {
2016-11-29 13:40:04 +01:00
}
2020-10-29 14:25:39 +01:00
void PropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {}
2010-09-15 12:42:33 +00:00
void EndPropagate() override {}
2011-07-11 20:13:14 +00:00
2020-10-29 14:25:39 +01:00
void Accept(ModelVisitor* const visitor) const override {
visitor->BeginVisitExtension(ModelVisitor::kUsageLessConstantExtension);
visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
weights_);
visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument,
upper_bounds_);
visitor->EndVisitExtension(ModelVisitor::kUsageLessConstantExtension);
}
2020-10-22 23:36:58 +02:00
private:
2010-09-15 12:42:33 +00:00
const int vars_count_;
2021-04-01 12:13:35 +02:00
const std::vector<int64_t> weights_;
2010-09-15 12:42:33 +00:00
const int bins_count_;
2021-04-01 12:13:35 +02:00
const std::vector<int64_t> upper_bounds_;
RevArray<int> first_unbound_backward_vector_;
2021-04-01 12:13:35 +02:00
RevArray<int64_t> sum_of_bound_variables_vector_;
std::vector<int> ranked_;
};
class DimensionSumCallbackLessThanConstant : public Dimension {
2020-10-22 23:36:58 +02:00
public:
2020-10-29 14:25:39 +01:00
DimensionSumCallbackLessThanConstant(Solver* const s, Pack* const p,
const Solver::IndexEvaluator1& weights,
int vars_count,
2021-04-01 12:13:35 +02:00
const std::vector<int64_t>& upper_bounds)
2020-10-22 23:36:58 +02:00
: Dimension(s, p),
vars_count_(vars_count),
weights_(weights),
bins_count_(upper_bounds.size()),
upper_bounds_(upper_bounds),
first_unbound_backward_vector_(bins_count_, 0),
2020-10-22 23:36:58 +02:00
sum_of_bound_variables_vector_(bins_count_, 0LL),
ranked_(vars_count_) {
DCHECK(weights);
DCHECK_GT(vars_count, 0);
for (int i = 0; i < vars_count_; ++i) {
ranked_[i] = i;
}
SortIndexByWeight(&ranked_, weights_);
}
~DimensionSumCallbackLessThanConstant() override {}
void Post() override {}
void PushFromTop(int bin_index) {
2021-04-01 12:13:35 +02:00
const int64_t slack =
upper_bounds_[bin_index] - sum_of_bound_variables_vector_[bin_index];
if (slack < 0) {
solver()->Fail();
}
int last_unbound = first_unbound_backward_vector_[bin_index];
for (; last_unbound >= 0; --last_unbound) {
const int var_index = ranked_[last_unbound];
if (IsUndecided(var_index, bin_index)) {
if (weights_(var_index) > slack) {
SetImpossible(var_index, bin_index);
} else {
break;
}
}
}
first_unbound_backward_vector_.SetValue(solver(), bin_index, last_unbound);
}
2020-10-29 14:25:39 +01:00
void InitialPropagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& undecided) override {
Solver* const s = solver();
2021-04-01 12:13:35 +02:00
int64_t sum = 0LL;
for (const int value : forced) {
sum += weights_(value);
}
sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
first_unbound_backward_vector_.SetValue(s, bin_index, ranked_.size() - 1);
PushFromTop(bin_index);
}
void EndInitialPropagate() override {}
2020-10-29 14:25:39 +01:00
void Propagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& removed) override {
2017-04-19 16:20:56 +02:00
if (!forced.empty()) {
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
2021-04-01 12:13:35 +02:00
int64_t sum = sum_of_bound_variables_vector_[bin_index];
for (const int value : forced) {
sum += weights_(value);
}
sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
PushFromTop(bin_index);
}
}
2020-10-29 14:25:39 +01:00
void InitialPropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {
2016-11-29 13:40:04 +01:00
}
2020-10-29 14:25:39 +01:00
void PropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {}
void EndPropagate() override {}
2020-10-29 14:25:39 +01:00
void Accept(ModelVisitor* const visitor) const override {
visitor->BeginVisitExtension(ModelVisitor::kUsageLessConstantExtension);
// TODO(user) : Visit weight correctly.
// visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
// weights_);
visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument,
upper_bounds_);
visitor->EndVisitExtension(ModelVisitor::kUsageLessConstantExtension);
}
2020-10-22 23:36:58 +02:00
private:
const int vars_count_;
Solver::IndexEvaluator1 weights_;
const int bins_count_;
2021-04-01 12:13:35 +02:00
const std::vector<int64_t> upper_bounds_;
RevArray<int> first_unbound_backward_vector_;
2021-04-01 12:13:35 +02:00
RevArray<int64_t> sum_of_bound_variables_vector_;
std::vector<int> ranked_;
2010-09-15 12:42:33 +00:00
};
class DimensionLessThanConstantCallback2 : public Dimension {
2020-10-22 23:36:58 +02:00
public:
2020-10-29 14:25:39 +01:00
DimensionLessThanConstantCallback2(Solver* const s, Pack* const p,
const Solver::IndexEvaluator2& weights,
int vars_count,
2021-04-01 12:13:35 +02:00
const std::vector<int64_t>& upper_bounds)
2020-10-22 23:36:58 +02:00
: Dimension(s, p),
vars_count_(vars_count),
weights_(weights),
bins_count_(upper_bounds.size()),
upper_bounds_(upper_bounds),
first_unbound_backward_vector_(bins_count_, 0),
2020-10-22 23:36:58 +02:00
sum_of_bound_variables_vector_(bins_count_, 0LL),
ranked_(bins_count_) {
DCHECK(weights);
DCHECK_GT(vars_count, 0);
for (int b = 0; b < bins_count_; ++b) {
ranked_[b].resize(vars_count);
for (int i = 0; i < vars_count_; ++i) {
ranked_[b][i] = i;
}
SortIndexByWeight(&ranked_[b], weights_, b);
}
}
~DimensionLessThanConstantCallback2() override {}
void Post() override {}
void PushFromTop(int bin_index) {
2021-04-01 12:13:35 +02:00
const int64_t slack =
upper_bounds_[bin_index] - sum_of_bound_variables_vector_[bin_index];
if (slack < 0) {
solver()->Fail();
}
int last_unbound = first_unbound_backward_vector_[bin_index];
for (; last_unbound >= 0; --last_unbound) {
const int var_index = ranked_[bin_index][last_unbound];
if (IsUndecided(var_index, bin_index)) {
if (weights_(var_index, bin_index) > slack) {
SetImpossible(var_index, bin_index);
} else {
break;
}
}
}
first_unbound_backward_vector_.SetValue(solver(), bin_index, last_unbound);
}
2020-10-29 14:25:39 +01:00
void InitialPropagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& undecided) override {
Solver* const s = solver();
2021-04-01 12:13:35 +02:00
int64_t sum = 0LL;
for (const int value : forced) {
sum += weights_(value, bin_index);
}
sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
first_unbound_backward_vector_.SetValue(s, bin_index,
ranked_[bin_index].size() - 1);
PushFromTop(bin_index);
}
void EndInitialPropagate() override {}
2020-10-29 14:25:39 +01:00
void Propagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& removed) override {
2017-04-19 16:20:56 +02:00
if (!forced.empty()) {
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
2021-04-01 12:13:35 +02:00
int64_t sum = sum_of_bound_variables_vector_[bin_index];
for (const int value : forced) {
sum += weights_(value, bin_index);
}
sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
PushFromTop(bin_index);
}
}
2020-10-29 14:25:39 +01:00
void InitialPropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {
2016-11-29 13:40:04 +01:00
}
2020-10-29 14:25:39 +01:00
void PropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {}
void EndPropagate() override {}
2020-10-29 14:25:39 +01:00
void Accept(ModelVisitor* const visitor) const override {
visitor->BeginVisitExtension(ModelVisitor::kUsageLessConstantExtension);
// TODO(user): Visit weight correctly
// visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
// weights_);
visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument,
upper_bounds_);
visitor->EndVisitExtension(ModelVisitor::kUsageLessConstantExtension);
}
2020-10-22 23:36:58 +02:00
private:
const int vars_count_;
Solver::IndexEvaluator2 weights_;
const int bins_count_;
2021-04-01 12:13:35 +02:00
const std::vector<int64_t> upper_bounds_;
RevArray<int> first_unbound_backward_vector_;
2021-04-01 12:13:35 +02:00
RevArray<int64_t> sum_of_bound_variables_vector_;
std::vector<std::vector<int>> ranked_;
};
class DimensionWeightedSumEqVar : public Dimension {
2020-10-22 23:36:58 +02:00
public:
class VarDemon : public Demon {
2020-10-22 23:36:58 +02:00
public:
2020-10-29 14:25:39 +01:00
VarDemon(DimensionWeightedSumEqVar* const dim, int index)
2010-10-13 16:22:18 +00:00
: dim_(dim), index_(index) {}
~VarDemon() override {}
2020-10-29 14:25:39 +01:00
void Run(Solver* const s) override { dim_->PushFromTop(index_); }
2011-07-11 20:13:14 +00:00
2020-10-22 23:36:58 +02:00
private:
2020-10-29 14:25:39 +01:00
DimensionWeightedSumEqVar* const dim_;
const int index_;
};
2020-10-29 14:25:39 +01:00
DimensionWeightedSumEqVar(Solver* const s, Pack* const p,
2021-04-01 12:13:35 +02:00
const std::vector<int64_t>& weights,
2020-10-29 14:25:39 +01:00
const std::vector<IntVar*>& loads)
2020-10-22 23:36:58 +02:00
: Dimension(s, p),
vars_count_(weights.size()),
weights_(weights),
bins_count_(loads.size()),
loads_(loads),
first_unbound_backward_vector_(bins_count_, 0),
sum_of_bound_variables_vector_(bins_count_, 0LL),
2020-10-22 23:36:58 +02:00
sum_of_all_variables_vector_(bins_count_, 0LL),
ranked_(vars_count_) {
DCHECK_GT(vars_count_, 0);
DCHECK_GT(bins_count_, 0);
for (int i = 0; i < vars_count_; ++i) {
ranked_[i] = i;
}
SortIndexByWeight(&ranked_, weights_);
}
~DimensionWeightedSumEqVar() override {}
2018-06-08 16:40:43 +02:00
std::string DebugString() const override {
return "DimensionWeightedSumEqVar";
}
void Post() override {
for (int i = 0; i < bins_count_; ++i) {
2020-10-29 14:25:39 +01:00
Demon* const d = solver()->RevAlloc(new VarDemon(this, i));
loads_[i]->WhenRange(d);
}
}
void PushFromTop(int bin_index) {
2020-10-29 14:25:39 +01:00
IntVar* const load = loads_[bin_index];
2021-04-01 12:13:35 +02:00
const int64_t sum_min = sum_of_bound_variables_vector_[bin_index];
const int64_t sum_max = sum_of_all_variables_vector_[bin_index];
2010-10-13 16:22:18 +00:00
load->SetRange(sum_min, sum_max);
2021-04-01 12:13:35 +02:00
const int64_t slack_up = load->Max() - sum_min;
const int64_t slack_down = sum_max - load->Min();
2010-10-13 16:22:18 +00:00
DCHECK_GE(slack_down, 0);
DCHECK_GE(slack_up, 0);
int last_unbound = first_unbound_backward_vector_[bin_index];
for (; last_unbound >= 0; --last_unbound) {
const int var_index = ranked_[last_unbound];
2021-04-01 12:13:35 +02:00
const int64_t weight = weights_[var_index];
if (IsUndecided(var_index, bin_index)) {
if (weight > slack_up) {
SetImpossible(var_index, bin_index);
} else if (weight > slack_down) {
Assign(var_index, bin_index);
} else {
break;
}
}
}
first_unbound_backward_vector_.SetValue(solver(), bin_index, last_unbound);
}
2020-10-29 14:25:39 +01:00
void InitialPropagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& undecided) override {
Solver* const s = solver();
2021-04-01 12:13:35 +02:00
int64_t sum = 0LL;
for (const int value : forced) {
sum += weights_[value];
}
sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
for (const int value : undecided) {
sum += weights_[value];
}
sum_of_all_variables_vector_.SetValue(s, bin_index, sum);
first_unbound_backward_vector_.SetValue(s, bin_index, ranked_.size() - 1);
PushFromTop(bin_index);
}
void EndInitialPropagate() override {}
2020-10-29 14:25:39 +01:00
void Propagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& removed) override {
Solver* const s = solver();
2021-04-01 12:13:35 +02:00
int64_t down = sum_of_bound_variables_vector_[bin_index];
for (const int value : forced) {
down += weights_[value];
}
sum_of_bound_variables_vector_.SetValue(s, bin_index, down);
2021-04-01 12:13:35 +02:00
int64_t up = sum_of_all_variables_vector_[bin_index];
for (const int value : removed) {
up -= weights_[value];
}
sum_of_all_variables_vector_.SetValue(s, bin_index, up);
PushFromTop(bin_index);
}
2020-10-29 14:25:39 +01:00
void InitialPropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {
2016-11-29 13:40:04 +01:00
}
2020-10-29 14:25:39 +01:00
void PropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {}
void EndPropagate() override {}
2011-07-11 20:13:14 +00:00
2020-10-29 14:25:39 +01:00
void Accept(ModelVisitor* const visitor) const override {
visitor->BeginVisitExtension(ModelVisitor::kUsageEqualVariableExtension);
visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
weights_);
visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
loads_);
visitor->EndVisitExtension(ModelVisitor::kUsageEqualVariableExtension);
}
2020-10-22 23:36:58 +02:00
private:
const int vars_count_;
2021-04-01 12:13:35 +02:00
const std::vector<int64_t> weights_;
const int bins_count_;
2020-10-29 14:25:39 +01:00
const std::vector<IntVar*> loads_;
RevArray<int> first_unbound_backward_vector_;
2021-04-01 12:13:35 +02:00
RevArray<int64_t> sum_of_bound_variables_vector_;
RevArray<int64_t> sum_of_all_variables_vector_;
std::vector<int> ranked_;
};
class DimensionWeightedCallback2SumEqVar : public Dimension {
2020-10-22 23:36:58 +02:00
public:
class VarDemon : public Demon {
2020-10-22 23:36:58 +02:00
public:
2020-10-29 14:25:39 +01:00
VarDemon(DimensionWeightedCallback2SumEqVar* const dim, int index)
: dim_(dim), index_(index) {}
~VarDemon() override {}
2020-10-29 14:25:39 +01:00
void Run(Solver* const s) override { dim_->PushFromTop(index_); }
2020-10-22 23:36:58 +02:00
private:
2020-10-29 14:25:39 +01:00
DimensionWeightedCallback2SumEqVar* const dim_;
const int index_;
};
2020-10-29 14:25:39 +01:00
DimensionWeightedCallback2SumEqVar(Solver* const s, Pack* const p,
const Solver::IndexEvaluator2& weights,
int vars_count,
2020-10-29 14:25:39 +01:00
const std::vector<IntVar*>& loads)
2020-10-22 23:36:58 +02:00
: Dimension(s, p),
vars_count_(vars_count),
weights_(weights),
bins_count_(loads.size()),
loads_(loads),
first_unbound_backward_vector_(bins_count_, 0),
sum_of_bound_variables_vector_(bins_count_, 0LL),
2020-10-22 23:36:58 +02:00
sum_of_all_variables_vector_(bins_count_, 0LL),
ranked_(bins_count_) {
DCHECK(weights);
DCHECK_GT(vars_count_, 0);
DCHECK_GT(bins_count_, 0);
for (int b = 0; b < bins_count_; ++b) {
ranked_[b].resize(vars_count);
for (int i = 0; i < vars_count_; ++i) {
ranked_[b][i] = i;
}
SortIndexByWeight(&ranked_[b], weights_, b);
}
}
~DimensionWeightedCallback2SumEqVar() override {}
std::string DebugString() const override {
return "DimensionWeightedCallback2SumEqVar";
}
void Post() override {
for (int i = 0; i < bins_count_; ++i) {
2020-10-29 14:25:39 +01:00
Demon* const d = solver()->RevAlloc(new VarDemon(this, i));
loads_[i]->WhenRange(d);
}
}
void PushFromTop(int bin_index) {
2020-10-29 14:25:39 +01:00
IntVar* const load = loads_[bin_index];
2021-04-01 12:13:35 +02:00
const int64_t sum_min = sum_of_bound_variables_vector_[bin_index];
const int64_t sum_max = sum_of_all_variables_vector_[bin_index];
load->SetRange(sum_min, sum_max);
2021-04-01 12:13:35 +02:00
const int64_t slack_up = load->Max() - sum_min;
const int64_t slack_down = sum_max - load->Min();
DCHECK_GE(slack_down, 0);
DCHECK_GE(slack_up, 0);
int last_unbound = first_unbound_backward_vector_[bin_index];
for (; last_unbound >= 0; --last_unbound) {
const int var_index = ranked_[bin_index][last_unbound];
2021-04-01 12:13:35 +02:00
const int64_t weight = weights_(var_index, bin_index);
if (IsUndecided(var_index, bin_index)) {
if (weight > slack_up) {
SetImpossible(var_index, bin_index);
} else if (weight > slack_down) {
Assign(var_index, bin_index);
} else {
break;
}
}
}
first_unbound_backward_vector_.SetValue(solver(), bin_index, last_unbound);
}
2020-10-29 14:25:39 +01:00
void InitialPropagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& undecided) override {
Solver* const s = solver();
2021-04-01 12:13:35 +02:00
int64_t sum = 0LL;
for (const int value : forced) {
sum += weights_(value, bin_index);
}
sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
for (const int value : undecided) {
sum += weights_(value, bin_index);
}
sum_of_all_variables_vector_.SetValue(s, bin_index, sum);
first_unbound_backward_vector_.SetValue(s, bin_index,
ranked_[bin_index].size() - 1);
PushFromTop(bin_index);
}
void EndInitialPropagate() override {}
2020-10-29 14:25:39 +01:00
void Propagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& removed) override {
Solver* const s = solver();
2021-04-01 12:13:35 +02:00
int64_t down = sum_of_bound_variables_vector_[bin_index];
for (const int value : forced) {
down += weights_(value, bin_index);
}
sum_of_bound_variables_vector_.SetValue(s, bin_index, down);
2021-04-01 12:13:35 +02:00
int64_t up = sum_of_all_variables_vector_[bin_index];
for (const int value : removed) {
up -= weights_(value, bin_index);
}
sum_of_all_variables_vector_.SetValue(s, bin_index, up);
PushFromTop(bin_index);
}
2020-10-29 14:25:39 +01:00
void InitialPropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {
2016-11-29 13:40:04 +01:00
}
2020-10-29 14:25:39 +01:00
void PropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {}
void EndPropagate() override {}
2020-10-29 14:25:39 +01:00
void Accept(ModelVisitor* const visitor) const override {
visitor->BeginVisitExtension(ModelVisitor::kUsageEqualVariableExtension);
// TODO(user): Visit weight correctly
// visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
// weights_);
visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
loads_);
visitor->EndVisitExtension(ModelVisitor::kUsageEqualVariableExtension);
}
2020-10-22 23:36:58 +02:00
private:
const int vars_count_;
Solver::IndexEvaluator2 weights_;
const int bins_count_;
2020-10-29 14:25:39 +01:00
const std::vector<IntVar*> loads_;
RevArray<int> first_unbound_backward_vector_;
2021-04-01 12:13:35 +02:00
RevArray<int64_t> sum_of_bound_variables_vector_;
RevArray<int64_t> sum_of_all_variables_vector_;
std::vector<std::vector<int>> ranked_;
};
2010-09-15 12:42:33 +00:00
class AssignedWeightedSumDimension : public Dimension {
2020-10-22 23:36:58 +02:00
public:
2010-09-15 12:42:33 +00:00
class VarDemon : public Demon {
2020-10-22 23:36:58 +02:00
public:
2020-10-29 14:25:39 +01:00
explicit VarDemon(AssignedWeightedSumDimension* const dim) : dim_(dim) {}
~VarDemon() override {}
2010-09-15 12:42:33 +00:00
2020-10-29 14:25:39 +01:00
void Run(Solver* const s) override { dim_->PropagateAll(); }
2011-07-11 20:13:14 +00:00
2020-10-22 23:36:58 +02:00
private:
2020-10-29 14:25:39 +01:00
AssignedWeightedSumDimension* const dim_;
2010-09-15 12:42:33 +00:00
};
2020-10-29 14:25:39 +01:00
AssignedWeightedSumDimension(Solver* const s, Pack* const p,
2021-04-01 12:13:35 +02:00
const std::vector<int64_t>& weights,
2020-10-29 14:25:39 +01:00
int bins_count, IntVar* const cost_var)
2020-10-22 23:36:58 +02:00
: Dimension(s, p),
vars_count_(weights.size()),
weights_(weights),
bins_count_(bins_count),
cost_var_(cost_var),
first_unbound_backward_(0),
sum_of_assigned_items_(0LL),
sum_of_unassigned_items_(0LL),
ranked_(vars_count_),
2010-09-15 12:42:33 +00:00
sum_all_weights_(0LL) {
DCHECK(cost_var);
DCHECK_GT(vars_count_, 0);
DCHECK_GT(bins_count_, 0);
2010-09-15 12:42:33 +00:00
for (int i = 0; i < vars_count_; ++i) {
ranked_[i] = i;
}
SortIndexByWeight(&ranked_, weights_);
first_unbound_backward_.SetValue(s, ranked_.size() - 1);
2010-09-15 12:42:33 +00:00
}
~AssignedWeightedSumDimension() override {}
2010-09-15 12:42:33 +00:00
void Post() override {
2020-10-29 14:25:39 +01:00
Demon* const uv = solver()->RevAlloc(new VarDemon(this));
2010-09-15 12:42:33 +00:00
cost_var_->WhenRange(uv);
}
void PropagateAll() {
cost_var_->SetRange(sum_of_assigned_items_.Value(),
sum_all_weights_ - sum_of_unassigned_items_.Value());
2021-04-01 12:13:35 +02:00
const int64_t slack_up = cost_var_->Max() - sum_of_assigned_items_.Value();
const int64_t slack_down = sum_all_weights_ - cost_var_->Min();
int last_unbound = first_unbound_backward_.Value();
2010-09-15 12:42:33 +00:00
for (; last_unbound >= 0; --last_unbound) {
const int var_index = ranked_[last_unbound];
if (!IsAssignedStatusKnown(var_index)) {
2021-04-01 12:13:35 +02:00
const int64_t coefficient = weights_[var_index];
2010-09-15 12:42:33 +00:00
if (coefficient > slack_up) {
SetUnassigned(var_index);
} else if (coefficient > slack_down) {
SetAssigned(var_index);
} else {
break;
}
}
}
first_unbound_backward_.SetValue(solver(), last_unbound);
}
2020-10-29 14:25:39 +01:00
void InitialPropagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& undecided) override {}
2010-09-15 12:42:33 +00:00
void EndInitialPropagate() override {}
2010-09-15 12:42:33 +00:00
2020-10-29 14:25:39 +01:00
void InitialPropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {
2010-09-15 12:42:33 +00:00
for (int index = 0; index < vars_count_; ++index) {
sum_all_weights_ += weights_[index];
}
PropagateUnassigned(assigned, unassigned);
}
2020-10-29 14:25:39 +01:00
void Propagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& removed) override {}
2010-09-15 12:42:33 +00:00
2020-10-29 14:25:39 +01:00
void PropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {
2021-04-01 12:13:35 +02:00
int64_t sum_assigned = sum_of_assigned_items_.Value();
2010-09-15 12:42:33 +00:00
for (int index = 0; index < assigned.size(); ++index) {
const int var_index = assigned[index];
sum_assigned += weights_[var_index];
}
2021-04-01 12:13:35 +02:00
int64_t sum_unassigned = sum_of_unassigned_items_.Value();
2010-09-15 12:42:33 +00:00
for (int index = 0; index < unassigned.size(); ++index) {
const int var_index = unassigned[index];
sum_unassigned += weights_[var_index];
}
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
2010-09-15 12:42:33 +00:00
sum_of_assigned_items_.SetValue(s, sum_assigned);
sum_of_unassigned_items_.SetValue(s, sum_unassigned);
PropagateAll();
}
void EndPropagate() override {}
2011-07-11 20:13:14 +00:00
2020-10-29 14:25:39 +01:00
void Accept(ModelVisitor* const visitor) const override {
visitor->BeginVisitExtension(
ModelVisitor::kWeightedSumOfAssignedEqualVariableExtension);
visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
weights_);
visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
cost_var_);
visitor->EndVisitExtension(
ModelVisitor::kWeightedSumOfAssignedEqualVariableExtension);
}
2020-10-22 23:36:58 +02:00
private:
2010-09-15 12:42:33 +00:00
const int vars_count_;
2021-04-01 12:13:35 +02:00
const std::vector<int64_t> weights_;
2010-09-15 12:42:33 +00:00
const int bins_count_;
2020-10-29 14:25:39 +01:00
IntVar* const cost_var_;
2010-09-15 12:42:33 +00:00
Rev<int> first_unbound_backward_;
2021-04-01 12:13:35 +02:00
Rev<int64_t> sum_of_assigned_items_;
Rev<int64_t> sum_of_unassigned_items_;
std::vector<int> ranked_;
2021-04-01 12:13:35 +02:00
int64_t sum_all_weights_;
2010-09-15 12:42:33 +00:00
};
// ----- Count unassigned jobs dimension -----
class CountAssignedItemsDimension : public Dimension {
2020-10-22 23:36:58 +02:00
public:
2010-09-15 12:42:33 +00:00
class VarDemon : public Demon {
2020-10-22 23:36:58 +02:00
public:
2020-10-29 14:25:39 +01:00
explicit VarDemon(CountAssignedItemsDimension* const dim) : dim_(dim) {}
~VarDemon() override {}
2010-09-15 12:42:33 +00:00
2020-10-29 14:25:39 +01:00
void Run(Solver* const s) override { dim_->PropagateAll(); }
2011-07-11 20:13:14 +00:00
2020-10-22 23:36:58 +02:00
private:
2020-10-29 14:25:39 +01:00
CountAssignedItemsDimension* const dim_;
2010-09-15 12:42:33 +00:00
};
2020-10-29 14:25:39 +01:00
CountAssignedItemsDimension(Solver* const s, Pack* const p, int vars_count,
int bins_count, IntVar* const cost_var)
2020-10-22 23:36:58 +02:00
: Dimension(s, p),
vars_count_(vars_count),
bins_count_(bins_count),
cost_var_(cost_var),
first_unbound_backward_(0),
assigned_count_(0),
2010-09-15 12:42:33 +00:00
unassigned_count_(0) {
DCHECK(cost_var);
DCHECK_GT(vars_count, 0);
DCHECK_GT(bins_count, 0);
}
~CountAssignedItemsDimension() override {}
2010-09-15 12:42:33 +00:00
void Post() override {
2020-10-29 14:25:39 +01:00
Demon* const uv = solver()->RevAlloc(new VarDemon(this));
2010-09-15 12:42:33 +00:00
cost_var_->WhenRange(uv);
}
void PropagateAll() {
cost_var_->SetRange(assigned_count_.Value(),
vars_count_ - unassigned_count_.Value());
2010-09-15 12:42:33 +00:00
if (assigned_count_.Value() == cost_var_->Max()) {
UnassignAllRemainingItems();
} else if (cost_var_->Min() == vars_count_ - unassigned_count_.Value()) {
AssignAllRemainingItems();
}
}
2020-10-29 14:25:39 +01:00
void InitialPropagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& undecided) override {}
2010-09-15 12:42:33 +00:00
void EndInitialPropagate() override {}
2010-09-15 12:42:33 +00:00
2020-10-29 14:25:39 +01:00
void InitialPropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {
2010-09-15 12:42:33 +00:00
PropagateUnassigned(assigned, unassigned);
}
2020-10-29 14:25:39 +01:00
void Propagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& removed) override {}
2010-09-15 12:42:33 +00:00
2020-10-29 14:25:39 +01:00
void PropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {
Solver* const s = solver();
2010-09-15 12:42:33 +00:00
assigned_count_.SetValue(s, assigned_count_.Value() + assigned.size());
unassigned_count_.SetValue(s,
unassigned_count_.Value() + unassigned.size());
PropagateAll();
}
void EndPropagate() override {}
2011-07-11 20:13:14 +00:00
2020-10-29 14:25:39 +01:00
void Accept(ModelVisitor* const visitor) const override {
visitor->BeginVisitExtension(ModelVisitor::kCountAssignedItemsExtension);
visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
cost_var_);
visitor->EndVisitExtension(ModelVisitor::kCountAssignedItemsExtension);
}
2020-10-22 23:36:58 +02:00
private:
2010-09-15 12:42:33 +00:00
const int vars_count_;
const int bins_count_;
2020-10-29 14:25:39 +01:00
IntVar* const cost_var_;
2010-09-15 12:42:33 +00:00
Rev<int> first_unbound_backward_;
Rev<int> assigned_count_;
Rev<int> unassigned_count_;
};
// ----- Count used bin dimension -----
class CountUsedBinDimension : public Dimension {
2020-10-22 23:36:58 +02:00
public:
2010-09-15 12:42:33 +00:00
class VarDemon : public Demon {
2020-10-22 23:36:58 +02:00
public:
2020-10-29 14:25:39 +01:00
explicit VarDemon(CountUsedBinDimension* const dim) : dim_(dim) {}
~VarDemon() override {}
2010-09-15 12:42:33 +00:00
2020-10-29 14:25:39 +01:00
void Run(Solver* const s) override { dim_->PropagateAll(); }
2011-07-11 20:13:14 +00:00
2020-10-22 23:36:58 +02:00
private:
2020-10-29 14:25:39 +01:00
CountUsedBinDimension* const dim_;
2010-09-15 12:42:33 +00:00
};
2020-10-29 14:25:39 +01:00
CountUsedBinDimension(Solver* const s, Pack* const p, int vars_count,
int bins_count, IntVar* const count_var)
2020-10-22 23:36:58 +02:00
: Dimension(s, p),
vars_count_(vars_count),
bins_count_(bins_count),
count_var_(count_var),
used_(bins_count_),
candidates_(bins_count_, 0),
card_min_(0),
card_max_(bins_count_),
initial_min_(0),
initial_max_(0) {
2010-09-15 12:42:33 +00:00
DCHECK(count_var);
DCHECK_GT(vars_count, 0);
DCHECK_GT(bins_count, 0);
}
~CountUsedBinDimension() override {}
void Post() override {
2020-10-29 14:25:39 +01:00
Demon* const uv = solver()->RevAlloc(new VarDemon(this));
2010-09-15 12:42:33 +00:00
count_var_->WhenRange(uv);
initial_min_ = 0;
initial_max_ = bins_count_;
}
void PropagateAll() {
count_var_->SetRange(card_min_.Value(), card_max_.Value());
if (card_min_.Value() == count_var_->Max()) {
for (int bin_index = 0; bin_index < bins_count_; ++bin_index) {
if (!used_.IsSet(bin_index) && candidates_[bin_index] > 0) {
2010-09-15 12:42:33 +00:00
RemoveAllPossibleFromBin(bin_index);
}
}
} else if (card_max_.Value() == count_var_->Min()) {
for (int bin_index = 0; bin_index < bins_count_; ++bin_index) {
if (candidates_[bin_index] == 1) {
AssignFirstPossibleToBin(bin_index);
}
}
}
}
2020-10-29 14:25:39 +01:00
void InitialPropagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& undecided) override {
2017-04-19 16:20:56 +02:00
if (!forced.empty()) {
used_.SetToOne(solver(), bin_index);
2010-09-15 12:42:33 +00:00
initial_min_++;
2017-04-19 16:20:56 +02:00
} else if (!undecided.empty()) {
candidates_.SetValue(solver(), bin_index, undecided.size());
2010-09-15 12:42:33 +00:00
} else {
initial_max_--;
}
}
void EndInitialPropagate() override {
2010-09-15 12:42:33 +00:00
card_min_.SetValue(solver(), initial_min_);
card_max_.SetValue(solver(), initial_max_);
PropagateAll();
}
2020-10-29 14:25:39 +01:00
void InitialPropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {
2016-11-29 13:40:04 +01:00
}
2010-09-15 12:42:33 +00:00
2020-10-29 14:25:39 +01:00
void Propagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& removed) override {
if (!used_.IsSet(bin_index)) {
2017-04-19 16:20:56 +02:00
if (!forced.empty()) {
used_.SetToOne(solver(), bin_index);
2010-09-15 12:42:33 +00:00
card_min_.SetValue(solver(), card_min_.Value() + 1);
2017-04-19 16:20:56 +02:00
} else if (!removed.empty()) {
candidates_.SetValue(solver(), bin_index,
candidates_.Value(bin_index) - removed.size());
2010-09-15 12:42:33 +00:00
if (candidates_[bin_index] == 0) {
card_max_.SetValue(solver(), card_max_.Value() - 1);
}
}
}
}
2020-10-29 14:25:39 +01:00
void PropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {}
2010-09-15 12:42:33 +00:00
void EndPropagate() override { PropagateAll(); }
2011-07-11 20:13:14 +00:00
2020-10-29 14:25:39 +01:00
void Accept(ModelVisitor* const visitor) const override {
visitor->BeginVisitExtension(ModelVisitor::kCountUsedBinsExtension);
visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
count_var_);
visitor->EndVisitExtension(ModelVisitor::kCountUsedBinsExtension);
}
2020-10-22 23:36:58 +02:00
private:
2010-09-15 12:42:33 +00:00
const int vars_count_;
const int bins_count_;
2020-10-29 14:25:39 +01:00
IntVar* const count_var_;
RevBitSet used_;
RevArray<int> candidates_;
2010-09-15 12:42:33 +00:00
Rev<int> card_min_;
Rev<int> card_max_;
int initial_min_;
int initial_max_;
};
// ---------- Variable Usage Dimension ----------
// This is a very naive, but correct implementation of the constraint.
class VariableUsageDimension : public Dimension {
2020-10-22 23:36:58 +02:00
public:
2020-10-29 14:25:39 +01:00
VariableUsageDimension(Solver* const solver, Pack* const pack,
2021-04-01 12:13:35 +02:00
const std::vector<int64_t>& capacities,
2020-10-29 14:25:39 +01:00
const std::vector<IntVar*>& weights)
: Dimension(solver, pack), capacities_(capacities), weights_(weights) {}
~VariableUsageDimension() override {}
void Post() override {
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
const int num_bins = capacities_.size();
const int num_items = weights_.size();
for (int bin_index = 0; bin_index < num_bins; ++bin_index) {
2020-10-29 14:25:39 +01:00
std::vector<IntVar*> terms;
for (int item_index = 0; item_index < num_items; ++item_index) {
2020-10-29 14:25:39 +01:00
IntVar* const assign_var = AssignVar(item_index, bin_index);
terms.push_back(s->MakeProd(assign_var, weights_[item_index])->Var());
}
s->AddConstraint(s->MakeSumLessOrEqual(terms, capacities_[bin_index]));
}
}
2020-10-29 14:25:39 +01:00
void InitialPropagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& undecided) override {}
void InitialPropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {
2016-11-29 13:40:04 +01:00
}
void EndInitialPropagate() override {}
2020-10-29 14:25:39 +01:00
void Propagate(int bin_index, const std::vector<int>& forced,
const std::vector<int>& removed) override {}
void PropagateUnassigned(const std::vector<int>& assigned,
const std::vector<int>& unassigned) override {}
void EndPropagate() override {}
std::string DebugString() const override { return "VariableUsageDimension"; }
2011-07-11 20:13:14 +00:00
2020-10-29 14:25:39 +01:00
void Accept(ModelVisitor* const visitor) const override {
visitor->BeginVisitExtension(
ModelVisitor::kVariableUsageLessConstantExtension);
visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument,
capacities_);
visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
weights_);
visitor->EndVisitExtension(
ModelVisitor::kVariableUsageLessConstantExtension);
}
2020-10-22 23:36:58 +02:00
private:
2021-04-01 12:13:35 +02:00
const std::vector<int64_t> capacities_;
2020-10-29 14:25:39 +01:00
const std::vector<IntVar*> weights_;
};
2020-10-22 23:36:58 +02:00
} // namespace
2010-09-15 12:42:33 +00:00
// ---------- API ----------
void Pack::AddWeightedSumLessOrEqualConstantDimension(
2021-04-01 12:13:35 +02:00
const std::vector<int64_t>& weights, const std::vector<int64_t>& bounds) {
CHECK_EQ(weights.size(), vars_.size());
2010-10-13 16:22:18 +00:00
CHECK_EQ(bounds.size(), bins_);
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
Dimension* const dim =
s->RevAlloc(new DimensionLessThanConstant(s, this, weights, bounds));
2010-09-15 12:42:33 +00:00
dims_.push_back(dim);
}
void Pack::AddWeightedSumLessOrEqualConstantDimension(
2021-04-01 12:13:35 +02:00
Solver::IndexEvaluator1 weights, const std::vector<int64_t>& bounds) {
CHECK(weights != nullptr);
CHECK_EQ(bounds.size(), bins_);
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
Dimension* const dim = s->RevAlloc(new DimensionSumCallbackLessThanConstant(
s, this, weights, vars_.size(), bounds));
dims_.push_back(dim);
}
void Pack::AddWeightedSumLessOrEqualConstantDimension(
2021-04-01 12:13:35 +02:00
Solver::IndexEvaluator2 weights, const std::vector<int64_t>& bounds) {
CHECK(weights != nullptr);
CHECK_EQ(bounds.size(), bins_);
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
Dimension* const dim = s->RevAlloc(new DimensionLessThanConstantCallback2(
s, this, weights, vars_.size(), bounds));
dims_.push_back(dim);
}
2021-04-01 12:13:35 +02:00
void Pack::AddWeightedSumEqualVarDimension(const std::vector<int64_t>& weights,
2020-10-29 14:25:39 +01:00
const std::vector<IntVar*>& loads) {
CHECK_EQ(weights.size(), vars_.size());
2010-10-13 16:22:18 +00:00
CHECK_EQ(loads.size(), bins_);
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
Dimension* const dim =
s->RevAlloc(new DimensionWeightedSumEqVar(s, this, weights, loads));
dims_.push_back(dim);
}
void Pack::AddWeightedSumEqualVarDimension(Solver::IndexEvaluator2 weights,
2020-10-29 14:25:39 +01:00
const std::vector<IntVar*>& loads) {
CHECK(weights != nullptr);
CHECK_EQ(loads.size(), bins_);
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
Dimension* const dim = s->RevAlloc(new DimensionWeightedCallback2SumEqVar(
s, this, weights, vars_.size(), loads));
dims_.push_back(dim);
}
2021-04-01 12:13:35 +02:00
void Pack::AddWeightedSumOfAssignedDimension(
const std::vector<int64_t>& weights, IntVar* const cost_var) {
CHECK_EQ(weights.size(), vars_.size());
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
Dimension* const dim = s->RevAlloc(
new AssignedWeightedSumDimension(s, this, weights, bins_, cost_var));
2010-09-15 12:42:33 +00:00
dims_.push_back(dim);
}
void Pack::AddSumVariableWeightsLessOrEqualConstantDimension(
2021-04-01 12:13:35 +02:00
const std::vector<IntVar*>& usage, const std::vector<int64_t>& capacity) {
CHECK_EQ(usage.size(), vars_.size());
2011-09-05 13:45:29 +00:00
CHECK_EQ(capacity.size(), bins_);
2020-10-29 14:25:39 +01:00
Solver* const s = solver();
Dimension* const dim =
s->RevAlloc(new VariableUsageDimension(s, this, capacity, usage));
dims_.push_back(dim);
}
2020-10-29 14:25:39 +01:00
void Pack::AddCountUsedBinDimension(IntVar* const count_var) {
Solver* const s = solver();
Dimension* const dim = s->RevAlloc(
new CountUsedBinDimension(s, this, vars_.size(), bins_, count_var));
2010-09-15 12:42:33 +00:00
dims_.push_back(dim);
}
2020-10-29 14:25:39 +01:00
void Pack::AddCountAssignedItemsDimension(IntVar* const count_var) {
Solver* const s = solver();
Dimension* const dim = s->RevAlloc(
new CountAssignedItemsDimension(s, this, vars_.size(), bins_, count_var));
2010-09-15 12:42:33 +00:00
dims_.push_back(dim);
}
2020-10-29 14:25:39 +01:00
Pack* Solver::MakePack(const std::vector<IntVar*>& vars, int number_of_bins) {
return RevAlloc(new Pack(this, vars, number_of_bins));
2010-09-15 12:42:33 +00:00
}
2020-10-22 23:36:58 +02:00
} // namespace operations_research