DASH  0.3.0
TeamSpec.h
1 #ifndef DASH__TEAM_SPEC_H_
2 #define DASH__TEAM_SPEC_H_
3 
4 #include <dash/Types.h>
5 #include <dash/Dimensional.h>
6 #include <dash/Exception.h>
7 #include <dash/Cartesian.h>
8 #include <dash/internal/Logging.h>
9 
10 #include <array>
11 #include <set>
12 #include <algorithm>
13 #include <sstream>
14 #include <iostream>
15 #include <cstring>
16 #include <type_traits>
17 #include <initializer_list>
18 
19 namespace dash {
20 
30 template<
31  dim_t MaxDimensions,
32  typename IndexType = dash::default_index_t>
33 class TeamSpec :
34  public CartesianIndexSpace<MaxDimensions, ROW_MAJOR, IndexType>
35 {
36 private:
37  typedef typename std::make_unsigned<IndexType>::type
38  SizeType;
40  self_t;
42  parent_t;
43 
44 public:
51  Team & team = dash::Team::All())
52  : _is_linear(true),
53  _myid(team.myid())
54  {
55  DASH_LOG_TRACE_VAR("TeamSpec(t)", team.is_null());
56  auto team_size = team.is_null() ? 0 : team.size();
57  _rank = 1;
58  this->_extents[0] = team_size;
59  for (auto d = 1; d < MaxDimensions; ++d) {
60  this->_extents[d] = 1;
61  }
62  this->resize(this->_extents);
63  }
64 
89  const self_t & other,
90  const DistributionSpec<MaxDimensions> & distribution,
91  Team & team = dash::Team::All())
92  : CartesianIndexSpace<MaxDimensions, ROW_MAJOR, IndexType>(
93  other.extents()),
94  _myid(team.myid())
95  {
96  DASH_LOG_TRACE_VAR("TeamSpec(ts, dist, t)", team.is_null());
97 #if 0
98  if (this->size() != team.size()) {
99  DASH_THROW(
101  "Size of team " << team.size() << " differs from " <<
102  "size of teamspec " << this->size() << " in TeamSpec()");
103  }
104 #endif
105  // Test if other teamspec has been default-constructed and has
106  // to be rearranged for a distribution with higher rank:
107  if (other._is_linear && distribution.rank() > 1) {
108  // Set extent of teamspec in the dimension the distribution is
109  // different from NONE:
110  if (distribution.is_tiled()) {
111  bool major_tiled_dim_set = false;
112  for (auto d = 0; d < MaxDimensions; ++d) {
113  this->_extents[d] = 1;
114  if (!major_tiled_dim_set &&
115  distribution[d].type == dash::internal::DIST_TILE) {
116  this->_extents[d] = team.size();
117  major_tiled_dim_set = true;
118  }
119  }
120  } else {
121  for (auto d = 0; d < MaxDimensions; ++d) {
122  if (distribution[d].type == dash::internal::DIST_NONE) {
123  this->_extents[d] = 1;
124  } else {
125  // Use size of given team; possibly different from size
126  // of default-constructed team spec:
127  this->_extents[d] = team.size();
128  }
129  }
130  }
131  }
132  update_rank();
133  DASH_LOG_TRACE_VAR("TeamSpec(ts, dist, t)", this->_extents);
134  this->resize(this->_extents);
135  DASH_LOG_TRACE_VAR("TeamSpec(ts, dist, t)", this->size());
136  }
137 
144  const DistributionSpec<MaxDimensions> & distribution,
145  Team & team = dash::Team::All())
146  : _myid(team.myid())
147  {
148  DASH_LOG_TRACE_VAR("TeamSpec(dist, t)", team.is_null());
149  bool distrib_dim_set = false;
150  if (distribution.is_tiled()) {
151  bool major_tiled_dim_set = false;
152  for (auto d = 0; d < MaxDimensions; ++d) {
153  this->_extents[d] = 1;
154  if (!major_tiled_dim_set &&
155  distribution[d].type == dash::internal::DIST_TILE) {
156  this->_extents[d] = team.size();
157  major_tiled_dim_set = true;
158  }
159  }
160  } else {
161  for (auto d = 0; d < MaxDimensions; ++d) {
162  if (distribution[d].type == dash::internal::DIST_NONE) {
163  this->_extents[d] = 1;
164  } else {
165  this->_extents[d] = team.size();
166  if (distrib_dim_set) {
167  DASH_THROW(
169  "TeamSpec(DistributionSpec, Team) only allows "
170  "one distributed dimension");
171  }
172  distrib_dim_set = true;
173  }
174  }
175  }
176  update_rank();
177  DASH_LOG_TRACE_VAR("TeamSpec(dist, t)", this->_extents);
178  this->resize(this->_extents);
179  DASH_LOG_TRACE_VAR("TeamSpec(dist, t)", this->size());
180  }
181 
192  template<typename ... Types>
193  TeamSpec(SizeType value, Types ... values)
194  : CartesianIndexSpace<MaxDimensions, ROW_MAJOR, IndexType>::
195  CartesianIndexSpace(value, values...),
196  _myid(dash::Team::All().myid())
197  {
198  update_rank();
199  this->resize(this->_extents);
200  DASH_LOG_TRACE_VAR("TeamSpec(size,...)", this->_extents);
201  }
202 
213  TeamSpec(const std::array<SizeType, MaxDimensions> & extents)
214  : CartesianIndexSpace<MaxDimensions, ROW_MAJOR, IndexType>::
215  CartesianIndexSpace(extents),
216  _myid(dash::Team::All().myid())
217  {
218  update_rank();
219  this->resize(this->_extents);
220  DASH_LOG_TRACE_VAR("TeamSpec({extents})", this->_extents);
221  }
222 
235  {
236  DASH_LOG_TRACE_VAR("TeamSpec.balance_extents()", this->_extents);
237  DASH_LOG_TRACE_VAR("TeamSpec.balance_extents()", this->size());
238  if(MaxDimensions <= 1) {
239  return;
240  }
241 
242  std::multiset<SizeType> new_extents;
243 
244  SizeType num_units = 1;
245  for (auto d = 0; d < MaxDimensions; ++d) {
246  num_units *= this->_extents[d];
247  this->_extents[d] = 1;
248  new_extents.insert(1);
249  }
250  _is_linear = false;
251 
252  // Find best surface-to-volume:
253  auto teamsize_prime_factors = dash::math::factorize(num_units);
254  // Equally distribute factors to extents.
255  // Start with the largest factors and multiply them onto the lowest
256  // value.
257  for (auto it = teamsize_prime_factors.rbegin();
258  it != teamsize_prime_factors.rend();
259  ++it) {
260  DASH_LOG_TRACE("TeamSpec.balance_extents()",
261  "factor:", it->first, "x", it->second);
262  for (auto i = 1; i < it->second + 1; ++i) {
263  new_extents.insert(it->first * *new_extents.begin());
264  new_extents.erase(new_extents.begin());
265  }
266  }
267 
268  int d = 0;
269  for (auto it = new_extents.rbegin();
270  it != new_extents.rend();
271  ++it, ++d) {
272  this->_extents[d] = *it;
273  }
274 
275  this->resize(this->_extents);
276  update_rank();
277  DASH_LOG_TRACE_VAR("TeamSpec.balance_extents() ->", this->_extents);
278  }
279 
298  team_unit_t neighbor(std::initializer_list<int> offsets) const
299  {
300  auto neighbor_coords = this->coords(_myid);
301  dim_t d = 0;
302  for (auto offset_d : offsets) {
303  neighbor_coords[d] += offset_d;
304  if (neighbor_coords[d] < 0 ||
305  neighbor_coords[d] >= this->_extents[d]) {
306  return UNDEFINED_TEAM_UNIT_ID;
307  }
308  ++d;
309  }
310  return team_unit_t(static_cast<dart_unit_t>(this->at(neighbor_coords)));
311  }
312 
313  team_unit_t neighbor(const std::array<int, MaxDimensions>& offsets) const
314  {
315  auto neighbor_coords = this->coords(_myid);
316  for (dim_t d = 0; d < MaxDimensions; ++d) {
317  neighbor_coords[d] += offsets[d];
318  if (neighbor_coords[d] < 0 ||
319  neighbor_coords[d] >= this->_extents[d]) {
320  return UNDEFINED_TEAM_UNIT_ID;
321  }
322  }
323  return team_unit_t(static_cast<dart_unit_t>(this->at(neighbor_coords)));
324  }
325 
350  team_unit_t periodic_neighbor(std::initializer_list<int> offsets) const
351  {
352  auto neighbor_coords = this->coords(_myid);
353  dim_t d = 0;
354  for (auto offset_d : offsets) {
355  neighbor_coords[d] += offset_d;
356  if (neighbor_coords[d] < 0) {
357  neighbor_coords[d] = this->_extents[d] + offset_d;
358  } else if(neighbor_coords[d] >= this->_extents[d]) {
359  neighbor_coords[d] %= this->_extents[d];
360  }
361  ++d;
362  }
363  return team_unit_t(static_cast<dart_unit_t>(this->at(neighbor_coords)));
364  }
365 
366  team_unit_t periodic_neighbor(const std::array<int, MaxDimensions>& offsets) const
367  {
368  auto neighbor_coords = this->coords(_myid);
369 
370  for (dim_t d = 0; d < MaxDimensions; ++d) {
371  neighbor_coords[d] += offsets[d];
372  if (neighbor_coords[d] < 0) {
373  neighbor_coords[d] = this->_extents[d] + offsets[d];
374  } else if(neighbor_coords[d] >= this->_extents[d]) {
375  neighbor_coords[d] %= this->_extents[d];
376  }
377  }
378  return team_unit_t(static_cast<dart_unit_t>(this->at(neighbor_coords)));
379  }
380 
386  IndexType index,
387  dim_t dimension,
388  IndexType dim_offset) const
389  {
390  if (_rank == 1) {
391  // Shortcut for trivial case
392  return (index >= 0 && index < this->size());
393  }
394  return parent_t::includes_index(index, dimension, dim_offset);
395  }
396 
403  SizeType num_units(dim_t dimension) const
404  {
405  return parent_t::extent(dimension);
406  }
407 
411  template<typename... Args>
412  void resize(SizeType arg, Args... args)
413  {
414  static_assert(
415  sizeof...(Args) == MaxDimensions-1,
416  "Invalid number of arguments");
417  std::array<SizeType, MaxDimensions> extents =
418  {{ arg, (SizeType)(args)... }};
419  resize(extents);
420  }
421 
425  template<typename SizeType_>
426  void resize(const std::array<SizeType_, MaxDimensions> & extents)
427  {
428  _is_linear = false;
429  parent_t::resize(extents);
430  update_rank();
431  }
432 
436  void resize_dim(dim_t dim, SizeType extent)
437  {
438  this->_extents[dim] = extent;
439  resize(this->_extents);
440  }
441 
454  dim_t rank() const
455  {
456  return _rank;
457  }
458 
459 private:
460  void update_rank()
461  {
462  _rank = 0;
463  for (auto d = 0; d < MaxDimensions; ++d) {
464  if (this->_extents[d] > 1) {
465  ++_rank;
466  }
467  }
468  if (_rank == 0) _rank = 1;
469  }
470 
471 protected:
473  dim_t _rank = 0;
475  bool _is_linear = false;
477  team_unit_t _myid;
478 
479 }; // class TeamSpec
480 
481 } // namespace dash
482 
483 #endif // DASH__TEAM_SPEC_H_
constexpr team_unit_t UNDEFINED_TEAM_UNIT_ID
Invalid local unit ID.
Definition: Types.h:341
bool includes_index(IndexType index, dim_t dimension, IndexType dim_offset) const
Whether the given index lies in the cartesian sub-space specified by a dimension and offset in the di...
Definition: TeamSpec.h:385
global_unit_t myid()
Shortcut to query the global unit ID of the calling unit.
constexpr std::enable_if< std::is_integral< IndexType >::value, IndexType >::type index(IndexType idx)
Definition: Iterator.h:60
This class is a simple memory pool which holds allocates elements of size ValueType.
Definition: AllOf.h:8
constexpr dim_t rank() const
The number of dimensions of the value.
Definition: Dimensional.h:200
bool is_tiled() const
Whether the distribution is tiled in any dimension.
Definition: Dimensional.h:304
dim_t rank() const
The actual number of dimensions with extent greater than 1 in this team arragement, that is the dimension of the vector space spanned by the team arrangement&#39;s extents.
Definition: TeamSpec.h:454
TeamSpec(const DistributionSpec< MaxDimensions > &distribution, Team &team=dash::Team::All())
Constructor, creates an instance of TeamSpec from a team (set of units) and a distribution spec...
Definition: TeamSpec.h:143
int dim_t
Scalar type for a dimension value, with 0 indicating the first dimension.
Definition: Types.h:39
void balance_extents()
Tries to equally distribute the units across the dimensions.
Definition: TeamSpec.h:234
void resize(SizeType arg, Args... args)
Change the extent of the cartesian space in every dimension.
Definition: Cartesian.h:350
internal::default_signed_index default_index_t
Signed integer type used as default for index values.
Definition: Types.h:59
A Team instance specifies a subset of all available units.
Definition: Team.h:41
constexpr const extents_type & extents() const noexcept
Extents of the cartesian space, by dimension.
Definition: Cartesian.h:402
std::array< IndexType, NumDimensions > coords(IndexType index) const
Convert given linear offset (index) to cartesian coordinates.
Definition: Cartesian.h:497
SizeType extent(dim_t dim) const
The extent of the cartesian space in the given dimension.
Definition: Cartesian.h:412
TeamSpec(SizeType value, Types ... values)
Constructor, initializes new instance of TeamSpec with extents specified in argument list...
Definition: TeamSpec.h:193
Defines a cartesian, totally-ordered index space by mapping linear indices to cartesian coordinates d...
Definition: Cartesian.h:239
TeamSpec(Team &team=dash::Team::All())
Constructor, creates an instance of TeamSpec from a team (set of units) with all team units organized...
Definition: TeamSpec.h:50
void resize_dim(dim_t dim, SizeType extent)
Change the extent of the cartesian space in the given dimension.
Definition: TeamSpec.h:436
team_unit_t neighbor(std::initializer_list< int > offsets) const
Resolve unit id at given offset in Cartesian team grid relative to the active unit&#39;s position in the ...
Definition: TeamSpec.h:298
constexpr IndexType at(IndexType arg, Args... args) const
Convert the given coordinates to their respective linear index.
Definition: Cartesian.h:429
Specifies the arrangement of team units in a specified number of dimensions.
Definition: TeamSpec.h:33
SizeType num_units(dim_t dimension) const
The number of units (extent) available in the given dimension.
Definition: TeamSpec.h:403
struct dash::unit_id< dash::local_unit, dart_team_unit_t > team_unit_t
Unit ID to use for team-local IDs.
Definition: Types.h:319
team_unit_t periodic_neighbor(std::initializer_list< int > offsets) const
Resolve unit id at given offset in Cartesian team grid relative to the active unit&#39;s position in the ...
Definition: TeamSpec.h:350
TeamSpec(const std::array< SizeType, MaxDimensions > &extents)
Constructor, initializes new instance of TeamSpec with extents specified in array by dimension...
Definition: TeamSpec.h:213
TeamSpec(const self_t &other, const DistributionSpec< MaxDimensions > &distribution, Team &team=dash::Team::All())
Constructor, creates an instance of TeamSpec with given extents from a team (set of units) and a dist...
Definition: TeamSpec.h:88
constexpr SizeType size() const noexcept
The number of discrete elements within the space spanned by the coordinate.
Definition: Cartesian.h:395
void resize(SizeType arg, Args... args)
Change the extent of the cartesian space in every dimension.
Definition: TeamSpec.h:412
static Team & All()
The invariant Team instance containing all available units.
Definition: Team.h:213
void resize(const std::array< SizeType_, MaxDimensions > &extents)
Change the extent of the cartesian space in every dimension.
Definition: TeamSpec.h:426
DistributionSpec describes distribution patterns of all dimensions,.
Definition: Dimensional.h:222