Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
branch_and_bound_knapsack_example.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
47#include <iostream>
48
49#include <Knapsack.H>
50#include <State_Search.H>
51#include <tpl_array.H>
52
53using Aleph::Array;
55
56namespace
57{
58
59namespace Search = Aleph::Search;
60
61struct KnapsackState
62{
63 size_t index = 0;
64 int weight = 0;
65 double value = 0;
67
68 explicit KnapsackState(const size_t n = 0)
69 : index(0), weight(0), value(0), chosen(n, 0)
70 {
71 // empty
72 }
73};
74
75class KnapsackBBDomain
76{
77public:
78 struct Move
79 {
80 bool take = false;
81 };
82
83 using State = KnapsackState;
84 using Objective = double;
85
86 KnapsackBBDomain(const Array<Knapsack_Item<int, double>> &items,
87 const int capacity)
88 : items_(items), capacity_(capacity)
89 {
90 // empty
91 }
92
93 // A solution is complete once every item is fixed to take/skip.
94 bool is_complete(const State &state) const
95 {
96 return state.index == items_.size();
97 }
98
99 // Exact value of a complete solution.
100 Objective objective_value(const State &state) const
101 {
102 return state.value;
103 }
104
105 // Fractional upper bound used to prune branches that cannot beat the incumbent.
106 Objective bound(const State &state) const
107 {
108 Objective optimistic = state.value;
109 int remaining = capacity_ - state.weight;
110
111 for (size_t i = state.index; i < items_.size() and remaining > 0; ++i)
112 if (items_[i].weight <= remaining)
113 {
114 optimistic += items_[i].value;
115 remaining -= items_[i].weight;
116 }
117 else
118 {
119 optimistic += items_[i].value*(static_cast<Objective>(remaining)/
120 static_cast<Objective>(items_[i].weight));
121 break;
122 }
123
124 return optimistic;
125 }
126
127 // Apply one branch decision.
128 void apply(State &state, const Move &move) const
129 {
130 if (move.take)
131 {
132 state.weight += items_[state.index].weight;
133 state.value += items_[state.index].value;
134 state.chosen[state.index] = 1;
135 }
136 else
137 state.chosen[state.index] = 0;
138
139 ++state.index;
140 }
141
142 // Undo exactly the last branch decision.
143 void undo(State &state, const Move &move) const
144 {
145 --state.index;
146 if (move.take)
147 {
148 state.weight -= items_[state.index].weight;
149 state.value -= items_[state.index].value;
150 }
151
152 state.chosen[state.index] = 0;
153 }
154
155 // Branch lazily: try "take" first when it is feasible, then "skip".
156 template <typename Visitor>
157 bool for_each_successor(const State &state, Visitor visit) const
158 {
159 if (state.index >= items_.size())
160 return true;
161
162 if (state.weight + items_[state.index].weight <= capacity_)
163 if (not visit(Move{true}))
164 return false;
165
166 return visit(Move{false});
167 }
168
169private:
171 int capacity_ = 0;
172};
173
174void print_solution(const KnapsackState &state)
175{
176 std::cout << "Chosen items:";
177 for (size_t i = 0; i < state.chosen.size(); ++i)
178 if (state.chosen[i])
179 std::cout << ' ' << i;
180 std::cout << '\n';
181}
182
183} // end namespace
184
185int main()
186{
187 const Array<Knapsack_Item<int, double>> items = {
188 {2, 40.0}, {5, 30.0}, {10, 50.0}, {5, 10.0}
189 };
190 constexpr int capacity = 16;
191
193 Search::ExplorationPolicy policy = Engine::default_policy();
194 policy.strategy = Search::ExplorationPolicy::Strategy::Best_First;
195
196 auto result = Search::branch_and_bound_search(KnapsackBBDomain(items, capacity),
197 KnapsackState(items.size()),
198 policy);
199
200 std::cout << "0/1 Knapsack reference example\n";
201 std::cout << "Capacity: " << capacity << '\n';
202 std::cout << "Strategy: best-first\n";
203 std::cout << "Optimal value: " << result.incumbent.best_value() << '\n';
204 std::cout << "Reference dynamic-programming value: "
205 << Aleph::knapsack_01_value<double, int>(items, capacity) << '\n';
206 std::cout << "Visited states: " << result.stats.visited_states << '\n';
207 std::cout << "Pruned by bound: " << result.stats.pruned_by_bound << '\n';
208 print_solution(result.incumbent.get().state);
209
210 return 0;
211}
Classical knapsack problem variants (0/1, unbounded, bounded).
Umbrella header for the implicit state-space search framework.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:351
Reusable branch-and-bound engine over implicit state spaces.
User-facing facade exported by the umbrella search header.
and
Check uniqueness with explicit hash + equality functors.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
Exploration controls shared across engines.
Strategy strategy
Traversal strategy.
An item for knapsack problems.
Definition Knapsack.H:66
Dynamic array container with automatic resizing.