Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
knapsack_solver.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#ifndef OR_TOOLS_ALGORITHMS_KNAPSACK_SOLVER_H_
15#define OR_TOOLS_ALGORITHMS_KNAPSACK_SOLVER_H_
16
17#include <cstdint>
18#include <memory>
19#include <string>
20#include <vector>
21
22#include "absl/strings/string_view.h"
24
25namespace operations_research {
26
27class BaseKnapsackSolver;
28
113 public:
201
202 explicit KnapsackSolver(const std::string& solver_name);
203 KnapsackSolver(SolverType solver_type, const std::string& solver_name);
204
205#ifndef SWIG
206 // This type is neither copyable nor movable.
209#endif
210
212
216 void Init(const std::vector<int64_t>& profits,
217 const std::vector<std::vector<int64_t> >& weights,
218 const std::vector<int64_t>& capacities);
219
223 int64_t Solve();
224
228 bool BestSolutionContains(int item_id) const;
232 bool IsSolutionOptimal() const { return is_solution_optimal_; }
233 std::string GetName() const;
234
235 bool use_reduction() const { return use_reduction_; }
236 void set_use_reduction(bool use_reduction) { use_reduction_ = use_reduction; }
237
243 void set_time_limit(double time_limit_seconds) {
244 time_limit_seconds_ = time_limit_seconds;
245 time_limit_ = std::make_unique<TimeLimit>(time_limit_seconds_);
246 }
247
248 private:
249 // Trivial reduction of capacity constraints when the capacity is higher than
250 // the sum of the weights of the items. Returns the number of reduced items.
251 int ReduceCapacities(int num_items,
252 const std::vector<std::vector<int64_t> >& weights,
253 const std::vector<int64_t>& capacities,
254 std::vector<std::vector<int64_t> >* reduced_weights,
255 std::vector<int64_t>* reduced_capacities);
256 int ReduceProblem(int num_items);
257 void ComputeAdditionalProfit(const std::vector<int64_t>& profits);
258 void InitReducedProblem(const std::vector<int64_t>& profits,
259 const std::vector<std::vector<int64_t> >& weights,
260 const std::vector<int64_t>& capacities);
261
262 std::unique_ptr<BaseKnapsackSolver> solver_;
263 std::vector<bool> known_value_;
264 std::vector<bool> best_solution_;
265 bool is_solution_optimal_ = false;
266 std::vector<int> mapping_reduced_item_id_;
267 bool is_problem_solved_;
268 int64_t additional_profit_;
269 bool use_reduction_;
270 double time_limit_seconds_;
271 std::unique_ptr<TimeLimit> time_limit_;
272};
273
274#if !defined(SWIG)
275// The following code defines needed classes for the KnapsackGenericSolver
276// class which is the entry point to extend knapsack with new constraints such
277// as conflicts between items.
278//
279// Constraints are enforced using KnapsackPropagator objects, in the current
280// code there is one propagator per dimension (KnapsackCapacityPropagator).
281// One of those propagators, named primary propagator, is used to guide the
282// search, i.e. decides which item should be assigned next.
283// Roughly speaking the search algorithm is:
284// - While not optimal
285// - Select next search node to expand
286// - Select next item_i to assign (using primary propagator)
287// - Generate a new search node where item_i is in the knapsack
288// - Check validity of this new partial solution (using propagators)
289// - If valid, add this new search node to the search
290// - Generate a new search node where item_i is not in the knapsack
291// - Check validity of this new partial solution (using propagators)
292// - If valid, add this new search node to the search
293//
294// TODO(user): Add a new propagator class for conflict constraint.
295// TODO(user): Add a new propagator class used as a guide when the problem has
296// several dimensions.
297
298// ----- KnapsackAssignment -----
299// KnapsackAssignment is a small struct used to pair an item with its
300// assignment. It is mainly used for search nodes and updates.
302 KnapsackAssignment(int _item_id, bool _is_in)
303 : item_id(_item_id), is_in(_is_in) {}
305 bool is_in;
306};
307
308// ----- KnapsackItem -----
309// KnapsackItem is a small struct to pair an item weight with its
310// corresponding profit.
311// The aim of the knapsack problem is to pack as many valuable items as
312// possible. A straight forward heuristic is to take those with the greatest
313// profit-per-unit-weight. This ratio is called efficiency in this
314// implementation. So items will be grouped in vectors, and sorted by
315// decreasing efficiency.
316// Note that profits are duplicated for each dimension. This is done to
317// simplify the code, especially the GetEfficiency method and vector sorting.
318// As there usually are only few dimensions, the overhead should not be an
319// issue.
321 KnapsackItem(int _id, int64_t _weight, int64_t _profit)
322 : id(_id), weight(_weight), profit(_profit) {}
323 double GetEfficiency(int64_t profit_max) const {
324 return (weight > 0)
325 ? static_cast<double>(profit) / static_cast<double>(weight)
326 : static_cast<double>(profit_max);
327 }
328
329 // The 'id' field is used to retrieve the initial item in order to
330 // communicate with other propagators and state.
331 const int id;
332 const int64_t weight;
333 const int64_t profit;
334};
336
337// ----- KnapsackSearchNode -----
338// KnapsackSearchNode is a class used to describe a decision in the decision
339// search tree.
340// The node is defined by a pointer to the parent search node and an
341// assignment (see KnapsackAssignment).
342// As the current state is not explicitly stored in a search node, one should
343// go through the search tree to incrementally build a partial solution from
344// a previous search node.
346 public:
349
350#ifndef SWIG
351 // This type is neither copyable nor movable.
354#endif
355
356 int depth() const { return depth_; }
357 const KnapsackSearchNode* parent() const { return parent_; }
358 const KnapsackAssignment& assignment() const { return assignment_; }
359
360 int64_t current_profit() const { return current_profit_; }
361 void set_current_profit(int64_t profit) { current_profit_ = profit; }
362
363 int64_t profit_upper_bound() const { return profit_upper_bound_; }
364 void set_profit_upper_bound(int64_t profit) { profit_upper_bound_ = profit; }
365
366 int next_item_id() const { return next_item_id_; }
367 void set_next_item_id(int id) { next_item_id_ = id; }
368
369 private:
370 // 'depth' field is used to navigate efficiently through the search tree
371 // (see KnapsackSearchPath).
372 int depth_;
373 const KnapsackSearchNode* const parent_;
374 KnapsackAssignment assignment_;
375
376 // 'current_profit' and 'profit_upper_bound' fields are used to sort search
377 // nodes using a priority queue. That allows to pop the node with the best
378 // upper bound, and more importantly to stop the search when optimality is
379 // proved.
380 int64_t current_profit_;
381 int64_t profit_upper_bound_;
382
383 // 'next_item_id' field allows to avoid an O(number_of_items) scan to find
384 // next item to select. This is done for free by the upper bound computation.
385 int next_item_id_;
386};
387
388// ----- KnapsackSearchPath -----
389// KnapsackSearchPath is a small class used to represent the path between a
390// node to another node in the search tree.
391// As the solution state is not stored for each search node, the state should
392// be rebuilt at each node. One simple solution is to apply all decisions
393// between the node 'to' and the root. This can be computed in
394// O(number_of_items).
395//
396// However, it is possible to achieve better average complexity. Two
397// consecutively explored nodes are usually close enough (i.e., much less than
398// number_of_items) to benefit from an incremental update from the node
399// 'from' to the node 'to'.
400//
401// The 'via' field is the common parent of 'from' field and 'to' field.
402// So the state can be built by reverting all decisions from 'from' to 'via'
403// and then applying all decisions from 'via' to 'to'.
405 public:
407 const KnapsackSearchNode& to);
408
409#ifndef SWIG
410 // This type is neither copyable nor movable.
413#endif
414
415 void Init();
416 const KnapsackSearchNode& from() const { return from_; }
417 const KnapsackSearchNode& via() const { return *via_; }
418 const KnapsackSearchNode& to() const { return to_; }
420 int depth) const;
421
422 private:
423 const KnapsackSearchNode& from_;
424 const KnapsackSearchNode* via_; // Computed in 'Init'.
425 const KnapsackSearchNode& to_;
426};
427
428// ----- KnapsackState -----
429// KnapsackState represents a partial solution to the knapsack problem.
431 public:
433
434#ifndef SWIG
435 // This type is neither copyable nor movable.
436 KnapsackState(const KnapsackState&) = delete;
438#endif
439
440 // Initializes vectors with number_of_items set to false (i.e. not bound yet).
441 void Init(int number_of_items);
442 // Updates the state by applying or reverting a decision.
443 // Returns false if fails, i.e. trying to apply an inconsistent decision
444 // to an already assigned item.
445 bool UpdateState(bool revert, const KnapsackAssignment& assignment);
446
447 int GetNumberOfItems() const { return is_bound_.size(); }
448 bool is_bound(int id) const { return is_bound_.at(id); }
449 bool is_in(int id) const { return is_in_.at(id); }
450
451 private:
452 // Vectors 'is_bound_' and 'is_in_' contain a boolean value for each item.
453 // 'is_bound_(item_i)' is false when there is no decision for item_i yet.
454 // When item_i is bound, 'is_in_(item_i)' represents the presence (true) or
455 // the absence (false) of item_i in the current solution.
456 std::vector<bool> is_bound_;
457 std::vector<bool> is_in_;
458};
459
460// ----- KnapsackPropagator -----
461// KnapsackPropagator is the base class for modeling and propagating a
462// constraint given an assignment.
463//
464// When some work has to be done both by the base and the derived class,
465// a protected pure virtual method ending by 'Propagator' is defined.
466// For instance, 'Init' creates a vector of items, and then calls
467// 'InitPropagator' to let the derived class perform its own initialization.
469 public:
470 explicit KnapsackPropagator(const KnapsackState& state);
471
472#ifndef SWIG
473 // This type is neither copyable nor movable.
476#endif
477
478 virtual ~KnapsackPropagator();
479
480 // Initializes data structure and then calls InitPropagator.
481 void Init(const std::vector<int64_t>& profits,
482 const std::vector<int64_t>& weights);
483
484 // Updates data structure and then calls UpdatePropagator.
485 // Returns false when failure.
486 bool Update(bool revert, const KnapsackAssignment& assignment);
487 // ComputeProfitBounds should set 'profit_lower_bound_' and
488 // 'profit_upper_bound_' which are constraint specific.
489 virtual void ComputeProfitBounds() = 0;
490 // Returns the id of next item to assign.
491 // Returns kNoSelection when all items are bound.
492 virtual int GetNextItemId() const = 0;
493
494 int64_t current_profit() const { return current_profit_; }
495 int64_t profit_lower_bound() const { return profit_lower_bound_; }
496 int64_t profit_upper_bound() const { return profit_upper_bound_; }
497
498 // Copies the current state into 'solution'.
499 // All unbound items are set to false (i.e. not in the knapsack).
500 // When 'has_one_propagator' is true, CopyCurrentSolutionPropagator is called
501 // to have a better solution. When there is only one propagator
502 // there is no need to check the solution with other propagators, so the
503 // partial solution can be smartly completed.
504 void CopyCurrentStateToSolution(bool has_one_propagator,
505 std::vector<bool>* solution) const;
506
507 protected:
508 // Initializes data structure. This method is called after initialization
509 // of KnapsackPropagator data structure.
510 virtual void InitPropagator() = 0;
511
512 // Updates internal data structure incrementally. This method is called
513 // after update of KnapsackPropagator data structure.
514 virtual bool UpdatePropagator(bool revert,
515 const KnapsackAssignment& assignment) = 0;
516
517 // Copies the current state into 'solution'.
518 // Only unbound items have to be copied as CopyCurrentSolution was already
519 // called with current state.
520 // This method is useful when a propagator is able to find a better solution
521 // than the blind instantiation to false of unbound items.
523 std::vector<bool>* solution) const = 0;
524
525 const KnapsackState& state() const { return state_; }
526 const std::vector<KnapsackItemPtr>& items() const { return items_; }
527
528 void set_profit_lower_bound(int64_t profit) { profit_lower_bound_ = profit; }
529 void set_profit_upper_bound(int64_t profit) { profit_upper_bound_ = profit; }
530
531 private:
532 std::vector<KnapsackItemPtr> items_;
533 int64_t current_profit_;
534 int64_t profit_lower_bound_;
535 int64_t profit_upper_bound_;
536 const KnapsackState& state_;
537};
538
539// ----- KnapsackCapacityPropagator -----
540// KnapsackCapacityPropagator is a KnapsackPropagator used to enforce
541// a capacity constraint.
542// As a KnapsackPropagator is supposed to compute profit lower and upper
543// bounds, and get the next item to select, it can be seen as a 0-1 Knapsack
544// solver. The most efficient way to compute the upper bound is to iterate on
545// items in profit-per-unit-weight decreasing order. The break item is
546// commonly defined as the first item for which there is not enough remaining
547// capacity. Selecting this break item as the next-item-to-assign usually
548// gives the best results (see Greenberg & Hegerich).
549//
550// This is exactly what is implemented in this class.
551//
552// When there is only one propagator, it is possible to compute a better
553// profit lower bound almost for free. During the scan to find the
554// break element all unbound items are added just as if they were part of
555// the current solution. This is used in both ComputeProfitBounds and
556// CopyCurrentSolutionPropagator.
557// For incrementality reasons, the ith item should be accessible in O(1). That's
558// the reason why the item vector has to be duplicated 'sorted_items_'.
560 public:
561 KnapsackCapacityPropagator(const KnapsackState& state, int64_t capacity);
562
563#ifndef SWIG
564 // This type is neither copyable nor movable.
567 delete;
568#endif
569
571 void ComputeProfitBounds() override;
572 int GetNextItemId() const override { return break_item_id_; }
573
574 protected:
575 // Initializes KnapsackCapacityPropagator (e.g., sort items in decreasing
576 // order).
577 void InitPropagator() override;
578 // Updates internal data structure incrementally (i.e., 'consumed_capacity_')
579 // to avoid a O(number_of_items) scan.
580 bool UpdatePropagator(bool revert,
581 const KnapsackAssignment& assignment) override;
583 std::vector<bool>* solution) const override;
584
585 private:
586 // An obvious additional profit upper bound corresponds to the linear
587 // relaxation: remaining_capacity * efficiency of the break item.
588 // It is possible to do better in O(1), using Martello-Toth bound U2.
589 // The main idea is to enforce integrality constraint on the break item,
590 // ie. either the break item is part of the solution, either it is not.
591 // So basically the linear relaxation is done on the item before the break
592 // item, or the one after the break item.
593 // This is what GetAdditionalProfit method implements.
594 int64_t GetAdditionalProfit(int64_t remaining_capacity,
595 int break_item_id) const;
596
597 const int64_t capacity_;
598 int64_t consumed_capacity_;
599 int break_item_id_;
600 std::vector<KnapsackItemPtr> sorted_items_;
601 int64_t profit_max_;
602};
603
604// ----- BaseKnapsackSolver -----
605// This is the base class for knapsack solvers.
607 public:
608 explicit BaseKnapsackSolver(absl::string_view solver_name)
609 : solver_name_(solver_name) {}
610 virtual ~BaseKnapsackSolver() = default;
611
612 // Initializes the solver and enters the problem to be solved.
613 virtual void Init(const std::vector<int64_t>& profits,
614 const std::vector<std::vector<int64_t> >& weights,
615 const std::vector<int64_t>& capacities) = 0;
616
617 // Gets the lower and upper bound when the item is in or out of the knapsack.
618 // To ensure objects are correctly initialized, this method should not be
619 // called before ::Init.
620 virtual void GetLowerAndUpperBoundWhenItem(int item_id, bool is_item_in,
621 int64_t* lower_bound,
622 int64_t* upper_bound);
623
624 // Solves the problem and returns the profit of the optimal solution.
625 virtual int64_t Solve(TimeLimit* time_limit, double time_limit_in_seconds,
626 bool* is_solution_optimal) = 0;
627
628 // Returns true if the item 'item_id' is packed in the optimal knapsack.
629 virtual bool best_solution(int item_id) const = 0;
630
631 virtual std::string GetName() const { return solver_name_; }
632
633 private:
634 const std::string solver_name_;
635};
636
637// ----- KnapsackGenericSolver -----
638// KnapsackGenericSolver is the multi-dimensional knapsack solver class.
639// In the current implementation, the next item to assign is given by the
640// primary propagator. Using SetPrimaryPropagator allows changing the default
641// (propagator of the first dimension), and selecting another dimension when
642// more constrained.
643// TODO(user): In the case of a multi-dimensional knapsack problem, implement
644// an aggregated propagator to combine all dimensions and give a better guide
645// to select the next item (see, for instance, Dobson's aggregated efficiency).
647 public:
648 explicit KnapsackGenericSolver(const std::string& solver_name);
649
650#ifndef SWIG
651 // This type is neither copyable nor movable.
654#endif
655
656 ~KnapsackGenericSolver() override;
657
658 // Initializes the solver and enters the problem to be solved.
659 void Init(const std::vector<int64_t>& profits,
660 const std::vector<std::vector<int64_t> >& weights,
661 const std::vector<int64_t>& capacities) override;
662 int GetNumberOfItems() const { return state_.GetNumberOfItems(); }
663 void GetLowerAndUpperBoundWhenItem(int item_id, bool is_item_in,
664 int64_t* lower_bound,
665 int64_t* upper_bound) override;
666
667 // Sets which propagator should be used to guide the search.
668 // 'primary_propagator_id' should be in 0..p-1 with p the number of
669 // propagators.
670 void set_primary_propagator_id(int primary_propagator_id) {
671 primary_propagator_id_ = primary_propagator_id;
672 }
673
674 // Solves the problem and returns the profit of the optimal solution.
675 int64_t Solve(TimeLimit* time_limit, double time_limit_in_seconds,
676 bool* is_solution_optimal) override;
677 // Returns true if the item 'item_id' is packed in the optimal knapsack.
678 bool best_solution(int item_id) const override {
679 return best_solution_.at(item_id);
680 }
681
682 private:
683 // Clears internal data structure.
684 void Clear();
685
686 // Updates all propagators reverting/applying all decision on the path.
687 // Returns true if fails. Note that, even if fails, all propagators should
688 // be updated to be in a stable state in order to stay incremental.
689 bool UpdatePropagators(const KnapsackSearchPath& path);
690 // Updates all propagators reverting/applying one decision.
691 // Return true if fails. Note that, even if fails, all propagators should
692 // be updated to be in a stable state in order to stay incremental.
693 bool IncrementalUpdate(bool revert, const KnapsackAssignment& assignment);
694 // Updates the best solution if the current solution has a better profit.
695 void UpdateBestSolution();
696
697 // Returns true if new relevant search node was added to the nodes array, that
698 // means this node should be added to the search queue too.
699 bool MakeNewNode(const KnapsackSearchNode& node, bool is_in);
700
701 // Gets the aggregated (min) profit upper bound among all propagators.
702 int64_t GetAggregatedProfitUpperBound() const;
703 bool HasOnePropagator() const { return propagators_.size() == 1; }
704 int64_t GetCurrentProfit() const {
705 return propagators_.at(primary_propagator_id_)->current_profit();
706 }
707 int64_t GetNextItemId() const {
708 return propagators_.at(primary_propagator_id_)->GetNextItemId();
709 }
710
711 std::vector<KnapsackPropagator*> propagators_;
712 int primary_propagator_id_;
713 std::vector<KnapsackSearchNode*> search_nodes_;
714 KnapsackState state_;
715 int64_t best_solution_profit_;
716 std::vector<bool> best_solution_;
717};
718#endif // SWIG
719} // namespace operations_research
720
721#endif // OR_TOOLS_ALGORITHMS_KNAPSACK_SOLVER_H_
virtual bool best_solution(int item_id) const =0
Returns true if the item 'item_id' is packed in the optimal knapsack.
virtual int64_t Solve(TimeLimit *time_limit, double time_limit_in_seconds, bool *is_solution_optimal)=0
Solves the problem and returns the profit of the optimal solution.
virtual void Init(const std::vector< int64_t > &profits, const std::vector< std::vector< int64_t > > &weights, const std::vector< int64_t > &capacities)=0
Initializes the solver and enters the problem to be solved.
BaseKnapsackSolver(absl::string_view solver_name)
virtual void GetLowerAndUpperBoundWhenItem(int item_id, bool is_item_in, int64_t *lower_bound, int64_t *upper_bound)
--— BaseKnapsackSolver --—
virtual std::string GetName() const
void CopyCurrentStateToSolutionPropagator(std::vector< bool > *solution) const override
KnapsackCapacityPropagator & operator=(const KnapsackCapacityPropagator &)=delete
KnapsackCapacityPropagator(const KnapsackState &state, int64_t capacity)
--— KnapsackCapacityPropagator --—
KnapsackCapacityPropagator(const KnapsackCapacityPropagator &)=delete
This type is neither copyable nor movable.
bool UpdatePropagator(bool revert, const KnapsackAssignment &assignment) override
Returns false when the propagator fails.
void GetLowerAndUpperBoundWhenItem(int item_id, bool is_item_in, int64_t *lower_bound, int64_t *upper_bound) override
--— BaseKnapsackSolver --—
void set_primary_propagator_id(int primary_propagator_id)
KnapsackGenericSolver(const KnapsackGenericSolver &)=delete
This type is neither copyable nor movable.
bool best_solution(int item_id) const override
Returns true if the item 'item_id' is packed in the optimal knapsack.
void Init(const std::vector< int64_t > &profits, const std::vector< std::vector< int64_t > > &weights, const std::vector< int64_t > &capacities) override
Initializes the solver and enters the problem to be solved.
KnapsackGenericSolver & operator=(const KnapsackGenericSolver &)=delete
KnapsackGenericSolver(const std::string &solver_name)
--— KnapsackGenericSolver --—
int64_t Solve(TimeLimit *time_limit, double time_limit_in_seconds, bool *is_solution_optimal) override
Solves the problem and returns the profit of the optimal solution.
KnapsackPropagator & operator=(const KnapsackPropagator &)=delete
virtual int GetNextItemId() const =0
void CopyCurrentStateToSolution(bool has_one_propagator, std::vector< bool > *solution) const
bool Update(bool revert, const KnapsackAssignment &assignment)
void Init(const std::vector< int64_t > &profits, const std::vector< int64_t > &weights)
Initializes data structure and then calls InitPropagator.
const KnapsackState & state() const
KnapsackPropagator(const KnapsackState &state)
--— KnapsackPropagator --—
virtual void CopyCurrentStateToSolutionPropagator(std::vector< bool > *solution) const =0
KnapsackPropagator(const KnapsackPropagator &)=delete
This type is neither copyable nor movable.
virtual bool UpdatePropagator(bool revert, const KnapsackAssignment &assignment)=0
const std::vector< KnapsackItemPtr > & items() const
KnapsackSearchNode(const KnapsackSearchNode *parent, const KnapsackAssignment &assignment)
--— KnapsackSearchNode --—
const KnapsackAssignment & assignment() const
KnapsackSearchNode & operator=(const KnapsackSearchNode &)=delete
const KnapsackSearchNode * parent() const
KnapsackSearchNode(const KnapsackSearchNode &)=delete
This type is neither copyable nor movable.
const KnapsackSearchNode & via() const
KnapsackSearchPath(const KnapsackSearchNode &from, const KnapsackSearchNode &to)
--— KnapsackSearchPath --—
const KnapsackSearchNode & to() const
const KnapsackSearchNode & from() const
KnapsackSearchPath(const KnapsackSearchPath &)=delete
This type is neither copyable nor movable.
const KnapsackSearchNode * MoveUpToDepth(const KnapsackSearchNode &node, int depth) const
KnapsackSearchPath & operator=(const KnapsackSearchPath &)=delete
void set_time_limit(double time_limit_seconds)
KnapsackSolver(const KnapsackSolver &)=delete
This type is neither copyable nor movable.
bool BestSolutionContains(int item_id) const
void Init(const std::vector< int64_t > &profits, const std::vector< std::vector< int64_t > > &weights, const std::vector< int64_t > &capacities)
KnapsackSolver(const std::string &solver_name)
--— KnapsackSolver --—
KnapsackSolver & operator=(const KnapsackSolver &)=delete
void set_use_reduction(bool use_reduction)
KnapsackState(const KnapsackState &)=delete
This type is neither copyable nor movable.
bool UpdateState(bool revert, const KnapsackAssignment &assignment)
Returns false when the state is invalid.
void Init(int number_of_items)
Initializes vectors with number_of_items set to false (i.e. not bound yet).
KnapsackState & operator=(const KnapsackState &)=delete
KnapsackState()
--— KnapsackState --—
double upper_bound
double lower_bound
const int64_t profit_max
time_limit
Definition solve.cc:22
double solution
In SWIG mode, we don't want anything besides these top-level includes.
KnapsackItem * KnapsackItemPtr
KnapsackAssignment(int _item_id, bool _is_in)
KnapsackItem(int _id, int64_t _weight, int64_t _profit)
double GetEfficiency(int64_t profit_max) const