Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
branch_and_bound_assignment_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
42# include <State_Search.H>
43# include <tpl_array.H>
44
45namespace
46{
47
48namespace Search = Aleph::Search;
49using Aleph::Array;
50
51struct AssignmentState
52{
53 size_t row = 0;
54 int total_cost = 0;
55 Array<unsigned char> used_columns;
56 Array<int> assigned_column;
57
58 explicit AssignmentState(const size_t n = 0)
59 : row(0), total_cost(0), used_columns(n, 0), assigned_column(n, -1)
60 {
61 // empty
62 }
63};
64
65class AssignmentBBDomain
66{
67public:
68 struct Move
69 {
70 size_t col = 0;
71 };
72
73 using State = AssignmentState;
74 using Objective = int;
75
76 explicit AssignmentBBDomain(const Array<Array<int>> &costs)
77 : costs_(costs)
78 {
79 // empty
80 }
81
82 bool is_complete(const State &state) const
83 {
84 return state.row == costs_.size();
85 }
86
87 Objective objective_value(const State &state) const
88 {
89 return state.total_cost;
90 }
91
92 Objective bound(const State &state) const
93 {
94 Objective optimistic = state.total_cost;
95
96 for (size_t row = state.row; row < costs_.size(); ++row)
97 {
98 int best = -1;
99 for (size_t col = 0; col < costs_[row].size(); ++col)
100 if (not state.used_columns[col] and (best < 0 or costs_[row][col] < best))
101 best = costs_[row][col];
102
103 optimistic += best;
104 }
105
106 return optimistic;
107 }
108
109 void apply(State &state, const Move &move) const
110 {
111 state.total_cost += costs_[state.row][move.col];
112 state.used_columns[move.col] = 1;
113 state.assigned_column[state.row] = static_cast<int>(move.col);
114 ++state.row;
115 }
116
117 void undo(State &state, const Move &move) const
118 {
119 --state.row;
120 state.total_cost -= costs_[state.row][move.col];
121 state.used_columns[move.col] = 0;
122 state.assigned_column[state.row] = -1;
123 }
124
125 template <typename Visitor>
126 bool for_each_successor(const State &state, Visitor visit) const
127 {
128 if (state.row >= costs_.size())
129 return true;
130
131 for (size_t col = 0; col < costs_[state.row].size(); ++col)
132 if (not state.used_columns[col] and not visit(Move{col}))
133 return false;
134
135 return true;
136 }
137
138private:
139 Array<Array<int>> costs_;
140};
141
142void print_assignment(const AssignmentState &state)
143{
144 std::cout << "Assignment:";
145 for (size_t row = 0; row < state.assigned_column.size(); ++row)
146 std::cout << " row" << row << "->col" << state.assigned_column[row];
147 std::cout << '\n';
148}
149
150} // end namespace
151
152int main()
153{
154 const Array<Array<int>> costs = {
155 Array<int>{9, 2, 7, 8},
156 Array<int>{6, 4, 3, 7},
157 Array<int>{5, 8, 1, 8},
158 Array<int>{7, 6, 9, 4}
159 };
160
162
163 Search::ExplorationPolicy policy = Engine::default_policy();
164 policy.strategy = Search::ExplorationPolicy::Strategy::Best_First;
165
166 Engine engine(AssignmentBBDomain(costs), policy, {}, Search::Minimize_Objective<int>{});
167 auto result = engine.search(AssignmentState(costs.size()));
168
169 std::cout << "Optimal assignment cost: " << result.incumbent.best_value() << '\n';
170 std::cout << "Visited states: " << result.stats.visited_states << '\n';
171 std::cout << "Pruned by bound: " << result.stats.pruned_by_bound << '\n';
172 print_assignment(result.incumbent.get().state);
173
174 return 0;
175}
Umbrella header for the implicit state-space search framework.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
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.
Objective policy for minimization problems.
static mt19937 engine
Dynamic array container with automatic resizing.