SIRIUS 7.5.0
Electronic structure library and applications
splindex.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2016 Anton Kozhevnikov, Thomas Schulthess
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
5// the following conditions are met:
6//
7// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
8// following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
10// and the following disclaimer in the documentation and/or other materials provided with the distribution.
11//
12// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
13// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
15// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
16// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
18// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
20/** \file splindex.hpp
21 *
22 * \brief Contains definition of sddk::splindex_base and specializations of sddk::splindex class.
23 */
24
25#ifndef __SPLINDEX_HPP__
26#define __SPLINDEX_HPP__
27
28#include "core/strong_type.hpp"
29#include "core/rte/rte.hpp"
30#include <cstddef>
31#include <numeric>
32
33namespace sirius {
34
35/// Return the maximum number of blocks (with size 'block_size') needed to split the 'length' elements.
36inline int num_blocks(int length__, int block_size__)
37{
38 return (length__ / block_size__) + std::min(length__ % block_size__, 1);
39}
40
41/// Split the 'length' elements into blocks with the initial block size.
42/** Return vector of block sizes that sum up to the initial 'length'. */
43inline auto split_in_blocks(int length__, int block_size__)
44{
45 int nb = num_blocks(length__, block_size__);
46 /* adjust the block size; this is done to prevent very unequal block sizes */
47 /* Take, for example, 21 elements and initial block size of 15. Number of blocks equals 2.
48 * Final block size is 21 / 2 + min(1, 21 % 2) = 11. Thus 21 elements will be split in two blocks
49 * of 11 and 10 elements. */
50 block_size__ = length__ / nb + std::min(1, length__ % nb);
51
52 std::vector<int> result(nb);
53
54 for (int i = 0; i < nb; i++) {
55 result[i] = std::min(length__, (i + 1) * block_size__) - i * block_size__;
56 }
57 /* check for correctness */
58 if (std::accumulate(result.begin(), result.end(), 0) != length__) {
59 throw std::runtime_error("error in sirius::split_in_blocks()");
60 }
61
62 return result;
63}
64
65/// Basic index type.
66template <typename T = int>
68 typedef T value_type;
69 typedef T global;
70 typedef T local;
71};
72
73/// K-point index type.
74struct kp_index_t {
75 typedef int value_type;
78};
79
81 typedef int value_type;
84};
85
87 typedef int value_type;
90};
91
93 typedef int value_type;
96};
97
99 typedef int value_type;
102};
103
104/// Number of blocks to which the global index is split.
106/// ID of the block.
107/** The id of the block has the range [0, n_blocks) */
109
111{
112 /// Global index.
113 global,
114 /// Local index.
115 local
116};
117
118/// Base class for split index.
119template <typename Index_t = basic_index_t<int>>
121{
122 public:
123 using value_type = typename Index_t::value_type;
124 protected:
125 /// Number of blocks over which the global index is distributed.
127
128 /// Index of the block with local fraction of the global index.
130
131 /// Size (aka length) of the global index.
132 value_type size_{-1};
133
134 /// Pair of <local index, block_id> describing the location of a global index element.
136 {
137 /// Local index inside a block.
138 typename Index_t::local index_local;
139 /// Index of the block.
141 /// Constructor.
142 location_t(typename Index_t::local index_local__, block_id ib__)
143 : index_local(index_local__)
144 , ib(ib__)
145 {
146 }
147 };
148
149 public:
150
151 /// Default constructor.
153 {
154 }
155
156 /// Constructor.
157 /** Check and set index size, number of blocks and block id. */
158 splindex(value_type size__, n_blocks n_blocks__, block_id block_id__)
159 {
160 if (size__ < 0) {
161 std::stringstream s;
162 s << "wrong size : " << size__;
163 throw std::runtime_error(s.str());
164 }
165 this->size_ = size__;
166
167 if (n_blocks__.get() < 0) {
168 std::stringstream s;
169 s << "wrong number of blocks : " << n_blocks__.get();
170 throw std::runtime_error(s.str());
171 }
172 this->n_blocks_ = n_blocks__;
173
174 if (block_id__.get() < 0 || block_id__.get() >= n_blocks__.get()) {
175 std::stringstream s;
176 s << "wrong rank block id : " << block_id__.get();
177 throw std::runtime_error(s.str());
178 }
179 this->block_id_ = block_id__;
180 }
181
182 virtual ~splindex()
183 {
184 }
185
186 /// Return local size of the split index for a given block.
187 virtual value_type local_size(block_id block_id__) const = 0;
188
189 /// Return location (block_id and local offset) of the global index.
190 virtual location_t location(typename Index_t::global idx__) const = 0;
191
192 /// Return global index by block id and local index.
193 virtual typename Index_t::global global_index(typename Index_t::local idxloc__, block_id block_id__) const = 0;
194
195 /// Return local size for the current block.
196 value_type local_size() const
197 {
198 return this->local_size(this->block_id_);
199 }
200
201 /// Return global index of an element by local index and block id.
202 inline auto global_index(typename splindex<Index_t>::location_t loc__) const
203 {
204 return this->global_index(loc__.index_local, loc__.ib);
205 }
206
207 inline auto global_index(typename Index_t::local idxloc__) const
208 {
209 return this->global_index(idxloc__, this->block_id_);
210 }
211
212 /// Return total length of the index (global number of elements).
213 inline auto size() const noexcept
214 {
215 return size_;
216 }
217
218 /// Compute size of the block from global index size and number of blocks.
219 static inline auto block_size(value_type size__, n_blocks n_blocks__)
220 {
221 return size__ / n_blocks__ + std::min(value_type(1), size__ % n_blocks__);
222 }
223};
224
225template <typename Index_t>
227{
228 private:
229 splindex<Index_t> const* idx_{nullptr};
230 public:
231 using difference_type = std::ptrdiff_t;
232 typename Index_t::local li;
233
234 splindex_iterator_t<Index_t>& operator=(splindex_iterator_t<Index_t> const& lhs_) = default;
235
237 : idx_{&idx__}
238 , li{0}
239 {
240 }
241
242 inline bool operator!=(splindex_iterator_t<Index_t> const& rhs__)
243 {
244 return this->li != rhs__.li;
245 }
246
247 inline splindex_iterator_t<Index_t>& operator++()
248 {
249 this->li++;
250 return *this;
251 }
252
253 inline splindex_iterator_t<Index_t> operator++(int)
254 {
255 splindex_iterator_t<Index_t> tmp(this->idx());
256 this->li++;
257 return tmp;
258 }
259
260 inline auto operator*()
261 {
262 struct {
263 typename Index_t::global i;
264 typename Index_t::local li; } ret{idx_->global_index(this->li), this->li};
265 return ret;
266 }
267
268 inline difference_type operator-(splindex_iterator_t<Index_t> const& rhs__) const
269 {
270 return li - rhs__.li;
271 }
272
273 inline splindex_iterator_t<Index_t>& operator+=(difference_type rhs__)
274 {
275 li += rhs__;
276 return *this;
277 }
278};
279
280template <typename Index_t = basic_index_t<int>>
281class splindex_block : public splindex<Index_t>
282{
283 public:
284 using value_type = typename splindex<Index_t>::value_type;
285 private:
286 /// Local index size of a given block.
287 value_type block_size_;
288 public:
290 {
291 }
292 /// Constructor.
293 splindex_block(value_type size__, n_blocks n_blocks__, block_id block_id__)
294 : splindex<Index_t>(size__, n_blocks__, block_id__)
295 {
296 this->block_size_ = this->block_size(size__, n_blocks__);
297 }
298
300
301 /// Return local size of the split index for a given block.
302 inline value_type local_size(block_id block_id__) const
303 {
304 RTE_ASSERT(block_id__ >= 0 && block_id__ < this->n_blocks_);
305
306 if (this->size_ == 0) {
307 return 0;
308 }
309
310 auto n = static_cast<int>(this->size_ / block_size_);
311 if (block_id__ < n) {
312 return block_size_;
313 } else {
314 return std::max(0, this->size_ - block_id__ * block_size_);
315 }
316 }
317
318 /// Return "local index, rank" pair for a global index.
319 inline typename splindex<Index_t>::location_t location(typename Index_t::global idx__) const
320 {
321 RTE_ASSERT(idx__ < this->size_);
322
323 auto ib = static_cast<int>(idx__ / this->block_size_);
324 value_type idxloc = idx__ - ib * this->block_size_;
325
326 return typename splindex<Index_t>::location_t(typename Index_t::local(idxloc), block_id(ib));
327 }
328
330
331 /// Return global index of an element by local index and block id.
332 inline typename Index_t::global global_index(typename Index_t::local idxloc__, block_id block_id__) const
333 {
334 RTE_ASSERT(block_id__ >= 0 && block_id__ < this->n_blocks_);
335
336 if (this->local_size(block_id__) == 0) {
337 return typename Index_t::global(-1);
338 }
339
340 RTE_ASSERT(idxloc__ < local_size(block_id__));
341
342 return typename Index_t::global(this->block_size_ * block_id__ + idxloc__);
343 }
344
345 inline auto global_offset() const
346 {
347 return this->global_index(typename Index_t::local(0), this->block_id_);
348 }
349
350 inline auto global_offset(block_id iblock__) const
351 {
352 return this->global_index(typename Index_t::local(0), iblock__);
353 }
354
355 inline auto counts() const
356 {
357 std::vector<value_type> v(this->n_blocks_);
358 for (int i = 0; i < this->n_blocks_; i++) {
359 v[i] = local_size(block_id(i));
360 }
361 return v;
362 }
363};
364
365template <typename Index_t = basic_index_t<int>>
366class splindex_block_cyclic : public splindex<Index_t>
367{
368 public:
369 using value_type = typename splindex<Index_t>::value_type;
370 private:
371 /// Cyclic block size.
372 value_type block_size_;
373 public:
375 {
376 }
377 /// Constructor.
378 splindex_block_cyclic(value_type size__, n_blocks n_blocks__, block_id block_id__, value_type block_size__)
379 : splindex<Index_t>(size__, n_blocks__, block_id__)
380 , block_size_{block_size__}
381 {
382 }
383
385
386 /// Return local size of the split index for a given block.
387 inline value_type local_size(block_id block_id__) const
388 {
389 RTE_ASSERT(block_id__ >= 0 && block_id__ < this->n_blocks_);
390
391 if (this->size_ == 0) {
392 return 0;
393 }
394 /* number of full blocks */
395 auto num_blocks = this->size() / this->block_size_;
396
397 auto n = (num_blocks / this->n_blocks_) * this->block_size_;
398 auto rank_offs = static_cast<int>(num_blocks % this->n_blocks_);
399
400 if (block_id__ < rank_offs) {
401 n += this->block_size_;
402 } else if (block_id__ == rank_offs) {
403 n += this->size_ % this->block_size_;
404 }
405 return n;
406 }
407
408 /// Return "local index, rank" pair for a global index.
409 inline typename splindex<Index_t>::location_t location(typename Index_t::global idx__) const
410 {
411 RTE_ASSERT(idx__ < this->size_);
412
413 /* number of full blocks */
414 auto num_blocks = idx__ / this->block_size_;
415
416 /* local index */
417 value_type idxloc = (num_blocks / this->n_blocks_) * block_size_ + idx__ % this->block_size_;
418
419 /* corresponding rank */
420 auto ib = static_cast<int>(num_blocks % this->n_blocks_);
421
422 return typename splindex<Index_t>::location_t(typename Index_t::local(idxloc), block_id(ib));
423 }
424
426
427 /// Return global index of an element by local index and block id.
428 inline typename Index_t::global global_index(typename Index_t::local idxloc__, block_id block_id__) const
429 {
430 RTE_ASSERT(block_id__ >= 0 && block_id__ < this->n_blocks_);
431 RTE_ASSERT(idxloc__ < local_size(block_id__));
432
433 auto nb = idxloc__ / this->block_size_;
434
435 return typename Index_t::global((nb * this->n_blocks_ + block_id__) * this->block_size_ +
436 idxloc__ % this->block_size_);
437 }
438
439};
440
441/// Externally defined block distribution.
442template <typename Index_t = basic_index_t<int>>
443class splindex_chunk : public splindex<Index_t>
444{
445 public:
446 using value_type = typename splindex<Index_t>::value_type;
447 private:
448 std::vector<std::vector<value_type>> global_index_;
449 std::vector<typename splindex<Index_t>::location_t> locations_;
450
451 public:
452 /// Default constructor.
454 {
455 }
456
457 /// Constructor with specific partitioning.
458 splindex_chunk(value_type size__, n_blocks n_blocks__, block_id block_id__, std::vector<value_type> const counts__)
459 : splindex<Index_t>(size__, n_blocks__, block_id__)
460 {
461 for (int r = 0; r < n_blocks__.get(); r++) {
462 global_index_.push_back(std::vector<value_type>());
463 for (value_type i = 0; i < counts__[r]; i++) {
464 global_index_.back().push_back(static_cast<value_type>(locations_.size()));
465 locations_.push_back(typename splindex<Index_t>::location_t(typename Index_t::local(i), block_id(r)));
466 }
467 }
468
469 RTE_ASSERT(static_cast<value_type>(locations_.size()) == this->size());
470 }
471
473
474 inline value_type local_size(block_id block_id__) const
475 {
476 RTE_ASSERT(block_id__ >= 0 && block_id__ < this->n_blocks_);
477
478 if (this->size_ == 0) {
479 return 0;
480 }
481 return static_cast<value_type>(global_index_[block_id__].size());
482 }
483
484 inline typename splindex<Index_t>::location_t location(typename Index_t::global idx__) const
485 {
486 return locations_[idx__];
487 }
488
490
491 inline typename Index_t::global global_index(typename Index_t::local idxloc__, block_id block_id__) const
492 {
493 RTE_ASSERT(block_id__ >= 0 && block_id__ < this->n_blocks_);
494 RTE_ASSERT(idxloc__ < local_size(block_id__));
495
496 return typename Index_t::global(global_index_[block_id__][idxloc__]);
497 }
498
499 inline auto global_offset() const
500 {
501 return this->global_index(typename Index_t::local(0), this->block_id_);
502 }
503};
504
505template <typename Index_t>
506auto begin_global(splindex<Index_t> const& a__)
507{
508 return typename Index_t::global(0);
509}
510
511template <typename Index_t>
512auto end_global(splindex<Index_t> const& a__)
513{
514 return typename Index_t::global(a__.size());
515}
516
517template <typename Index_t>
518auto begin(splindex<Index_t> const& a__)
519{
520 splindex_iterator_t<Index_t> it(a__);
521 it.li = typename Index_t::local(0);
522 return it;
523}
524
525template <typename Index_t>
526auto end(splindex<Index_t> const& a__)
527{
528 splindex_iterator_t<Index_t> it(a__);
529 it.li = typename Index_t::local(a__.local_size());
530 return it;
531}
532
533} // namespace sirius
534
535#endif // __SPLINDEX_HPP__
value_type block_size_
Cyclic block size.
Definition: splindex.hpp:372
Index_t::global global_index(typename Index_t::local idxloc__, block_id block_id__) const
Return global index of an element by local index and block id.
Definition: splindex.hpp:428
splindex< Index_t >::location_t location(typename Index_t::global idx__) const
Return "local index, rank" pair for a global index.
Definition: splindex.hpp:409
value_type local_size(block_id block_id__) const
Return local size of the split index for a given block.
Definition: splindex.hpp:387
splindex_block_cyclic(value_type size__, n_blocks n_blocks__, block_id block_id__, value_type block_size__)
Constructor.
Definition: splindex.hpp:378
value_type local_size(block_id block_id__) const
Return local size of the split index for a given block.
Definition: splindex.hpp:302
value_type block_size_
Local index size of a given block.
Definition: splindex.hpp:287
splindex< Index_t >::location_t location(typename Index_t::global idx__) const
Return "local index, rank" pair for a global index.
Definition: splindex.hpp:319
Index_t::global global_index(typename Index_t::local idxloc__, block_id block_id__) const
Return global index of an element by local index and block id.
Definition: splindex.hpp:332
splindex_block(value_type size__, n_blocks n_blocks__, block_id block_id__)
Constructor.
Definition: splindex.hpp:293
Externally defined block distribution.
Definition: splindex.hpp:444
splindex< Index_t >::location_t location(typename Index_t::global idx__) const
Return location (block_id and local offset) of the global index.
Definition: splindex.hpp:484
splindex_chunk()
Default constructor.
Definition: splindex.hpp:453
splindex_chunk(value_type size__, n_blocks n_blocks__, block_id block_id__, std::vector< value_type > const counts__)
Constructor with specific partitioning.
Definition: splindex.hpp:458
Index_t::global global_index(typename Index_t::local idxloc__, block_id block_id__) const
Return global index by block id and local index.
Definition: splindex.hpp:491
value_type local_size(block_id block_id__) const
Return local size of the split index for a given block.
Definition: splindex.hpp:474
Base class for split index.
Definition: splindex.hpp:121
value_type local_size() const
Return local size for the current block.
Definition: splindex.hpp:196
n_blocks n_blocks_
Number of blocks over which the global index is distributed.
Definition: splindex.hpp:126
virtual Index_t::global global_index(typename Index_t::local idxloc__, block_id block_id__) const =0
Return global index by block id and local index.
splindex(value_type size__, n_blocks n_blocks__, block_id block_id__)
Constructor.
Definition: splindex.hpp:158
auto global_index(typename splindex< Index_t >::location_t loc__) const
Return global index of an element by local index and block id.
Definition: splindex.hpp:202
value_type size_
Size (aka length) of the global index.
Definition: splindex.hpp:132
splindex()
Default constructor.
Definition: splindex.hpp:152
virtual value_type local_size(block_id block_id__) const =0
Return local size of the split index for a given block.
static auto block_size(value_type size__, n_blocks n_blocks__)
Compute size of the block from global index size and number of blocks.
Definition: splindex.hpp:219
virtual location_t location(typename Index_t::global idx__) const =0
Return location (block_id and local offset) of the global index.
block_id block_id_
Index of the block with local fraction of the global index.
Definition: splindex.hpp:129
auto size() const noexcept
Return total length of the index (global number of elements).
Definition: splindex.hpp:213
Namespace of the SIRIUS library.
Definition: sirius.f90:5
int num_blocks(int length__, int block_size__)
Return the maximum number of blocks (with size 'block_size') needed to split the 'length' elements.
Definition: splindex.hpp:36
auto split_in_blocks(int length__, int block_size__)
Split the 'length' elements into blocks with the initial block size.
Definition: splindex.hpp:43
index_domain_t
Definition: splindex.hpp:111
@ global
Global index.
strong_type< int, struct __block_id_tag > block_id
ID of the block.
Definition: splindex.hpp:108
Eror and warning handling during run-time execution.
A wrapper class to create strong types.
Basic index type.
Definition: splindex.hpp:67
K-point index type.
Definition: splindex.hpp:74
Pair of <local index, block_id> describing the location of a global index element.
Definition: splindex.hpp:136
block_id ib
Index of the block.
Definition: splindex.hpp:140
location_t(typename Index_t::local index_local__, block_id ib__)
Constructor.
Definition: splindex.hpp:142
Index_t::local index_local
Local index inside a block.
Definition: splindex.hpp:138