Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
branch_and_bound_artificial_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
40# include <iostream>
41# include <string>
42
43# include <State_Search.H>
44
45using namespace Aleph;
46
47namespace
48{
49
50struct ArtificialState
51{
52 size_t depth = 0;
53 int code = 1;
54 int value = 0;
55};
56
57struct ArtificialMove
58{
59 int target_code = 1;
60 int delta = 0;
61 char label = 'L';
62};
63
64struct ArtificialMaxDomain
65{
66 using State = ArtificialState;
67 using Move = ArtificialMove;
68 using Objective = int;
69
70 bool is_complete(const State &state) const
71 {
72 return state.depth == 2;
73 }
74
75 Objective objective_value(const State &state) const
76 {
77 return state.value;
78 }
79
80 Objective bound(const State &state) const
81 {
82 switch (state.code)
83 {
84 case 1: return 9;
85 case 2: return 9;
86 case 3: return 5;
87 default: return state.value;
88 }
89 }
90
91 void apply(State &state, const Move &move) const
92 {
93 state.code = move.target_code;
94 state.value += move.delta;
95 ++state.depth;
96 }
97
98 void undo(State &state, const Move &move) const
99 {
100 --state.depth;
101 state.value -= move.delta;
102 state.code /= 2;
103 }
104
105 template <typename Visitor>
106 bool for_each_successor(const State &state, Visitor visit) const
107 {
108 if (state.depth >= 2)
109 return true;
110
111 switch (state.code)
112 {
113 case 1:
114 if (not visit(Move{2, 0, 'L'}))
115 return false;
116 return visit(Move{3, 0, 'R'});
117
118 case 2:
119 if (not visit(Move{4, 7, 'L'}))
120 return false;
121 return visit(Move{5, 9, 'R'});
122
123 case 3:
124 if (not visit(Move{6, 5, 'L'}))
125 return false;
126 return visit(Move{7, 4, 'R'});
127
128 default:
129 return true;
130 }
131 }
132};
133
134struct ArtificialMinDomain
135{
136 using State = ArtificialState;
137 using Move = ArtificialMove;
138 using Objective = int;
139
140 bool is_complete(const State &state) const
141 {
142 return state.depth == 2;
143 }
144
145 Objective objective_value(const State &state) const
146 {
147 return state.value;
148 }
149
150 Objective bound(const State &state) const
151 {
152 switch (state.code)
153 {
154 case 1: return 6;
155 case 2: return 6;
156 case 3: return 7;
157 default: return state.value;
158 }
159 }
160
161 void apply(State &state, const Move &move) const
162 {
163 state.code = move.target_code;
164 state.value += move.delta;
165 ++state.depth;
166 }
167
168 void undo(State &state, const Move &move) const
169 {
170 --state.depth;
171 state.value -= move.delta;
172 state.code /= 2;
173 }
174
175 template <typename Visitor>
176 bool for_each_successor(const State &state, Visitor visit) const
177 {
178 if (state.depth >= 2)
179 return true;
180
181 switch (state.code)
182 {
183 case 1:
184 if (not visit(Move{2, 0, 'L'}))
185 return false;
186 return visit(Move{3, 0, 'R'});
187
188 case 2:
189 if (not visit(Move{4, 8, 'L'}))
190 return false;
191 return visit(Move{5, 6, 'R'});
192
193 case 3:
194 if (not visit(Move{6, 7, 'L'}))
195 return false;
196 return visit(Move{7, 9, 'R'});
197
198 default:
199 return true;
200 }
201 }
202};
203
204struct ArtificialMaxBadOrderDomain
205{
206 using State = ArtificialState;
207 using Move = ArtificialMove;
208 using Objective = int;
209
210 bool is_complete(const State &state) const
211 {
212 return state.depth == 2;
213 }
214
215 Objective objective_value(const State &state) const
216 {
217 return state.value;
218 }
219
220 Objective bound(const State &state) const
221 {
222 switch (state.code)
223 {
224 case 1: return 9;
225 case 2: return 9;
226 case 3: return 5;
227 default: return state.value;
228 }
229 }
230
231 void apply(State &state, const Move &move) const
232 {
233 state.code = move.target_code;
234 state.value += move.delta;
235 ++state.depth;
236 }
237
238 void undo(State &state, const Move &move) const
239 {
240 --state.depth;
241 state.value -= move.delta;
242 state.code /= 2;
243 }
244
245 template <typename Visitor>
246 bool for_each_successor(const State &state, Visitor visit) const
247 {
248 if (state.depth >= 2)
249 return true;
250
251 switch (state.code)
252 {
253 case 1:
254 if (not visit(Move{3, 0, 'R'}))
255 return false;
256 return visit(Move{2, 0, 'L'});
257
258 case 2:
259 if (not visit(Move{4, 7, 'L'}))
260 return false;
261 return visit(Move{5, 9, 'R'});
262
263 case 3:
264 if (not visit(Move{6, 5, 'L'}))
265 return false;
266 return visit(Move{7, 4, 'R'});
267
268 default:
269 return true;
270 }
271 }
272};
273
274std::string signature(const SearchPath<ArtificialMove> &path)
275{
276 std::string out;
277 for (const auto &move : path)
278 out.push_back(move.label);
279 return out;
280}
281
282template <typename Result>
283void print_summary(const char *title, const Result &result)
284{
285 std::cout << title << '\n';
286 std::cout << " objective: " << result.incumbent.best_value() << '\n';
287 std::cout << " path: " << signature(result.incumbent.get().path) << '\n';
288 std::cout << " visited: " << result.stats.visited_states << '\n';
289 std::cout << " pruned by bound: " << result.stats.pruned_by_bound << '\n';
290 std::cout << " ordered batches: " << result.stats.move_ordering.ordered_batches << '\n';
291}
292
293} // end namespace
294
295int main()
296{
297 auto max_plain = branch_and_bound_search(ArtificialMaxBadOrderDomain{}, ArtificialState{});
298 print_summary("Maximization (depth-first, domain order)", max_plain);
299
302 ordered_policy.move_ordering = MoveOrderingMode::Estimated_Bound;
303 auto max_ordered = branch_and_bound_search(ArtificialMaxBadOrderDomain{},
304 ArtificialState{},
306 print_summary("Maximization (depth-first, bound-ordered)", max_ordered);
307
310 max_best_policy.strategy = ExplorationPolicy::Strategy::Best_First;
311 auto max_best = branch_and_bound_search(ArtificialMaxBadOrderDomain{},
312 ArtificialState{},
314 print_summary("Maximization (best-first)", max_best);
315
318 min_policy.strategy = ExplorationPolicy::Strategy::Best_First;
319
321 ArtificialMinDomain{}, min_policy, {}, Minimize_Objective<int>{});
322 auto min_result = min_engine.search(ArtificialState{});
323 print_summary("Minimization (best-first)", min_result);
324
325 return 0;
326}
Umbrella header for the implicit state-space search framework.
Reusable branch-and-bound engine over implicit state spaces.
static ExplorationPolicy default_policy() noexcept
Return the default branch-and-bound exploration policy.
Result search(State initial_state)
Execute branch and bound and keep only the incumbent.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
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.
std::string code(Node *root)
Compute a string with the Lukasiewicz`s word of a tree.
auto branch_and_bound_search(Domain domain, typename Domain::State initial_state, ExplorationPolicy policy=Branch_And_Bound< Domain, ObjectivePolicy >::default_policy(), SearchLimits limits={}, ObjectivePolicy objective={})
Convenience wrapper for one-shot branch and bound.
Exploration controls shared across engines.
Objective policy for minimization problems.