knapsack_solver.h
Go to the documentation of this file.
1 // Copyright 2010-2018 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 //
15 // This library solves knapsacks:
16 // - 0-1 knapsack problems,
17 // - Multi-dimensional knapsack problems,
18 // - TODO(user) Multi-dimensional knapsack problem with n-ary conflicts
19 // between items.
20 //
21 // Given n items, each with a profit and a weight, given a knapsack of
22 // capacity c, the goal is to find a subset of items which fits inside c
23 // and maximizes the total profit.
24 // The knapsack problem can easily be extended from 1 to d dimensions.
25 // As an example, this can be useful to constrain the maximum number of
26 // items inside the knapsack.
27 // Without loss of generality, profits and weights are assumed to be positive.
28 //
29 // From a mathematical point of view, the multi-dimensional knapsack problem
30 // can be modeled by d linear constraints:
31 // ForEach(j:1..d)(Sum(i:1..n)(weight_ij * item_i) <= c_j
32 // where item_i is a 0-1 integer variable.
33 // Then the goal is to maximize: Sum(i:1..n)(profit_i * item_i).
34 //
35 // There are several ways to solve knapsack problems. One of the most
36 // efficient ways is based on dynamic programming (mainly when weights, profits
37 // and dimensions are small, the algorithm runs in pseudo polynomial time).
38 // Unfortunately when adding conflict constraints the problem becomes strongly
39 // NP-hard, i.e. there is no pseudo-polynomial algorithm to solve it.
40 // That's the reason why the most of the following code is based on branch and
41 // bound search.
42 //
43 // For instance to solve a 2-dimensional knapsack problem with 9 items,
44 // one just has to feed a profit vector with the 9 profits, a vector of 2
45 // vectors for weights, and a vector of capacities.
46 // E.g.:
47 // vector: profits = [1, 2, 3, 4, 5, 6, 7, 8, 9]
48 // vector of vector: weights = [ [1, 2, 3, 4, 5, 6, 7, 8, 9],
49 // [1, 1, 1, 1, 1, 1, 1, 1, 1]]
50 // vector: capacities = [34, 4]
51 // And then:
52 // KnapsackSolver solver(
53 // KnapsackSolver::KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER,
54 // "Multi-dimensional solver");
55 // solver.Init(profits, weights, capacities);
56 // int64 profit = solver.Solve();
57 //
58 // Currently four algorithms are implemented:
59 // - KNAPSACK_BRUTE_FORCE_SOLVER: Limited to 30 items and one dimension, this
60 // solver uses a brute force algorithm, ie. explores all possible states.
61 // Experiments show competitive performance for instances with less than
62 // 15 items.
63 // - KNAPSACK_64ITEMS_SOLVER: Limited to 64 items and one dimension, this
64 // solver uses a branch & bound algorithm. This solver is about 4 times
65 // faster than KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER.
66 // - KNAPSACK_DYNAMIC_PROGRAMMING_SOLVER: Limited to one dimension, this solver
67 // is based on a dynamic programming algorithm. The time and space
68 // complexity is O(capacity * number_of_items).
69 // - KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER: This solver can deal
70 // with both large number of items and several dimensions. This solver is
71 // based on branch and bound.
72 // - KNAPSACK_MULTIDIMENSION_CBC_MIP_SOLVER: This solver can deal with both
73 // large number of items and several dimensions. This solver is based on
74 // Integer Programming solver CBC.
75 // - KNAPSACK_MULTIDIMENSION_SCIP_MIP_SOLVER: This solver can deal with both
76 // large number of items and several dimensions. This solver is based on
77 // Integer Programming solver SCIP.
78 //
79 #ifndef OR_TOOLS_ALGORITHMS_KNAPSACK_SOLVER_H_
80 #define OR_TOOLS_ALGORITHMS_KNAPSACK_SOLVER_H_
81 
82 #include <math.h>
83 
84 #include <memory>
85 #include <string>
86 #include <vector>
87 
88 #include "absl/memory/memory.h"
89 #include "ortools/base/basictypes.h"
90 #include "ortools/base/integral_types.h"
91 #include "ortools/base/logging.h"
92 #include "ortools/base/macros.h"
93 #include "ortools/util/time_limit.h"
94 
95 namespace operations_research {
96 
97 // ----- KnapsackSolver -----
98 // KnapsackSolver is a factory for knapsack solvers. Several solvers are
99 // implemented, some can deal with a limited number of items, some can deal with
100 // several dimensions.
101 //
102 // Besides the four algorithms listed above, KnapsackSolver also implements a
103 // problem reduction algorithm based on lower
104 // and upper bounds (see Ingargolia and Korsh: A reduction algorithm for
105 // zero-one single knapsack problems. Management Science, 1973). This reduction
106 // method is preferred to better algorithms (see, for instance, Martello
107 // and Toth: A new algorithm for the 0-1 knapsack problem. Management Science,
108 // 1988), because it remains valid with more complex problems, e.g.,
109 // multi-dimensional, conflicts...
110 //
111 // The main idea is to compute lower and upper bounds for each item in or out
112 // of the knapsack; if the best lower bound is strictly greater than the upper
113 // bound when an item is in, then this item is surely not in the optimal
114 // solution.
115 class BaseKnapsackSolver;
116 
118  public:
119  enum SolverType {
123 #if defined(USE_CBC)
124  KNAPSACK_MULTIDIMENSION_CBC_MIP_SOLVER = 3,
125 #endif // USE_CBC
127 #if defined(USE_SCIP)
128  KNAPSACK_MULTIDIMENSION_SCIP_MIP_SOLVER = 6,
129 #endif // USE_SCIP
130  };
131 
132  explicit KnapsackSolver(const std::string& solver_name);
133  KnapsackSolver(SolverType solver_type, const std::string& solver_name);
134  virtual ~KnapsackSolver();
135 
136  // Initializes the solver and enters the problem to be solved.
137  void Init(const std::vector<int64>& profits,
138  const std::vector<std::vector<int64> >& weights,
139  const std::vector<int64>& capacities);
140 
141  // Solves the problem and returns the profit of the optimal solution.
142  int64 Solve();
143 
144  // Returns true if the item 'item_id' is packed in the optimal knapsack.
145  bool BestSolutionContains(int item_id) const;
146  // Returns true if the solution was proven optimal.
147  bool IsSolutionOptimal() const { return is_solution_optimal_; }
148  std::string GetName() const;
149 
150  bool use_reduction() const { return use_reduction_; }
151  void set_use_reduction(bool use_reduction) { use_reduction_ = use_reduction; }
152 
153  // Time limit in seconds. When a finite time limit is set the solution
154  // obtained might not be optimal if the limit is reached.
155  void set_time_limit(double time_limit_seconds) {
156  time_limit_seconds_ = time_limit_seconds;
157  time_limit_ = absl::make_unique<TimeLimit>(time_limit_seconds_);
158  }
159 
160  private:
161  // Trivial reduction of capacity constraints when the capacity is higher than
162  // the sum of the weights of the items. Returns the number of reduced items.
163  int ReduceCapacities(int num_items,
164  const std::vector<std::vector<int64> >& weights,
165  const std::vector<int64>& capacities,
166  std::vector<std::vector<int64> >* reduced_weights,
167  std::vector<int64>* reduced_capacities);
168  int ReduceProblem(int num_items);
169  void ComputeAdditionalProfit(const std::vector<int64>& profits);
170  void InitReducedProblem(const std::vector<int64>& profits,
171  const std::vector<std::vector<int64> >& weights,
172  const std::vector<int64>& capacities);
173 
174  std::unique_ptr<BaseKnapsackSolver> solver_;
175  std::vector<bool> known_value_;
176  std::vector<bool> best_solution_;
177  bool is_solution_optimal_ = false;
178  std::vector<int> mapping_reduced_item_id_;
179  bool is_problem_solved_;
180  int64 additional_profit_;
181  bool use_reduction_;
182  double time_limit_seconds_;
183  std::unique_ptr<TimeLimit> time_limit_;
184 
185  DISALLOW_COPY_AND_ASSIGN(KnapsackSolver);
186 };
187 
188 #if !defined(SWIG)
189 // The following code defines needed classes for the KnapsackGenericSolver
190 // class which is the entry point to extend knapsack with new constraints such
191 // as conflicts between items.
192 //
193 // Constraints are enforced using KnapsackPropagator objects, in the current
194 // code there is one propagator per dimension (KnapsackCapacityPropagator).
195 // One of those propagators, named master propagator, is used to guide the
196 // search, i.e. decides which item should be assigned next.
197 // Roughly speaking the search algorithm is:
198 // - While not optimal
199 // - Select next search node to expand
200 // - Select next item_i to assign (using master propagator)
201 // - Generate a new search node where item_i is in the knapsack
202 // - Check validity of this new partial solution (using propagators)
203 // - If valid, add this new search node to the search
204 // - Generate a new search node where item_i is not in the knapsack
205 // - Check validity of this new partial solution (using propagators)
206 // - If valid, add this new search node to the search
207 //
208 // TODO(user): Add a new propagator class for conflict constraint.
209 // TODO(user): Add a new propagator class used as a guide when the problem has
210 // several dimensions.
211 
212 // ----- KnapsackAssignement -----
213 // KnapsackAssignement is a small struct used to pair an item with its
214 // assignment. It is mainly used for search nodes and updates.
216  KnapsackAssignment(int _item_id, bool _is_in)
217  : item_id(_item_id), is_in(_is_in) {}
218  int item_id;
219  bool is_in;
220 };
221 
222 // ----- KnapsackItem -----
223 // KnapsackItem is a small struct to pair an item weight with its
224 // corresponding profit.
225 // The aim of the knapsack problem is to pack as many valuable items as
226 // possible. A straight forward heuristic is to take those with the greatest
227 // profit-per-unit-weight. This ratio is called efficiency in this
228 // implementation. So items will be grouped in vectors, and sorted by
229 // decreasing efficiency.
230 // Note that profits are duplicated for each dimension. This is done to
231 // simplify the code, especially the GetEfficiency method and vector sorting.
232 // As there usually are only few dimensions, the overhead should not be an
233 // issue.
234 struct KnapsackItem {
235  KnapsackItem(int _id, int64 _weight, int64 _profit)
236  : id(_id), weight(_weight), profit(_profit) {}
237  double GetEfficiency(int64 profit_max) const {
238  return (weight > 0)
239  ? static_cast<double>(profit) / static_cast<double>(weight)
240  : static_cast<double>(profit_max);
241  }
242 
243  // The 'id' field is used to retrieve the initial item in order to
244  // communicate with other propagators and state.
245  const int id;
246  const int64 weight;
247  const int64 profit;
248 };
250 
251 // ----- KnapsackSearchNode -----
252 // KnapsackSearchNode is a class used to describe a decision in the decision
253 // search tree.
254 // The node is defined by a pointer to the parent search node and an
255 // assignment (see KnapsackAssignement).
256 // As the current state is not explicitly stored in a search node, one should
257 // go through the search tree to incrementally build a partial solution from
258 // a previous search node.
260  public:
263  int depth() const { return depth_; }
264  const KnapsackSearchNode* const parent() const { return parent_; }
265  const KnapsackAssignment& assignment() const { return assignment_; }
266 
267  int64 current_profit() const { return current_profit_; }
268  void set_current_profit(int64 profit) { current_profit_ = profit; }
269 
270  int64 profit_upper_bound() const { return profit_upper_bound_; }
271  void set_profit_upper_bound(int64 profit) { profit_upper_bound_ = profit; }
272 
273  int next_item_id() const { return next_item_id_; }
274  void set_next_item_id(int id) { next_item_id_ = id; }
275 
276  private:
277  // 'depth' field is used to navigate efficiently through the search tree
278  // (see KnapsackSearchPath).
279  int depth_;
280  const KnapsackSearchNode* const parent_;
281  KnapsackAssignment assignment_;
282 
283  // 'current_profit' and 'profit_upper_bound' fields are used to sort search
284  // nodes using a priority queue. That allows to pop the node with the best
285  // upper bound, and more importantly to stop the search when optimality is
286  // proved.
287  int64 current_profit_;
288  int64 profit_upper_bound_;
289 
290  // 'next_item_id' field allows to avoid an O(number_of_items) scan to find
291  // next item to select. This is done for free by the upper bound computation.
292  int next_item_id_;
293 
294  DISALLOW_COPY_AND_ASSIGN(KnapsackSearchNode);
295 };
296 
297 // ----- KnapsackSearchPath -----
298 // KnapsackSearchPath is a small class used to represent the path between a
299 // node to another node in the search tree.
300 // As the solution state is not stored for each search node, the state should
301 // be rebuilt at each node. One simple solution is to apply all decisions
302 // between the node 'to' and the root. This can be computed in
303 // O(number_of_items).
304 //
305 // However, it is possible to achieve better average complexity. Two
306 // consecutively explored nodes are usually close enough (i.e., much less than
307 // number_of_items) to benefit from an incremental update from the node
308 // 'from' to the node 'to'.
309 //
310 // The 'via' field is the common parent of 'from' field and 'to' field.
311 // So the state can be built by reverting all decisions from 'from' to 'via'
312 // and then applying all decisions from 'via' to 'to'.
314  public:
316  const KnapsackSearchNode& to);
317  void Init();
318  const KnapsackSearchNode& from() const { return from_; }
319  const KnapsackSearchNode& via() const { return *via_; }
320  const KnapsackSearchNode& to() const { return to_; }
322  int depth) const;
323 
324  private:
325  const KnapsackSearchNode& from_;
326  const KnapsackSearchNode* via_; // Computed in 'Init'.
327  const KnapsackSearchNode& to_;
328 
329  DISALLOW_COPY_AND_ASSIGN(KnapsackSearchPath);
330 };
331 
332 // ----- KnapsackState -----
333 // KnapsackState represents a partial solution to the knapsack problem.
335  public:
336  KnapsackState();
337 
338  // Initializes vectors with number_of_items set to false (i.e. not bound yet).
339  void Init(int number_of_items);
340  // Updates the state by applying or reverting a decision.
341  // Returns false if fails, i.e. trying to apply an inconsistent decision
342  // to an already assigned item.
343  bool UpdateState(bool revert, const KnapsackAssignment& assignment);
344 
345  int GetNumberOfItems() const { return is_bound_.size(); }
346  bool is_bound(int id) const { return is_bound_.at(id); }
347  bool is_in(int id) const { return is_in_.at(id); }
348 
349  private:
350  // Vectors 'is_bound_' and 'is_in_' contain a boolean value for each item.
351  // 'is_bound_(item_i)' is false when there is no decision for item_i yet.
352  // When item_i is bound, 'is_in_(item_i)' represents the presence (true) or
353  // the absence (false) of item_i in the current solution.
354  std::vector<bool> is_bound_;
355  std::vector<bool> is_in_;
356 
357  DISALLOW_COPY_AND_ASSIGN(KnapsackState);
358 };
359 
360 // ----- KnapsackPropagator -----
361 // KnapsackPropagator is the base class for modeling and propagating a
362 // constraint given an assignment.
363 //
364 // When some work has to be done both by the base and the derived class,
365 // a protected pure virtual method ending by 'Propagator' is defined.
366 // For instance, 'Init' creates a vector of items, and then calls
367 // 'InitPropagator' to let the derived class perform its own initialization.
369  public:
370  explicit KnapsackPropagator(const KnapsackState& state);
371  virtual ~KnapsackPropagator();
372 
373  // Initializes data structure and then calls InitPropagator.
374  void Init(const std::vector<int64>& profits,
375  const std::vector<int64>& weights);
376 
377  // Updates data structure and then calls UpdatePropagator.
378  // Returns false when failure.
379  bool Update(bool revert, const KnapsackAssignment& assignment);
380  // ComputeProfitBounds should set 'profit_lower_bound_' and
381  // 'profit_upper_bound_' which are constraint specific.
382  virtual void ComputeProfitBounds() = 0;
383  // Returns the id of next item to assign.
384  // Returns kNoSelection when all items are bound.
385  virtual int GetNextItemId() const = 0;
386 
387  int64 current_profit() const { return current_profit_; }
388  int64 profit_lower_bound() const { return profit_lower_bound_; }
389  int64 profit_upper_bound() const { return profit_upper_bound_; }
390 
391  // Copies the current state into 'solution'.
392  // All unbound items are set to false (i.e. not in the knapsack).
393  // When 'has_one_propagator' is true, CopyCurrentSolutionPropagator is called
394  // to have a better solution. When there is only one propagator
395  // there is no need to check the solution with other propagators, so the
396  // partial solution can be smartly completed.
397  void CopyCurrentStateToSolution(bool has_one_propagator,
398  std::vector<bool>* solution) const;
399 
400  protected:
401  // Initializes data structure. This method is called after initialization
402  // of KnapsackPropagator data structure.
403  virtual void InitPropagator() = 0;
404 
405  // Updates internal data structure incrementally. This method is called
406  // after update of KnapsackPropagator data structure.
407  virtual bool UpdatePropagator(bool revert,
408  const KnapsackAssignment& assignment) = 0;
409 
410  // Copies the current state into 'solution'.
411  // Only unbound items have to be copied as CopyCurrentSolution was already
412  // called with current state.
413  // This method is useful when a propagator is able to find a better solution
414  // than the blind instantiation to false of unbound items.
416  std::vector<bool>* solution) const = 0;
417 
418  const KnapsackState& state() const { return state_; }
419  const std::vector<KnapsackItemPtr>& items() const { return items_; }
420 
421  void set_profit_lower_bound(int64 profit) { profit_lower_bound_ = profit; }
422  void set_profit_upper_bound(int64 profit) { profit_upper_bound_ = profit; }
423 
424  private:
425  std::vector<KnapsackItemPtr> items_;
426  int64 current_profit_;
427  int64 profit_lower_bound_;
428  int64 profit_upper_bound_;
429  const KnapsackState& state_;
430 
431  DISALLOW_COPY_AND_ASSIGN(KnapsackPropagator);
432 };
433 
434 // ----- KnapsackCapacityPropagator -----
435 // KnapsackCapacityPropagator is a KnapsackPropagator used to enforce
436 // a capacity constraint.
437 // As a KnapsackPropagator is supposed to compute profit lower and upper
438 // bounds, and get the next item to select, it can be seen as a 0-1 Knapsack
439 // solver. The most efficient way to compute the upper bound is to iterate on
440 // items in profit-per-unit-weight decreasing order. The break item is
441 // commonly defined as the first item for which there is not enough remaining
442 // capacity. Selecting this break item as the next-item-to-assign usually
443 // gives the best results (see Greenberg & Hegerich).
444 //
445 // This is exactly what is implemented in this class.
446 //
447 // When there is only one propagator, it is possible to compute a better
448 // profit lower bound almost for free. During the scan to find the
449 // break element all unbound items are added just as if they were part of
450 // the current solution. This is used in both ComputeProfitBounds and
451 // CopyCurrentSolutionPropagator.
452 // For incrementality reasons, the ith item should be accessible in O(1). That's
453 // the reason why the item vector has to be duplicated 'sorted_items_'.
455  public:
456  KnapsackCapacityPropagator(const KnapsackState& state, int64 capacity);
457  ~KnapsackCapacityPropagator() override;
458  void ComputeProfitBounds() override;
459  int GetNextItemId() const override { return break_item_id_; }
460 
461  protected:
462  // Initializes KnapsackCapacityPropagator (e.g., sort items in decreasing
463  // order).
464  void InitPropagator() override;
465  // Updates internal data structure incrementally (i.e., 'consumed_capacity_')
466  // to avoid a O(number_of_items) scan.
467  bool UpdatePropagator(bool revert,
468  const KnapsackAssignment& assignment) override;
470  std::vector<bool>* solution) const override;
471 
472  private:
473  // An obvious additional profit upper bound corresponds to the linear
474  // relaxation: remaining_capacity * efficiency of the break item.
475  // It is possible to do better in O(1), using Martello-Toth bound U2.
476  // The main idea is to enforce integrality constraint on the break item,
477  // ie. either the break item is part of the solution, either it is not.
478  // So basically the linear relaxation is done on the item before the break
479  // item, or the one after the break item.
480  // This is what GetAdditionalProfit method implements.
481  int64 GetAdditionalProfit(int64 remaining_capacity, int break_item_id) const;
482 
483  const int64 capacity_;
484  int64 consumed_capacity_;
485  int break_item_id_;
486  std::vector<KnapsackItemPtr> sorted_items_;
487  int64 profit_max_;
488 
489  DISALLOW_COPY_AND_ASSIGN(KnapsackCapacityPropagator);
490 };
491 
492 // ----- BaseKnapsackSolver -----
493 // This is the base class for knapsack solvers.
495  public:
496  explicit BaseKnapsackSolver(const std::string& solver_name)
497  : solver_name_(solver_name) {}
498  virtual ~BaseKnapsackSolver() {}
499 
500  // Initializes the solver and enters the problem to be solved.
501  virtual void Init(const std::vector<int64>& profits,
502  const std::vector<std::vector<int64> >& weights,
503  const std::vector<int64>& capacities) = 0;
504 
505  // Gets the lower and upper bound when the item is in or out of the knapsack.
506  // To ensure objects are correctly initialized, this method should not be
507  // called before ::Init.
508  virtual void GetLowerAndUpperBoundWhenItem(int item_id, bool is_item_in,
509  int64* lower_bound,
510  int64* upper_bound);
511 
512  // Solves the problem and returns the profit of the optimal solution.
513  virtual int64 Solve(TimeLimit* time_limit, bool* is_solution_optimal) = 0;
514 
515  // Returns true if the item 'item_id' is packed in the optimal knapsack.
516  virtual bool best_solution(int item_id) const = 0;
517 
518  virtual std::string GetName() const { return solver_name_; }
519 
520  private:
521  const std::string solver_name_;
522 };
523 
524 // ----- KnapsackGenericSolver -----
525 // KnapsackGenericSolver is the multi-dimensional knapsack solver class.
526 // In the current implementation, the next item to assign is given by the
527 // master propagator. Using SetMasterPropagator allows changing the default
528 // (propagator of the first dimension), and selecting another dimension when
529 // more constrained.
530 // TODO(user): In the case of a multi-dimensional knapsack problem, implement
531 // an aggregated propagator to combine all dimensions and give a better guide
532 // to select the next item (see, for instance, Dobson's aggregated efficiency).
534  public:
535  explicit KnapsackGenericSolver(const std::string& solver_name);
536  ~KnapsackGenericSolver() override;
537 
538  // Initializes the solver and enters the problem to be solved.
539  void Init(const std::vector<int64>& profits,
540  const std::vector<std::vector<int64> >& weights,
541  const std::vector<int64>& capacities) override;
542  int GetNumberOfItems() const { return state_.GetNumberOfItems(); }
543  void GetLowerAndUpperBoundWhenItem(int item_id, bool is_item_in,
544  int64* lower_bound,
545  int64* upper_bound) override;
546 
547  // Sets which propagator should be used to guide the search.
548  // 'master_propagator_id' should be in 0..p-1 with p the number of
549  // propagators.
550  void set_master_propagator_id(int master_propagator_id) {
551  master_propagator_id_ = master_propagator_id;
552  }
553 
554  // Solves the problem and returns the profit of the optimal solution.
555  int64 Solve(TimeLimit* time_limit, bool* is_solution_optimal) override;
556  // Returns true if the item 'item_id' is packed in the optimal knapsack.
557  bool best_solution(int item_id) const override {
558  return best_solution_.at(item_id);
559  }
560 
561  private:
562  // Clears internal data structure.
563  void Clear();
564 
565  // Updates all propagators reverting/applying all decision on the path.
566  // Returns true if fails. Note that, even if fails, all propagators should
567  // be updated to be in a stable state in order to stay incremental.
568  bool UpdatePropagators(const KnapsackSearchPath& path);
569  // Updates all propagators reverting/applying one decision.
570  // Return true if fails. Note that, even if fails, all propagators should
571  // be updated to be in a stable state in order to stay incremental.
572  bool IncrementalUpdate(bool revert, const KnapsackAssignment& assignment);
573  // Updates the best solution if the current solution has a better profit.
574  void UpdateBestSolution();
575 
576  // Returns true if new relevant search node was added to the nodes array, that
577  // means this node should be added to the search queue too.
578  bool MakeNewNode(const KnapsackSearchNode& node, bool is_in);
579 
580  // Gets the aggregated (min) profit upper bound among all propagators.
581  int64 GetAggregatedProfitUpperBound() const;
582  bool HasOnePropagator() const { return propagators_.size() == 1; }
583  int64 GetCurrentProfit() const {
584  return propagators_.at(master_propagator_id_)->current_profit();
585  }
586  int64 GetNextItemId() const {
587  return propagators_.at(master_propagator_id_)->GetNextItemId();
588  }
589 
590  std::vector<KnapsackPropagator*> propagators_;
591  int master_propagator_id_;
592  std::vector<KnapsackSearchNode*> search_nodes_;
593  KnapsackState state_;
594  int64 best_solution_profit_;
595  std::vector<bool> best_solution_;
596 
597  DISALLOW_COPY_AND_ASSIGN(KnapsackGenericSolver);
598 };
599 #endif // SWIG
600 } // namespace operations_research
601 
602 #endif // OR_TOOLS_ALGORITHMS_KNAPSACK_SOLVER_H_
const KnapsackSearchNode & to() const
const KnapsackSearchNode & via() const
KnapsackItem(int _id, int64 _weight, int64 _profit)
KnapsackAssignment(int _item_id, bool _is_in)
const KnapsackState & state() const
const std::vector< KnapsackItemPtr > & items() const
int GetNextItemId() const override
Returns the id of next item to assign.
void InitPropagator() override
Initializes KnapsackCapacityPropagator (e.g., sort items in decreasing order).
void Init(int number_of_items)
Initializes vectors with number_of_items set to false (i.e. not bound yet).
bool Update(bool revert, const KnapsackAssignment &assignment)
Updates data structure and then calls UpdatePropagator.
virtual void InitPropagator()=0
Initializes data structure.
void CopyCurrentStateToSolutionPropagator(std::vector< bool > *solution) const override
Copies the current state into 'solution'.
virtual void Init(const std::vector< int64 > &profits, const std::vector< std::vector< int64 > > &weights, const std::vector< int64 > &capacities)=0
Initializes the solver and enters the problem to be solved.
bool BestSolutionContains(int item_id) const
Returns true if the item 'item_id' is packed in the optimal knapsack.
const KnapsackSearchNode & from() const
double GetEfficiency(int64 profit_max) const
--— KnapsackSearchNode --— KnapsackSearchNode is a class used to describe a decision in the decision ...
bool IsSolutionOptimal() const
Returns true if the solution was proven optimal.
bool best_solution(int item_id) const override
Returns true if the item 'item_id' is packed in the optimal knapsack.
void set_master_propagator_id(int master_propagator_id)
Sets which propagator should be used to guide the search.
--— KnapsackSearchPath --— KnapsackSearchPath is a small class used to represent the path between a n...
--— KnapsackGenericSolver --— KnapsackGenericSolver is the multi-dimensional knapsack solver class.
const int id
The 'id' field is used to retrieve the initial item in order to communicate with other propagators an...
KnapsackSearchPath(const KnapsackSearchNode &from, const KnapsackSearchNode &to)
virtual bool UpdatePropagator(bool revert, const KnapsackAssignment &assignment)=0
Updates internal data structure incrementally.
KnapsackSearchNode(const KnapsackSearchNode *const parent, const KnapsackAssignment &assignment)
virtual bool best_solution(int item_id) const =0
Returns true if the item 'item_id' is packed in the optimal knapsack.
void Init(const std::vector< int64 > &profits, const std::vector< std::vector< int64 > > &weights, const std::vector< int64 > &capacities) override
Initializes the solver and enters the problem to be solved.
const KnapsackAssignment & assignment() const
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
void set_use_reduction(bool use_reduction)
virtual void GetLowerAndUpperBoundWhenItem(int item_id, bool is_item_in, int64 *lower_bound, int64 *upper_bound)
Gets the lower and upper bound when the item is in or out of the knapsack.
void Init(const std::vector< int64 > &profits, const std::vector< int64 > &weights)
Initializes data structure and then calls InitPropagator.
const KnapsackSearchNode *const parent() const
KnapsackSolver(const std::string &solver_name)
BaseKnapsackSolver(const std::string &solver_name)
KnapsackCapacityPropagator(const KnapsackState &state, int64 capacity)
int64 Solve(TimeLimit *time_limit, bool *is_solution_optimal) override
Solves the problem and returns the profit of the optimal solution.
void Init(const std::vector< int64 > &profits, const std::vector< std::vector< int64 > > &weights, const std::vector< int64 > &capacities)
Initializes the solver and enters the problem to be solved.
bool UpdatePropagator(bool revert, const KnapsackAssignment &assignment) override
Updates internal data structure incrementally (i.e., 'consumed_capacity_') to avoid a O(number_of_ite...
--— KnapsackCapacityPropagator --— KnapsackCapacityPropagator is a KnapsackPropagator used to enforce...
--— KnapsackPropagator --— KnapsackPropagator is the base class for modeling and propagating a constr...
virtual int64 Solve(TimeLimit *time_limit, bool *is_solution_optimal)=0
Solves the problem and returns the profit of the optimal solution.
virtual void CopyCurrentStateToSolutionPropagator(std::vector< bool > *solution) const =0
Copies the current state into 'solution'.
const KnapsackSearchNode * MoveUpToDepth(const KnapsackSearchNode &node, int depth) const
void set_time_limit(double time_limit_seconds)
Time limit in seconds.
KnapsackGenericSolver(const std::string &solver_name)
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in c...
--— KnapsackAssignement --— KnapsackAssignement is a small struct used to pair an item with its assig...
bool UpdateState(bool revert, const KnapsackAssignment &assignment)
Updates the state by applying or reverting a decision.
void CopyCurrentStateToSolution(bool has_one_propagator, std::vector< bool > *solution) const
Copies the current state into 'solution'.
virtual void ComputeProfitBounds()=0
ComputeProfitBounds should set 'profit_lower_bound_' and 'profit_upper_bound_' which are constraint s...
void ComputeProfitBounds() override
ComputeProfitBounds should set 'profit_lower_bound_' and 'profit_upper_bound_' which are constraint s...
virtual int GetNextItemId() const =0
Returns the id of next item to assign.
void GetLowerAndUpperBoundWhenItem(int item_id, bool is_item_in, int64 *lower_bound, int64 *upper_bound) override
Gets the lower and upper bound when the item is in or out of the knapsack.
--— BaseKnapsackSolver --— This is the base class for knapsack solvers.
KnapsackPropagator(const KnapsackState &state)
--— KnapsackItem --— KnapsackItem is a small struct to pair an item weight with its corresponding pro...
int64 Solve()
Solves the problem and returns the profit of the optimal solution.
KnapsackItem * KnapsackItemPtr
virtual std::string GetName() const
--— KnapsackState --— KnapsackState represents a partial solution to the knapsack problem.