26#include "absl/base/attributes.h"
42 void Reset()
override;
50 double new_value,
double old_value)
override;
53 double coefficient)
override;
59 int64_t
nodes()
const override;
65 bool IsLP()
const override;
66 bool IsMIP()
const override;
84 bool IsKnapsackModel()
const;
85 bool IsVariableFixedToValue(
const MPVariable* var,
double value)
const;
86 bool IsVariableFixed(
const MPVariable* var)
const;
87 double GetVariableValueFromSolution(
const MPVariable* var)
const;
90 std::unique_ptr<KnapsackSolver> knapsack_solver_;
91 std::vector<int64_t> profits_;
92 std::vector<std::vector<int64_t>> weights_;
93 std::vector<int64_t> capacities_;
104 if (!IsKnapsackModel()) {
105 LOG(ERROR) <<
"Model is not a knapsack model";
115 if (profits_.size() <= 64 && capacities_.size() == 1) {
119 std::make_unique<KnapsackSolver>(solver_type,
"linear_solver");
120 const double time_limit_seconds =
122 ? (
static_cast<double>(
solver_->time_limit()) / 1000.0)
123 : std::numeric_limits<double>::infinity();
124 knapsack_solver_->set_time_limit(time_limit_seconds);
125 knapsack_solver_->Init(profits_, weights_, capacities_);
126 knapsack_solver_->Solve();
130 for (
int var_id = 0; var_id <
solver_->variables_.size(); ++var_id) {
132 const double value = GetVariableValueFromSolution(var);
144 knapsack_solver_.reset(
nullptr);
148 NonIncrementalChange();
152 NonIncrementalChange();
156 NonIncrementalChange();
160 NonIncrementalChange();
164 NonIncrementalChange();
168 NonIncrementalChange();
173 double new_value,
double old_value) {
174 NonIncrementalChange();
178 NonIncrementalChange();
182 const MPVariable*
const variable,
double coefficient) {
183 NonIncrementalChange();
187 NonIncrementalChange();
197 int constraint_index)
const {
203 int variable_index)
const {
215 return "knapsack_solver-0.0";
222 for (
int column = 0; column <
solver_->variables_.size(); ++column) {
229 weights_.resize(
solver_->constraints_.size());
230 capacities_.resize(
solver_->constraints_.size(),
231 std::numeric_limits<int64_t>::max());
232 for (
int row = 0; row <
solver_->constraints_.size(); ++row) {
234 double fixed_usage = 0.0;
236 std::vector<double> coefficients(
solver_->variables_.size() + 1, 0.0);
237 for (
const auto& entry : ct->coefficients_) {
238 const int var_index = entry.first->index();
240 if (IsVariableFixedToValue(entry.first, 1.0)) {
241 fixed_usage += entry.second;
242 }
else if (!IsVariableFixedToValue(entry.first, 0.0)) {
243 coefficients[var_index] = entry.second;
248 const double capacity = ct->
ub() - fixed_usage;
250 coefficients[
solver_->variables_.size()] = capacity;
251 double relative_error = 0.0;
252 double scaling_factor = 0.0;
254 std::numeric_limits<int64_t>::max(),
255 &scaling_factor, &relative_error);
258 std::vector<int64_t> scaled_coefficients(
solver_->variables_.size(), 0);
259 for (
const auto& entry : ct->coefficients_) {
260 if (!IsVariableFixed(entry.first)) {
261 scaled_coefficients[entry.first->index()] =
262 static_cast<int64_t
>(round(scaling_factor * entry.second)) / gcd;
265 weights_[row].swap(scaled_coefficients);
267 static_cast<int64_t
>(round(scaling_factor * capacity)) / gcd;
272 std::vector<double> coefficients(
solver_->variables_.size(), 0.0);
273 for (
const auto& entry :
solver_->objective_->coefficients_) {
277 if (!IsVariableFixed(entry.first)) {
278 coefficients[entry.first->index()] = entry.second;
281 double relative_error = 0.0;
282 double scaling_factor = 0.0;
284 std::numeric_limits<int64_t>::max(),
285 &scaling_factor, &relative_error);
287 std::vector<int64_t> scaled_coefficients(
solver_->variables_.size(), 0);
288 for (
const auto& entry :
solver_->objective_->coefficients_) {
289 scaled_coefficients[entry.first->index()] =
290 static_cast<int64_t
>(round(scaling_factor * entry.second)) / gcd;
292 profits_.swap(scaled_coefficients);
311bool KnapsackInterface::IsKnapsackModel()
const {
313 for (
int column = 0; column <
solver_->variables_.size(); ++column) {
315 if (var->
lb() <= -1.0 || var->
ub() >= 2.0 || !var->
integer()) {
320 for (
const auto& entry :
solver_->objective_->coefficients_) {
321 if (entry.second < 0) {
326 for (
int row = 0; row <
solver_->constraints_.size(); ++row) {
328 if (ct->lb() > 0.0) {
331 for (
const auto& entry : ct->coefficients_) {
332 if (entry.second < 0) {
341bool KnapsackInterface::IsVariableFixedToValue(
const MPVariable* var,
342 double value)
const {
343 const double lb_round_up = ceil(var->lb());
344 return value == lb_round_up &&
floor(var->ub()) == lb_round_up;
347bool KnapsackInterface::IsVariableFixed(
const MPVariable* var)
const {
348 return IsVariableFixedToValue(var, 0.0) || IsVariableFixedToValue(var, 1.0);
351double KnapsackInterface::GetVariableValueFromSolution(
353 return !IsVariableFixedToValue(var, 0.0) &&
354 (knapsack_solver_->BestSolutionContains(var->index()) ||
355 IsVariableFixedToValue(var, 1.0))
363const void*
const kRegisterKnapsack ABSL_ATTRIBUTE_UNUSED = [] {
void SetDualTolerance(double value) override
~KnapsackInterface() override
void SetVariableInteger(int index, bool integer) override
int64_t nodes() const override
void ClearConstraint(MPConstraint *constraint) override
void ExtractNewVariables() override
int64_t iterations() const override
std::string SolverVersion() const override
void ExtractNewConstraints() override
void SetVariableBounds(int index, double lb, double ub) override
void SetCoefficient(MPConstraint *constraint, const MPVariable *variable, double new_value, double old_value) override
void AddVariable(MPVariable *var) override
void SetLpAlgorithm(int value) override
void SetRelativeMipGap(double value) override
void AddRowConstraint(MPConstraint *ct) override
void * underlying_solver() override
void SetObjectiveCoefficient(const MPVariable *variable, double coefficient) override
MPSolver::BasisStatus row_status(int constraint_index) const override
void SetObjectiveOffset(double value) override
void SetConstraintBounds(int index, double lb, double ub) override
void ClearObjective() override
void SetPrimalTolerance(double value) override
void SetOptimizationDirection(bool maximize) override
MPSolver::BasisStatus column_status(int variable_index) const override
KnapsackInterface(MPSolver *solver)
void ExtractObjective() override
void SetParameters(const MPSolverParameters ¶m) override
void SetScalingMode(int value) override
MPSolver::ResultStatus Solve(const MPSolverParameters ¶m) override
bool IsContinuous() const override
bool IsMIP() const override
bool IsLP() const override
void SetPresolveMode(int value) override
SolverType
Enum controlling which underlying algorithm is used.
@ KNAPSACK_64ITEMS_SOLVER
@ KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER
double ub() const
Returns the upper bound.
static MPSolverInterfaceFactoryRepository * GetInstance()
void Register(MPSolverInterfaceFactory factory, MPSolver::OptimizationProblemType problem_type, std::function< bool()> is_runtime_ready={})
void set_variable_as_extracted(int var_index, bool extracted)
friend class MPConstraint
void set_constraint_as_extracted(int ct_index, bool extracted)
void ResetExtractionInformation()
int last_constraint_index_
bool variable_is_extracted(int var_index) const
static constexpr int64_t kUnknownNumberOfNodes
MPSolverInterface(MPSolver *solver)
void SetCommonParameters(const MPSolverParameters ¶m)
MPSolver::ResultStatus result_status_
SynchronizationStatus sync_status_
@ MODEL_INVALID
the model is trivially invalid (NaN coefficients, etc).
@ FEASIBLE
feasible, or stopped by limit.
@ KNAPSACK_MIXED_INTEGER_PROGRAMMING
The class for variables of a Mathematical Programming (MP) model.
bool integer() const
Returns the integrality requirement of the variable.
double lb() const
Returns the lower bound.
double ub() const
Returns the upper bound.
void set_solution_value(double value)
double GetBestScalingOfDoublesToInt64(absl::Span< const double > input, absl::Span< const double > lb, absl::Span< const double > ub, int64_t max_absolute_sum)
int64_t ComputeGcdOfRoundedDoubles(absl::Span< const double > x, double scaling_factor)