PBeFS
Parallel Best-First Search
Loading...
Searching...
No Matches
Knapsack.h
Go to the documentation of this file.
1/*--------------------------------------------------------------------------*/
2/*---------------------------- File Knapsack.h -----------------------------*/
3/*--------------------------------------------------------------------------*/
19/*--------------------------------------------------------------------------*/
20/*------------------------------ DEFINITIONS -------------------------------*/
21/*--------------------------------------------------------------------------*/
22
23#ifndef __PBeFS_Knapsack
24 #define __PBeFS_Knapsack
25 /* self-identification: #endif at the end of the file */
26
27/*--------------------------------------------------------------------------*/
28/*-------------------------------- INCLUDES --------------------------------*/
29/*--------------------------------------------------------------------------*/
30
31#include <algorithm>
32
33#include <cstddef>
34
35#include <cstdint>
36
37#include <cmath>
38
39#include <cstring>
40
41#include <limits>
42
43#include <random>
44
45#include <type_traits>
46
47#include <utility>
48
49#include <vector>
50
52
53/*--------------------------------------------------------------------------*/
54/*------------------------------- NAMESPACE --------------------------------*/
55/*--------------------------------------------------------------------------*/
56
58namespace PBeFS_di_unipi_it
59{
60
61/*--------------------------------------------------------------------------*/
62/*-------------------------- CLASS BasicKnapsack ---------------------------*/
63/*--------------------------------------------------------------------------*/
65
76
77template< class V = double >
79
80 using value_type = V;
81
82 struct node_type {
83 std::size_t k = 0;
84 long weight = 0;
85 long profit = 0;
86 std::vector< char > x;
87 };
88
89 static constexpr Sense sense = Sense::maximize;
90
91 std::vector< long > p;
92 std::vector< long > w;
93 long cap = 0;
94 bool explicit_children = false;
95
96 node_type root( void ) const {
97 node_type n;
98 n.x.assign( p.size() , 0 );
99 return( n );
100 }
101
102 // the value of the greedy completion of n
103 long greedy( const node_type & n ) const {
104 long r = cap - n.weight , v = n.profit;
105 for( std::size_t i = n.k ; i < p.size() ; ++i )
106 if( w[ i ] <= r ) {
107 r -= w[ i ];
108 v += p[ i ];
109 }
110 return( v );
111 }
112
115 if( n.weight > cap ) {
116 e.infeasible = true;
117 return( e );
118 }
119 long r = cap - n.weight;
120 double b = double( n.profit );
121 std::size_t j = n.k;
122 for( ; ( j < p.size() ) && ( w[ j ] <= r ) ; ++j ) {
123 r -= w[ j ];
124 b += double( p[ j ] );
125 }
126 if( j < p.size() )
127 b += double( p[ j ] ) * double( r ) / double( w[ j ] );
128 if constexpr( std::is_integral_v< V > )
129 e.bound = V( std::floor( b ) );
130 else
131 e.bound = V( b );
132 e.feasible = V( greedy( n ) );
133 return( e );
134 }
135
136 template< class F >
137 void branch( const node_type & n , F && f ) const {
138 if( n.k == p.size() )
139 return;
140 // the item k left out first and taken last, so that with ties a depth
141 // first search goes on with the item taken, as the greedy order does
142 const V none = BBValueTraits< V >::infinity();
143 const auto bound = [ & ]( node_type & x ) {
144 if( ! explicit_children )
145 return( none );
146 const BasicEvaluation< V > e = evaluate( x );
147 return( e.infeasible ? none : e.bound );
148 };
149 node_type c = n;
150 ++c.k;
151 const bool fits = explicit_children || ( n.weight + w[ n.k ] <= cap );
152 node_type t = c;
153 const V bc = bound( c );
154 f( std::move( c ) , bc );
155 if( fits ) {
156 t.weight += w[ n.k ];
157 t.profit += p[ n.k ];
158 t.x[ n.k ] = 1;
159 const V bt = bound( t );
160 f( std::move( t ) , bt );
161 }
162 }
163
164 std::uint64_t hash( const node_type & n ) const {
165 return( ADS::splitmix64( ( std::uint64_t( n.k ) << 40 ) ^
166 ( std::uint64_t( n.weight ) << 20 ) ^
167 std::uint64_t( n.profit ) ) );
168 }
169
170 V estimate( const node_type & n ) const {
171 return( V( greedy( n ) ) );
172 }
173
174 // the bytes of a node, for MPI
175 void serialize( const node_type & n , std::vector< char > & out ) const {
176 const auto put = [ & ]( const auto & v ) {
177 const auto * b = reinterpret_cast< const char * >( & v );
178 out.insert( out.end() , b , b + sizeof( v ) );
179 };
180 put( n.k );
181 put( n.weight );
182 put( n.profit );
183 out.insert( out.end() , n.x.begin() , n.x.end() );
184 }
185
186 node_type deserialize( const char * & in ) const {
187 node_type n;
188 std::memcpy( & n.k , in , sizeof( n.k ) );
189 in += sizeof( n.k );
190 std::memcpy( & n.weight , in , sizeof( n.weight ) );
191 in += sizeof( n.weight );
192 std::memcpy( & n.profit , in , sizeof( n.profit ) );
193 in += sizeof( n.profit );
194 n.x.assign( in , in + p.size() );
195 in += p.size();
196 return( n );
197 }
198
199 // the optimal value, by the dynamic program on the capacity
200 long optimum( void ) const {
201 std::vector< long > best( std::size_t( cap ) + 1 , 0 );
202 for( std::size_t i = 0 ; i < p.size() ; ++i )
203 for( long c = cap ; c >= w[ i ] ; --c )
204 best[ c ] = std::max( best[ c ] , best[ c - w[ i ] ] + p[ i ] );
205 return( best[ cap ] );
206 }
207
208 // a random instance of the class of Pisinger cls (0 uncorrelated, 1
209 // weakly correlated, 2 strongly correlated), of n items of weight at most
210 // r, the capacity half the total weight
211 static BasicKnapsack random( int cls , std::size_t n , long r ,
212 std::uint64_t seed ) {
213 std::mt19937_64 gen( seed );
214 std::vector< std::pair< long , long > > it( n );
215 long tw = 0;
216 for( auto & [ pi , wi ] : it ) {
217 wi = 1 + long( random_below( gen , std::uint64_t( r ) ) );
218 if( cls == 0 )
219 pi = 1 + long( random_below( gen , std::uint64_t( r ) ) );
220 else
221 if( cls == 1 )
222 pi = std::max( 1L , wi - r / 10 + long( random_below(
223 gen , std::uint64_t( r / 5 + 1 ) ) ) );
224 else
225 pi = wi + r / 10;
226 tw += wi;
227 }
228 std::sort( it.begin() , it.end() , []( const auto & a , const auto & b ) {
229 return( a.first * b.second > b.first * a.second );
230 } );
231 BasicKnapsack kp;
232 for( const auto & [ pi , wi ] : it ) {
233 kp.p.push_back( pi );
234 kp.w.push_back( wi );
235 }
236 kp.cap = tw / 2;
237 return( kp );
238 }
239
240 // true if n is a node of value v: its greedy completion fits and gives v
241 bool check( const node_type & n , V v ) const {
242 long wt = 0 , pt = 0;
243 for( std::size_t i = 0 ; i < n.k ; ++i )
244 if( n.x[ i ] ) {
245 wt += w[ i ];
246 pt += p[ i ];
247 }
248 return( ( wt == n.weight ) && ( pt == n.profit ) && ( wt <= cap ) &&
249 ( V( greedy( n ) ) == v ) );
250 }
251
252 }; // end( struct( BasicKnapsack ) )
253
254/*--------------------------------------------------------------------------*/
256
258
259/*--------------------------------------------------------------------------*/
260
261} // end( namespace PBeFS_di_unipi_it )
262
263/*--------------------------------------------------------------------------*/
264
265#endif /* __PBeFS_Knapsack */
266
267/*--------------------------------------------------------------------------*/
268/*-------------------------- End File Knapsack.h ---------------------------*/
269/*--------------------------------------------------------------------------*/
Header file for the best-first search with an incumbent, i.e., for Branch-and-Bound (B&B): the concep...
namespace for the Parallel Best-First Search library
Definition AStar.h:83
std::uint64_t random_below(Gen &gen, std::uint64_t n)
an integer in [ 0 , n ) from the next word of a 64-bit generator, n > 0
Definition SearchUtils.h:165
BasicKnapsack<> Knapsack
the 0-1 knapsack with values of type double
Definition Knapsack.h:257
Sense
the sense of the optimization
Definition BranchAndBound.h:131
@ maximize
the largest value is sought
Definition BranchAndBound.h:133
static constexpr V infinity(void) noexcept
the infinite value
Definition BranchAndBound.h:212
the outcome of the evaluation of a node, with values of type V
Definition BranchAndBound.h:155
V bound
a bound on the values of the node
Definition BranchAndBound.h:156
std::optional< V > feasible
a feasible value, n being its solution, if there is one
Definition BranchAndBound.h:158
bool infeasible
true if the node has no solution
Definition BranchAndBound.h:157
long weight
the weight of those taken
Definition Knapsack.h:84
std::vector< char > x
the items taken
Definition Knapsack.h:86
long profit
their profit
Definition Knapsack.h:85
std::size_t k
the items fixed
Definition Knapsack.h:83
a 0-1 knapsack, its items sorted by decreasing ratio of profit to weight
Definition Knapsack.h:78
std::uint64_t hash(const node_type &n) const
Definition Knapsack.h:164
V value_type
the type of the values
Definition Knapsack.h:80
static constexpr Sense sense
Definition Knapsack.h:89
static BasicKnapsack random(int cls, std::size_t n, long r, std::uint64_t seed)
Definition Knapsack.h:211
void serialize(const node_type &n, std::vector< char > &out) const
Definition Knapsack.h:175
BasicEvaluation< V > evaluate(node_type &n) const
Definition Knapsack.h:113
long cap
the capacity
Definition Knapsack.h:93
long optimum(void) const
Definition Knapsack.h:200
node_type deserialize(const char *&in) const
Definition Knapsack.h:186
void branch(const node_type &n, F &&f) const
Definition Knapsack.h:137
std::vector< long > p
the profits
Definition Knapsack.h:91
long greedy(const node_type &n) const
Definition Knapsack.h:103
bool explicit_children
own bounds, infeasible children
Definition Knapsack.h:94
node_type root(void) const
Definition Knapsack.h:96
std::vector< long > w
the weights
Definition Knapsack.h:92
bool check(const node_type &n, V v) const
Definition Knapsack.h:241
V estimate(const node_type &n) const
Definition Knapsack.h:170