annotate DEPENDENCIES/generic/include/boost/graph/parallel/distribution.hpp @ 118:770eb830ec19 emscripten

Typo fix
author Chris Cannam
date Wed, 18 May 2016 16:14:08 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 // Copyright 2004 The Trustees of Indiana University.
Chris@16 2
Chris@16 3 // Use, modification and distribution is subject to the Boost Software
Chris@16 4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 5 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 6
Chris@16 7 // Authors: Douglas Gregor
Chris@16 8 // Peter Gottschling
Chris@16 9 // Andrew Lumsdaine
Chris@16 10 #ifndef BOOST_PARALLEL_DISTRIBUTION_HPP
Chris@16 11 #define BOOST_PARALLEL_DISTRIBUTION_HPP
Chris@16 12
Chris@16 13 #ifndef BOOST_GRAPH_USE_MPI
Chris@16 14 #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
Chris@16 15 #endif
Chris@16 16
Chris@16 17 #include <cstddef>
Chris@16 18 #include <vector>
Chris@16 19 #include <algorithm>
Chris@16 20 #include <numeric>
Chris@16 21 #include <boost/assert.hpp>
Chris@16 22 #include <boost/iterator/counting_iterator.hpp>
Chris@16 23 #include <boost/random/uniform_int.hpp>
Chris@16 24 #include <boost/shared_ptr.hpp>
Chris@16 25 #include <typeinfo>
Chris@16 26
Chris@16 27 namespace boost { namespace parallel {
Chris@16 28
Chris@16 29 template<typename ProcessGroup, typename SizeType = std::size_t>
Chris@16 30 class variant_distribution
Chris@16 31 {
Chris@16 32 public:
Chris@16 33 typedef typename ProcessGroup::process_id_type process_id_type;
Chris@16 34 typedef typename ProcessGroup::process_size_type process_size_type;
Chris@16 35 typedef SizeType size_type;
Chris@16 36
Chris@16 37 private:
Chris@16 38 struct basic_distribution
Chris@16 39 {
Chris@16 40 virtual ~basic_distribution() {}
Chris@16 41 virtual size_type block_size(process_id_type, size_type) const = 0;
Chris@16 42 virtual process_id_type in_process(size_type) const = 0;
Chris@16 43 virtual size_type local(size_type) const = 0;
Chris@16 44 virtual size_type global(size_type) const = 0;
Chris@16 45 virtual size_type global(process_id_type, size_type) const = 0;
Chris@16 46 virtual void* address() = 0;
Chris@16 47 virtual const void* address() const = 0;
Chris@16 48 virtual const std::type_info& type() const = 0;
Chris@16 49 };
Chris@16 50
Chris@16 51 template<typename Distribution>
Chris@16 52 struct poly_distribution : public basic_distribution
Chris@16 53 {
Chris@16 54 explicit poly_distribution(const Distribution& distribution)
Chris@16 55 : distribution_(distribution) { }
Chris@16 56
Chris@16 57 virtual size_type block_size(process_id_type id, size_type n) const
Chris@16 58 { return distribution_.block_size(id, n); }
Chris@16 59
Chris@16 60 virtual process_id_type in_process(size_type i) const
Chris@16 61 { return distribution_(i); }
Chris@16 62
Chris@16 63 virtual size_type local(size_type i) const
Chris@16 64 { return distribution_.local(i); }
Chris@16 65
Chris@16 66 virtual size_type global(size_type n) const
Chris@16 67 { return distribution_.global(n); }
Chris@16 68
Chris@16 69 virtual size_type global(process_id_type id, size_type n) const
Chris@16 70 { return distribution_.global(id, n); }
Chris@16 71
Chris@16 72 virtual void* address() { return &distribution_; }
Chris@16 73 virtual const void* address() const { return &distribution_; }
Chris@16 74 virtual const std::type_info& type() const { return typeid(Distribution); }
Chris@16 75
Chris@16 76 private:
Chris@16 77 Distribution distribution_;
Chris@16 78 };
Chris@16 79
Chris@16 80 public:
Chris@16 81 variant_distribution() { }
Chris@16 82
Chris@16 83 template<typename Distribution>
Chris@16 84 variant_distribution(const Distribution& distribution)
Chris@16 85 : distribution_(new poly_distribution<Distribution>(distribution)) { }
Chris@16 86
Chris@16 87 size_type block_size(process_id_type id, size_type n) const
Chris@16 88 { return distribution_->block_size(id, n); }
Chris@16 89
Chris@16 90 process_id_type operator()(size_type i) const
Chris@16 91 { return distribution_->in_process(i); }
Chris@16 92
Chris@16 93 size_type local(size_type i) const
Chris@16 94 { return distribution_->local(i); }
Chris@16 95
Chris@16 96 size_type global(size_type n) const
Chris@16 97 { return distribution_->global(n); }
Chris@16 98
Chris@16 99 size_type global(process_id_type id, size_type n) const
Chris@16 100 { return distribution_->global(id, n); }
Chris@16 101
Chris@16 102 operator bool() const { return distribution_; }
Chris@16 103
Chris@16 104 void clear() { distribution_.reset(); }
Chris@16 105
Chris@16 106 template<typename T>
Chris@16 107 T* as()
Chris@16 108 {
Chris@16 109 if (distribution_->type() == typeid(T))
Chris@16 110 return static_cast<T*>(distribution_->address());
Chris@16 111 else
Chris@16 112 return 0;
Chris@16 113 }
Chris@16 114
Chris@16 115 template<typename T>
Chris@16 116 const T* as() const
Chris@16 117 {
Chris@16 118 if (distribution_->type() == typeid(T))
Chris@16 119 return static_cast<T*>(distribution_->address());
Chris@16 120 else
Chris@16 121 return 0;
Chris@16 122 }
Chris@16 123
Chris@16 124 private:
Chris@16 125 shared_ptr<basic_distribution> distribution_;
Chris@16 126 };
Chris@16 127
Chris@16 128 struct block
Chris@16 129 {
Chris@16 130 template<typename LinearProcessGroup>
Chris@16 131 explicit block(const LinearProcessGroup& pg, std::size_t n)
Chris@16 132 : id(process_id(pg)), p(num_processes(pg)), n(n) { }
Chris@16 133
Chris@16 134 // If there are n elements in the distributed data structure, returns the number of elements stored locally.
Chris@16 135 template<typename SizeType>
Chris@16 136 SizeType block_size(SizeType n) const
Chris@16 137 { return (n / p) + ((std::size_t)(n % p) > id? 1 : 0); }
Chris@16 138
Chris@16 139 // If there are n elements in the distributed data structure, returns the number of elements stored on processor ID
Chris@16 140 template<typename SizeType, typename ProcessID>
Chris@16 141 SizeType block_size(ProcessID id, SizeType n) const
Chris@16 142 { return (n / p) + ((ProcessID)(n % p) > id? 1 : 0); }
Chris@16 143
Chris@16 144 // Returns the processor on which element with global index i is stored
Chris@16 145 template<typename SizeType>
Chris@16 146 SizeType operator()(SizeType i) const
Chris@16 147 {
Chris@16 148 SizeType cutoff_processor = n % p;
Chris@16 149 SizeType cutoff = cutoff_processor * (n / p + 1);
Chris@16 150
Chris@16 151 if (i < cutoff) return i / (n / p + 1);
Chris@16 152 else return cutoff_processor + (i - cutoff) / (n / p);
Chris@16 153 }
Chris@16 154
Chris@16 155 // Find the starting index for processor with the given id
Chris@16 156 template<typename ID>
Chris@16 157 std::size_t start(ID id) const
Chris@16 158 {
Chris@16 159 std::size_t estimate = id * (n / p + 1);
Chris@16 160 ID cutoff_processor = n % p;
Chris@16 161 if (id < cutoff_processor) return estimate;
Chris@16 162 else return estimate - (id - cutoff_processor);
Chris@16 163 }
Chris@16 164
Chris@16 165 // Find the local index for the ith global element
Chris@16 166 template<typename SizeType>
Chris@16 167 SizeType local(SizeType i) const
Chris@16 168 {
Chris@16 169 SizeType owner = (*this)(i);
Chris@16 170 return i - start(owner);
Chris@16 171 }
Chris@16 172
Chris@16 173 // Returns the global index of local element i
Chris@16 174 template<typename SizeType>
Chris@16 175 SizeType global(SizeType i) const
Chris@16 176 { return global(id, i); }
Chris@16 177
Chris@16 178 // Returns the global index of the ith local element on processor id
Chris@16 179 template<typename ProcessID, typename SizeType>
Chris@16 180 SizeType global(ProcessID id, SizeType i) const
Chris@16 181 { return i + start(id); }
Chris@16 182
Chris@16 183 private:
Chris@16 184 std::size_t id; //< The ID number of this processor
Chris@16 185 std::size_t p; //< The number of processors
Chris@16 186 std::size_t n; //< The size of the problem space
Chris@16 187 };
Chris@16 188
Chris@16 189 // Block distribution with arbitrary block sizes
Chris@16 190 struct uneven_block
Chris@16 191 {
Chris@16 192 typedef std::vector<std::size_t> size_vector;
Chris@16 193
Chris@16 194 template<typename LinearProcessGroup>
Chris@16 195 explicit uneven_block(const LinearProcessGroup& pg, const std::vector<std::size_t>& local_sizes)
Chris@16 196 : id(process_id(pg)), p(num_processes(pg)), local_sizes(local_sizes)
Chris@16 197 {
Chris@16 198 BOOST_ASSERT(local_sizes.size() == p);
Chris@16 199 local_starts.resize(p + 1);
Chris@16 200 local_starts[0] = 0;
Chris@16 201 std::partial_sum(local_sizes.begin(), local_sizes.end(), &local_starts[1]);
Chris@16 202 n = local_starts[p];
Chris@16 203 }
Chris@16 204
Chris@16 205 // To do maybe: enter local size in each process and gather in constructor (much handier)
Chris@16 206 // template<typename LinearProcessGroup>
Chris@16 207 // explicit uneven_block(const LinearProcessGroup& pg, std::size_t my_local_size)
Chris@16 208
Chris@16 209 // If there are n elements in the distributed data structure, returns the number of elements stored locally.
Chris@16 210 template<typename SizeType>
Chris@16 211 SizeType block_size(SizeType) const
Chris@16 212 { return local_sizes[id]; }
Chris@16 213
Chris@16 214 // If there are n elements in the distributed data structure, returns the number of elements stored on processor ID
Chris@16 215 template<typename SizeType, typename ProcessID>
Chris@16 216 SizeType block_size(ProcessID id, SizeType) const
Chris@16 217 { return local_sizes[id]; }
Chris@16 218
Chris@16 219 // Returns the processor on which element with global index i is stored
Chris@16 220 template<typename SizeType>
Chris@16 221 SizeType operator()(SizeType i) const
Chris@16 222 {
Chris@16 223 BOOST_ASSERT (i >= (SizeType) 0 && i < (SizeType) n); // check for valid range
Chris@16 224 size_vector::const_iterator lb = std::lower_bound(local_starts.begin(), local_starts.end(), (std::size_t) i);
Chris@16 225 return ((SizeType)(*lb) == i ? lb : --lb) - local_starts.begin();
Chris@16 226 }
Chris@16 227
Chris@16 228 // Find the starting index for processor with the given id
Chris@16 229 template<typename ID>
Chris@16 230 std::size_t start(ID id) const
Chris@16 231 {
Chris@16 232 return local_starts[id];
Chris@16 233 }
Chris@16 234
Chris@16 235 // Find the local index for the ith global element
Chris@16 236 template<typename SizeType>
Chris@16 237 SizeType local(SizeType i) const
Chris@16 238 {
Chris@16 239 SizeType owner = (*this)(i);
Chris@16 240 return i - start(owner);
Chris@16 241 }
Chris@16 242
Chris@16 243 // Returns the global index of local element i
Chris@16 244 template<typename SizeType>
Chris@16 245 SizeType global(SizeType i) const
Chris@16 246 { return global(id, i); }
Chris@16 247
Chris@16 248 // Returns the global index of the ith local element on processor id
Chris@16 249 template<typename ProcessID, typename SizeType>
Chris@16 250 SizeType global(ProcessID id, SizeType i) const
Chris@16 251 { return i + start(id); }
Chris@16 252
Chris@16 253 private:
Chris@16 254 std::size_t id; //< The ID number of this processor
Chris@16 255 std::size_t p; //< The number of processors
Chris@16 256 std::size_t n; //< The size of the problem space
Chris@16 257 std::vector<std::size_t> local_sizes; //< The sizes of all blocks
Chris@16 258 std::vector<std::size_t> local_starts; //< Lowest global index of each block
Chris@16 259 };
Chris@16 260
Chris@16 261
Chris@16 262 struct oned_block_cyclic
Chris@16 263 {
Chris@16 264 template<typename LinearProcessGroup>
Chris@16 265 explicit oned_block_cyclic(const LinearProcessGroup& pg, std::size_t size)
Chris@16 266 : id(process_id(pg)), p(num_processes(pg)), size(size) { }
Chris@16 267
Chris@16 268 template<typename SizeType>
Chris@16 269 SizeType block_size(SizeType n) const
Chris@16 270 {
Chris@16 271 return block_size(id, n);
Chris@16 272 }
Chris@16 273
Chris@16 274 template<typename SizeType, typename ProcessID>
Chris@16 275 SizeType block_size(ProcessID id, SizeType n) const
Chris@16 276 {
Chris@16 277 SizeType all_blocks = n / size;
Chris@16 278 SizeType extra_elements = n % size;
Chris@16 279 SizeType everyone_gets = all_blocks / p;
Chris@16 280 SizeType extra_blocks = all_blocks % p;
Chris@16 281 SizeType my_blocks = everyone_gets + (p < extra_blocks? 1 : 0);
Chris@16 282 SizeType my_elements = my_blocks * size
Chris@16 283 + (p == extra_blocks? extra_elements : 0);
Chris@16 284 return my_elements;
Chris@16 285 }
Chris@16 286
Chris@16 287 template<typename SizeType>
Chris@16 288 SizeType operator()(SizeType i) const
Chris@16 289 {
Chris@16 290 return (i / size) % p;
Chris@16 291 }
Chris@16 292
Chris@16 293 template<typename SizeType>
Chris@16 294 SizeType local(SizeType i) const
Chris@16 295 {
Chris@16 296 return ((i / size) / p) * size + i % size;
Chris@16 297 }
Chris@16 298
Chris@16 299 template<typename SizeType>
Chris@16 300 SizeType global(SizeType i) const
Chris@16 301 { return global(id, i); }
Chris@16 302
Chris@16 303 template<typename ProcessID, typename SizeType>
Chris@16 304 SizeType global(ProcessID id, SizeType i) const
Chris@16 305 {
Chris@16 306 return ((i / size) * p + id) * size + i % size;
Chris@16 307 }
Chris@16 308
Chris@16 309 private:
Chris@16 310 std::size_t id; //< The ID number of this processor
Chris@16 311 std::size_t p; //< The number of processors
Chris@16 312 std::size_t size; //< Block size
Chris@16 313 };
Chris@16 314
Chris@16 315 struct twod_block_cyclic
Chris@16 316 {
Chris@16 317 template<typename LinearProcessGroup>
Chris@16 318 explicit twod_block_cyclic(const LinearProcessGroup& pg,
Chris@16 319 std::size_t block_rows, std::size_t block_columns,
Chris@16 320 std::size_t data_columns_per_row)
Chris@16 321 : id(process_id(pg)), p(num_processes(pg)),
Chris@16 322 block_rows(block_rows), block_columns(block_columns),
Chris@16 323 data_columns_per_row(data_columns_per_row)
Chris@16 324 { }
Chris@16 325
Chris@16 326 template<typename SizeType>
Chris@16 327 SizeType block_size(SizeType n) const
Chris@16 328 {
Chris@16 329 return block_size(id, n);
Chris@16 330 }
Chris@16 331
Chris@16 332 template<typename SizeType, typename ProcessID>
Chris@16 333 SizeType block_size(ProcessID id, SizeType n) const
Chris@16 334 {
Chris@16 335 // TBD: This is really lame :)
Chris@16 336 int result = -1;
Chris@16 337 while (n > 0) {
Chris@16 338 --n;
Chris@16 339 if ((*this)(n) == id && (int)local(n) > result) result = local(n);
Chris@16 340 }
Chris@16 341 ++result;
Chris@16 342
Chris@16 343 // std::cerr << "Block size of id " << id << " is " << result << std::endl;
Chris@16 344 return result;
Chris@16 345 }
Chris@16 346
Chris@16 347 template<typename SizeType>
Chris@16 348 SizeType operator()(SizeType i) const
Chris@16 349 {
Chris@16 350 SizeType result = get_block_num(i) % p;
Chris@16 351 // std::cerr << "Item " << i << " goes on processor " << result << std::endl;
Chris@16 352 return result;
Chris@16 353 }
Chris@16 354
Chris@16 355 template<typename SizeType>
Chris@16 356 SizeType local(SizeType i) const
Chris@16 357 {
Chris@16 358 // Compute the start of the block
Chris@16 359 std::size_t block_num = get_block_num(i);
Chris@16 360 // std::cerr << "Item " << i << " is in block #" << block_num << std::endl;
Chris@16 361
Chris@16 362 std::size_t local_block_num = block_num / p;
Chris@16 363 std::size_t block_start = local_block_num * block_rows * block_columns;
Chris@16 364
Chris@16 365 // Compute the offset into the block
Chris@16 366 std::size_t data_row = i / data_columns_per_row;
Chris@16 367 std::size_t data_col = i % data_columns_per_row;
Chris@16 368 std::size_t block_offset = (data_row % block_rows) * block_columns
Chris@16 369 + (data_col % block_columns);
Chris@16 370
Chris@16 371 // std::cerr << "Item " << i << " maps to local index " << block_start+block_offset << std::endl;
Chris@16 372 return block_start + block_offset;
Chris@16 373 }
Chris@16 374
Chris@16 375 template<typename SizeType>
Chris@16 376 SizeType global(SizeType i) const
Chris@16 377 {
Chris@16 378 // Compute the (global) block in which this element resides
Chris@16 379 SizeType local_block_num = i / (block_rows * block_columns);
Chris@16 380 SizeType block_offset = i % (block_rows * block_columns);
Chris@16 381 SizeType block_num = local_block_num * p + id;
Chris@16 382
Chris@16 383 // Compute the position of the start of the block (globally)
Chris@16 384 SizeType block_start = block_num * block_rows * block_columns;
Chris@16 385
Chris@16 386 std::cerr << "Block " << block_num << " starts at index " << block_start
Chris@16 387 << std::endl;
Chris@16 388
Chris@16 389 // Compute the row and column of this block
Chris@16 390 SizeType block_row = block_num / (data_columns_per_row / block_columns);
Chris@16 391 SizeType block_col = block_num % (data_columns_per_row / block_columns);
Chris@16 392
Chris@16 393 SizeType row_in_block = block_offset / block_columns;
Chris@16 394 SizeType col_in_block = block_offset % block_columns;
Chris@16 395
Chris@16 396 std::cerr << "Local index " << i << " is in block at row " << block_row
Chris@16 397 << ", column " << block_col << ", in-block row " << row_in_block
Chris@16 398 << ", in-block col " << col_in_block << std::endl;
Chris@16 399
Chris@16 400 SizeType result = block_row * block_rows + block_col * block_columns
Chris@16 401 + row_in_block * block_rows + col_in_block;
Chris@16 402
Chris@16 403
Chris@16 404 std::cerr << "global(" << i << "@" << id << ") = " << result
Chris@16 405 << " =? " << local(result) << std::endl;
Chris@16 406 BOOST_ASSERT(i == local(result));
Chris@16 407 return result;
Chris@16 408 }
Chris@16 409
Chris@16 410 private:
Chris@16 411 template<typename SizeType>
Chris@16 412 std::size_t get_block_num(SizeType i) const
Chris@16 413 {
Chris@16 414 std::size_t data_row = i / data_columns_per_row;
Chris@16 415 std::size_t data_col = i % data_columns_per_row;
Chris@16 416 std::size_t block_row = data_row / block_rows;
Chris@16 417 std::size_t block_col = data_col / block_columns;
Chris@16 418 std::size_t blocks_in_row = data_columns_per_row / block_columns;
Chris@16 419 std::size_t block_num = block_col * blocks_in_row + block_row;
Chris@16 420 return block_num;
Chris@16 421 }
Chris@16 422
Chris@16 423 std::size_t id; //< The ID number of this processor
Chris@16 424 std::size_t p; //< The number of processors
Chris@16 425 std::size_t block_rows; //< The # of rows in each block
Chris@16 426 std::size_t block_columns; //< The # of columns in each block
Chris@16 427 std::size_t data_columns_per_row; //< The # of columns per row of data
Chris@16 428 };
Chris@16 429
Chris@16 430 class twod_random
Chris@16 431 {
Chris@16 432 template<typename RandomNumberGen>
Chris@16 433 struct random_int
Chris@16 434 {
Chris@16 435 explicit random_int(RandomNumberGen& gen) : gen(gen) { }
Chris@16 436
Chris@16 437 template<typename T>
Chris@16 438 T operator()(T n) const
Chris@16 439 {
Chris@16 440 uniform_int<T> distrib(0, n-1);
Chris@16 441 return distrib(gen);
Chris@16 442 }
Chris@16 443
Chris@16 444 private:
Chris@16 445 RandomNumberGen& gen;
Chris@16 446 };
Chris@16 447
Chris@16 448 public:
Chris@16 449 template<typename LinearProcessGroup, typename RandomNumberGen>
Chris@16 450 explicit twod_random(const LinearProcessGroup& pg,
Chris@16 451 std::size_t block_rows, std::size_t block_columns,
Chris@16 452 std::size_t data_columns_per_row,
Chris@16 453 std::size_t n,
Chris@16 454 RandomNumberGen& gen)
Chris@16 455 : id(process_id(pg)), p(num_processes(pg)),
Chris@16 456 block_rows(block_rows), block_columns(block_columns),
Chris@16 457 data_columns_per_row(data_columns_per_row),
Chris@16 458 global_to_local(n / (block_rows * block_columns))
Chris@16 459 {
Chris@16 460 std::copy(make_counting_iterator(std::size_t(0)),
Chris@16 461 make_counting_iterator(global_to_local.size()),
Chris@16 462 global_to_local.begin());
Chris@16 463
Chris@16 464 random_int<RandomNumberGen> rand(gen);
Chris@16 465 std::random_shuffle(global_to_local.begin(), global_to_local.end(), rand);
Chris@16 466 }
Chris@16 467
Chris@16 468 template<typename SizeType>
Chris@16 469 SizeType block_size(SizeType n) const
Chris@16 470 {
Chris@16 471 return block_size(id, n);
Chris@16 472 }
Chris@16 473
Chris@16 474 template<typename SizeType, typename ProcessID>
Chris@16 475 SizeType block_size(ProcessID id, SizeType n) const
Chris@16 476 {
Chris@16 477 // TBD: This is really lame :)
Chris@16 478 int result = -1;
Chris@16 479 while (n > 0) {
Chris@16 480 --n;
Chris@16 481 if ((*this)(n) == id && (int)local(n) > result) result = local(n);
Chris@16 482 }
Chris@16 483 ++result;
Chris@16 484
Chris@16 485 // std::cerr << "Block size of id " << id << " is " << result << std::endl;
Chris@16 486 return result;
Chris@16 487 }
Chris@16 488
Chris@16 489 template<typename SizeType>
Chris@16 490 SizeType operator()(SizeType i) const
Chris@16 491 {
Chris@16 492 SizeType result = get_block_num(i) % p;
Chris@16 493 // std::cerr << "Item " << i << " goes on processor " << result << std::endl;
Chris@16 494 return result;
Chris@16 495 }
Chris@16 496
Chris@16 497 template<typename SizeType>
Chris@16 498 SizeType local(SizeType i) const
Chris@16 499 {
Chris@16 500 // Compute the start of the block
Chris@16 501 std::size_t block_num = get_block_num(i);
Chris@16 502 // std::cerr << "Item " << i << " is in block #" << block_num << std::endl;
Chris@16 503
Chris@16 504 std::size_t local_block_num = block_num / p;
Chris@16 505 std::size_t block_start = local_block_num * block_rows * block_columns;
Chris@16 506
Chris@16 507 // Compute the offset into the block
Chris@16 508 std::size_t data_row = i / data_columns_per_row;
Chris@16 509 std::size_t data_col = i % data_columns_per_row;
Chris@16 510 std::size_t block_offset = (data_row % block_rows) * block_columns
Chris@16 511 + (data_col % block_columns);
Chris@16 512
Chris@16 513 // std::cerr << "Item " << i << " maps to local index " << block_start+block_offset << std::endl;
Chris@16 514 return block_start + block_offset;
Chris@16 515 }
Chris@16 516
Chris@16 517 private:
Chris@16 518 template<typename SizeType>
Chris@16 519 std::size_t get_block_num(SizeType i) const
Chris@16 520 {
Chris@16 521 std::size_t data_row = i / data_columns_per_row;
Chris@16 522 std::size_t data_col = i % data_columns_per_row;
Chris@16 523 std::size_t block_row = data_row / block_rows;
Chris@16 524 std::size_t block_col = data_col / block_columns;
Chris@16 525 std::size_t blocks_in_row = data_columns_per_row / block_columns;
Chris@16 526 std::size_t block_num = block_col * blocks_in_row + block_row;
Chris@16 527 return global_to_local[block_num];
Chris@16 528 }
Chris@16 529
Chris@16 530 std::size_t id; //< The ID number of this processor
Chris@16 531 std::size_t p; //< The number of processors
Chris@16 532 std::size_t block_rows; //< The # of rows in each block
Chris@16 533 std::size_t block_columns; //< The # of columns in each block
Chris@16 534 std::size_t data_columns_per_row; //< The # of columns per row of data
Chris@16 535 std::vector<std::size_t> global_to_local;
Chris@16 536 };
Chris@16 537
Chris@16 538 class random_distribution
Chris@16 539 {
Chris@16 540 template<typename RandomNumberGen>
Chris@16 541 struct random_int
Chris@16 542 {
Chris@16 543 explicit random_int(RandomNumberGen& gen) : gen(gen) { }
Chris@16 544
Chris@16 545 template<typename T>
Chris@16 546 T operator()(T n) const
Chris@16 547 {
Chris@16 548 uniform_int<T> distrib(0, n-1);
Chris@16 549 return distrib(gen);
Chris@16 550 }
Chris@16 551
Chris@16 552 private:
Chris@16 553 RandomNumberGen& gen;
Chris@16 554 };
Chris@16 555
Chris@16 556 public:
Chris@16 557 template<typename LinearProcessGroup, typename RandomNumberGen>
Chris@16 558 random_distribution(const LinearProcessGroup& pg, RandomNumberGen& gen,
Chris@16 559 std::size_t n)
Chris@16 560 : base(pg, n), local_to_global(n), global_to_local(n)
Chris@16 561 {
Chris@16 562 std::copy(make_counting_iterator(std::size_t(0)),
Chris@16 563 make_counting_iterator(n),
Chris@16 564 local_to_global.begin());
Chris@16 565
Chris@16 566 random_int<RandomNumberGen> rand(gen);
Chris@16 567 std::random_shuffle(local_to_global.begin(), local_to_global.end(), rand);
Chris@16 568
Chris@16 569
Chris@16 570 for (std::vector<std::size_t>::size_type i = 0; i < n; ++i)
Chris@16 571 global_to_local[local_to_global[i]] = i;
Chris@16 572 }
Chris@16 573
Chris@16 574 template<typename SizeType>
Chris@16 575 SizeType block_size(SizeType n) const
Chris@16 576 { return base.block_size(n); }
Chris@16 577
Chris@16 578 template<typename SizeType, typename ProcessID>
Chris@16 579 SizeType block_size(ProcessID id, SizeType n) const
Chris@16 580 { return base.block_size(id, n); }
Chris@16 581
Chris@16 582 template<typename SizeType>
Chris@16 583 SizeType operator()(SizeType i) const
Chris@16 584 {
Chris@16 585 return base(global_to_local[i]);
Chris@16 586 }
Chris@16 587
Chris@16 588 template<typename SizeType>
Chris@16 589 SizeType local(SizeType i) const
Chris@16 590 {
Chris@16 591 return base.local(global_to_local[i]);
Chris@16 592 }
Chris@16 593
Chris@16 594 template<typename ProcessID, typename SizeType>
Chris@16 595 SizeType global(ProcessID p, SizeType i) const
Chris@16 596 {
Chris@16 597 return local_to_global[base.global(p, i)];
Chris@16 598 }
Chris@16 599
Chris@16 600 template<typename SizeType>
Chris@16 601 SizeType global(SizeType i) const
Chris@16 602 {
Chris@16 603 return local_to_global[base.global(i)];
Chris@16 604 }
Chris@16 605
Chris@16 606 private:
Chris@16 607 block base;
Chris@16 608 std::vector<std::size_t> local_to_global;
Chris@16 609 std::vector<std::size_t> global_to_local;
Chris@16 610 };
Chris@16 611
Chris@16 612 } } // end namespace boost::parallel
Chris@16 613
Chris@16 614 #endif // BOOST_PARALLEL_DISTRIBUTION_HPP
Chris@16 615