https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MultiIndex.h
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#pragma once
11
12#include "Moose.h"
13#include "MooseError.h"
14#include "DataIO.h"
15#include <algorithm>
16
21template <class T>
23{
24public:
26 template <bool is_const = false>
28
30 typedef T value_type;
31 typedef std::vector<unsigned int> size_type;
35
37 MultiIndex(const size_type & shape);
38
40 MultiIndex(const size_type & shape, const std::vector<T> & data);
41
43 T & operator()(const size_type & indices);
44 const T & operator()(const size_type & indices) const;
46
48 T & operator[](unsigned int j) { return _data[j]; }
49 const T & operator[](unsigned int j) const { return _data[j]; }
50 T & at(unsigned int j) { return _data.at(j); }
52
54 MultiIndex<T> slice(unsigned int dimension, unsigned int index) const;
55 MultiIndex<T> slice(size_type dimension, size_type index) const;
57
59 const size_type & size() const { return _shape; }
60
62 unsigned int dim() const { return _shape.size(); }
63
65 unsigned int nEntries() const { return _nentries; }
66
68 std::vector<T> getRawData() const { return _data; }
69
71 void resize(const size_type & shape);
72
74 void assign(const size_type & shape, T value);
75
77 unsigned int stride(unsigned int j) const;
78 const size_type & stride() const { return _stride; }
80
82 void dataStore(std::ostream & stream, void * context);
83 void dataLoad(std::istream & stream, void * context);
85
92
94 unsigned int flatIndex(const size_type & indices) const;
95
96protected:
98 void findIndexVector(unsigned int flat_index, size_type & indices) const;
99
102
104 unsigned int _dim;
105
107 unsigned int _nentries;
108
111
113 std::vector<T> _data;
114
115private:
118
120 void reshape(const size_type & shape);
121};
122
126template <class T>
127template <bool is_const>
129{
130public:
131 typedef typename std::conditional<is_const, const MultiIndex<T> &, MultiIndex<T> &>::type
133
134 const_noconst_iterator(reference_type multi_index, unsigned int position)
135 : _multi_index(multi_index), _flat_index(position), _shape(multi_index.size())
136 {
137 _multi_index.findIndexVector(position, _indices);
138 }
139
140 // Simple data getters
141 unsigned int flatIndex() const { return _flat_index; }
142 reference_type getMultiIndexObject() const { return _multi_index; }
143
144 // assignment =
146 {
147 _multi_index = other.getMultiIndexObject();
148 _flat_index = other.flatIndex();
149 _multi_index.findIndexVector(_flat_index, _indices);
150 return *this;
151 }
152
153 // Compiler generated copy constructor
155
156 // prefix ++
158 {
159 ++_flat_index;
160 // increment indices
161 for (unsigned int j = 0; j < _indices.size(); ++j)
162 {
163 _indices[_indices.size() - j - 1] =
164 (_indices[_indices.size() - j - 1] + 1) % _shape[_indices.size() - j - 1];
165 if (_indices[_indices.size() - j - 1] != 0)
166 break;
167 }
168 return *this;
169 }
170
171 // postfix ++
173 {
174 const_noconst_iterator clone(*this);
175 ++_flat_index;
176 // increment indices
177 for (unsigned int j = 0; j < _indices.size(); ++j)
178 {
179 _indices[_indices.size() - j - 1] =
180 (_indices[_indices.size() - j - 1] + 1) % _shape[_indices.size() - j - 1];
181 if (_indices[_indices.size() - j - 1] != 0)
182 break;
183 }
184 return clone;
185 }
186
187 // prefix --
189 {
190 --_flat_index;
191 // decrement indices
192 for (unsigned int j = 0; j < _indices.size(); ++j)
193 {
194 if (_indices[_indices.size() - j - 1] == 0)
195 _indices[_indices.size() - j - 1] = _shape[_indices.size() - j - 1] - 1;
196 else
197 {
198 --_indices[_indices.size() - j - 1];
199 break;
200 }
201 }
202 return *this;
203 }
204
205 // postfix --
207 {
208 const_noconst_iterator clone(*this);
209 --_flat_index;
210 // decrement indices
211 for (unsigned int j = 0; j < _indices.size(); ++j)
212 {
213 if (_indices[_indices.size() - j - 1] == 0)
214 _indices[_indices.size() - j - 1] = _shape[_indices.size() - j - 1] - 1;
215 else
216 {
217 --_indices[_indices.size() - j - 1];
218 break;
219 }
220 }
221 return clone;
222 }
223
225 bool operator==(const const_noconst_iterator & other) const
226 {
227 return _flat_index == other.flatIndex() && &_multi_index == &other.getMultiIndexObject();
228 }
229 bool operator!=(const const_noconst_iterator & other) const { return !(*this == other); }
230
232 std::pair<const size_type &, T &> operator*()
233 {
234 return std::pair<const size_type &, T &>(_indices, _multi_index._data[_flat_index]);
235 }
236 std::pair<const size_type &, const T &> operator*() const
237 {
238 return std::pair<const size_type &, const T &>(_indices, _multi_index._data[_flat_index]);
239 }
240
241protected:
243 unsigned int _flat_index;
246};
247
248template <class T>
250{
251 reshape(shape);
252 _data.resize(_nentries);
253}
254
255template <class T>
256MultiIndex<T>::MultiIndex(const size_type & shape, const std::vector<T> & data)
257{
258 reshape(shape);
259
260 if (data.size() != _nentries)
261 mooseError("shape and data arguments' sizes are inconsistent.");
262 _data = data;
263}
264
265template <class T>
266T &
268{
269 return _data[flatIndex(indices)];
270}
271
272template <class T>
273const T &
275{
276 return _data[flatIndex(indices)];
277}
278
279template <class T>
281MultiIndex<T>::slice(unsigned int dimension, unsigned int index) const
282{
283 size_type dim(1, dimension);
284 size_type ind(1, index);
285 return slice(dim, ind);
286}
287
288template <class T>
291{
292 // input checks
293 if (dimension.size() != index.size())
294 mooseError("dimension and index must have the same size.");
295 if (dimension.size() > _dim - 1)
296 mooseError("The result of slice must be at least of dimension 1.");
297
298#if DEBUG
299 for (unsigned int d = 0; d < dimension.size(); ++d)
300 {
301 if (dimension[d] >= _dim)
302 mooseError("dimension is set to ", dimension[d], " which is larger than _dim ", _dim);
303 if (index[d] >= _shape[dimension[d]])
304 mooseError("index= ",
305 index[d],
306 " at dimension=",
307 dimension[d],
308 " is larger than ",
309 _shape[dimension[d]]);
310 }
311#endif // DEBUG
312
313 // create a MultiIndex object with new dim = dim - dimension.size()
314 size_type new_shape;
315 for (unsigned int j = 0; j < _dim; ++j)
316 if (std::find(dimension.begin(), dimension.end(), j) == dimension.end())
317 new_shape.push_back(_shape[j]);
318 MultiIndex<T> multi_index = MultiIndex(new_shape);
319
320 // copy the data
321 MultiIndex<T>::iterator it = multi_index.begin();
322 for (unsigned int n = 0; n < _nentries; ++n)
323 {
324 size_type indices;
325 findIndexVector(n, indices);
326 bool addTo = true;
327 for (unsigned int d = 0; d < dimension.size(); ++d)
328 if (indices[dimension[d]] != index[d])
329 {
330 addTo = false;
331 break;
332 }
333
334 if (addTo)
335 {
336 (*it).second = _data[n];
337 ++it;
338 }
339 }
340 return multi_index;
341}
342
343template <class T>
344void
346{
347 if (shape.size() != _shape.size())
348 mooseError("resize cannot change the dimensionality of MultiIndex.");
349
350 // first copy the old shape and data
351 size_type old_shape = _shape;
352 size_type old_stride = _stride;
353 std::vector<T> old_data = _data;
354
355 // reset _shape & recompute meta data
356 reshape(shape);
357
358 // fill in _data to all possible indices
359 _data.assign(_nentries, T(0));
360 for (unsigned int j = 0; j < _nentries; ++j)
361 {
362 size_type indices;
363 findIndexVector(j, indices);
364
365 // check if indices existed in the old version of _data
366 bool existed_in_old = true;
367 for (unsigned int d = 0; d < _dim; ++d)
368 if (indices[d] >= old_shape[d])
369 {
370 existed_in_old = false;
371 break;
372 }
373
374 // find the corresponding old_j
375 if (existed_in_old)
376 {
377 unsigned int old_j = 0;
378 for (unsigned int d = 0; d < _dim; ++d)
379 old_j += indices[d] * old_stride[d];
380
381 // finally set the data entry
382 _data[j] = old_data[old_j];
383 }
384 }
385}
386
387template <class T>
388unsigned int
389MultiIndex<T>::stride(unsigned int j) const
390{
391 mooseAssert(j < _dim, "Dimension is" << _dim << ", stride(j) called with j = " << j);
392 return _stride[j];
393}
394
395template <class T>
396void
397MultiIndex<T>::assign(const size_type & shape, T value)
398{
399 reshape(shape);
400 _data.assign(_nentries, value);
401}
402
403template <class T>
404void
405MultiIndex<T>::dataStore(std::ostream & stream, void * context)
406{
407 ::dataStore(stream, _shape, context);
408 ::dataStore(stream, _data, context);
409}
410
411template <class T>
412void
413MultiIndex<T>::dataLoad(std::istream & stream, void * context)
414{
415 ::dataLoad(stream, _shape, context);
416 ::dataLoad(stream, _data, context);
417 _dim = _shape.size();
418 _nentries = _data.size();
419 buildAccumulatedShape();
420}
421
422template <class T>
423void
424MultiIndex<T>::findIndexVector(unsigned int flat_index, MultiIndex<T>::size_type & indices) const
425{
426 indices.resize(_dim);
427 for (unsigned int d = 0; d < _dim; ++d)
428 {
429 unsigned int i = flat_index / _stride[d];
430 indices[d] = i;
431 flat_index -= i * _stride[d];
432 }
433}
434
435// compute the accumulated shapes as:
436// as[0] = I_1 * I_2 ...* I_{M}, as[1] = I_2 * I_3 ...* I_{M} ...
437template <class T>
438void
440{
441 // TODO: simplify - this is needlessly complicated - can be done in a single loop
442 _stride.resize(_dim);
443 for (unsigned int d = 0; d < _dim; ++d)
444 {
445 unsigned int k = 1;
446 for (unsigned int j = d + 1; j < _dim; ++j)
447 k *= _shape[j];
448 _stride[d] = k;
449 }
450}
451
452template <class T>
453void
455{
456 if (shape.size() == 0)
457 {
458 _shape = {};
459 _dim = 0;
460 _stride = {};
461 _nentries = 0;
462 return;
463 }
464
465 _shape = shape;
466 _dim = shape.size();
467
468 _nentries = 1;
469 for (unsigned int d = 0; d < _dim; ++d)
470 _nentries *= _shape[d];
471
472 buildAccumulatedShape();
473}
474
475template <class T>
476unsigned int
478{
479 mooseAssert(indices.size() == _dim,
480 "Indices vector has wrong size. size=" << indices.size() << " vs. dim=" << _dim);
481#if DEBUG
482 for (unsigned int j = 0; j < indices.size(); ++j)
483 if (indices[j] >= _shape[j])
484 mooseError("Indices vector at entry ", j, " is ", indices[j], " vs. shape ", _shape[j]);
485#endif // DEBUG
486
487 // implement the index
488 // index = i_M + i_{M-1} * I_M + i_{M-1} * I_M * I_{M-1} ...
489 unsigned int index = 0;
490 for (unsigned int d = 0; d < _dim; ++d)
491 index += indices[d] * _stride[d];
492
493 return index;
494}
495
496template <class T>
497void
498dataStore(std::ostream & stream, MultiIndex<T> & mi, void * context)
499{
500 mi.dataStore(stream, context);
501}
502
503template <class T>
504void
505dataLoad(std::istream & stream, MultiIndex<T> & mi, void * context)
506{
507 mi.dataLoad(stream, context);
508}
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
void dataStore(std::ostream &stream, MultiIndex< T > &mi, void *context)
Definition MultiIndex.h:498
void dataLoad(std::istream &stream, MultiIndex< T > &mi, void *context)
Definition MultiIndex.h:505
unsigned int dim
MultiIndex container iterator.
Definition MultiIndex.h:129
std::pair< const size_type &, const T & > operator*() const
Definition MultiIndex.h:236
unsigned int flatIndex() const
Definition MultiIndex.h:141
const_noconst_iterator & operator--()
Definition MultiIndex.h:188
const_noconst_iterator(const const_noconst_iterator &)=default
bool operator!=(const const_noconst_iterator &other) const
Definition MultiIndex.h:229
std::pair< const size_type &, T & > operator*()
dereferencing operator
Definition MultiIndex.h:232
std::conditional< is_const, constMultiIndex< T > &, MultiIndex< T > & >::type reference_type
Definition MultiIndex.h:132
const_noconst_iterator & operator++(int)
Definition MultiIndex.h:172
const_noconst_iterator & operator++()
Definition MultiIndex.h:157
const_noconst_iterator & operator--(int)
Definition MultiIndex.h:206
const_noconst_iterator(reference_type multi_index, unsigned int position)
Definition MultiIndex.h:134
const_noconst_iterator & operator=(const const_noconst_iterator &other)
Definition MultiIndex.h:145
reference_type getMultiIndexObject() const
Definition MultiIndex.h:142
bool operator==(const const_noconst_iterator &other) const
to be equal both iterators must hold a reference to the same MultiIndexObject and be at the same _fla...
Definition MultiIndex.h:225
Implements a container class for multi-indexed objects with an arbitrary number of indices.
Definition MultiIndex.h:23
void findIndexVector(unsigned int flat_index, size_type &indices) const
given a flat index computes the vector of indices i0, i1, i2, ...
Definition MultiIndex.h:424
std::vector< T > _data
the data unrolled into a vector
Definition MultiIndex.h:113
unsigned int stride(unsigned int j) const
access the stride
Definition MultiIndex.h:389
MultiIndex< T > slice(unsigned int dimension, unsigned int index) const
accesses a slice of the multi index object
Definition MultiIndex.h:281
T & operator()(const size_type &indices)
element access operators
Definition MultiIndex.h:267
size_type _shape
the size along each index
Definition MultiIndex.h:101
const T & operator()(const size_type &indices) const
Definition MultiIndex.h:274
std::vector< unsigned int > size_type
Definition MultiIndex.h:31
iterator end()
Definition MultiIndex.h:88
const size_type & size() const
container size as dim dimensional vector
Definition MultiIndex.h:59
unsigned int nEntries() const
total number of values stored in the container
Definition MultiIndex.h:65
T & operator[](unsigned int j)
direct data access via bracket operator
Definition MultiIndex.h:48
void resize(const size_type &shape)
Resize container. Must keep dimensionality constant.
Definition MultiIndex.h:345
const_iterator end() const
Definition MultiIndex.h:90
void assign(const size_type &shape, T value)
Reshape container arbitrarily and initialize with value.
Definition MultiIndex.h:397
unsigned int _dim
the number of dimensions TODO: get rid of this -> _shape.size()
Definition MultiIndex.h:104
T value_type
container related types and categories
Definition MultiIndex.h:30
void buildAccumulatedShape()
build accumulated shape vector for flat index calculation
Definition MultiIndex.h:439
void dataStore(std::ostream &stream, void *context)
Implement loadHelper and storeHelper for easier data (de)serialization.
Definition MultiIndex.h:405
unsigned int flatIndex(const size_type &indices) const
compute the flat index for a size_type index
Definition MultiIndex.h:477
unsigned int _nentries
the number of entries TODO: get rid of this -> _data.size()
Definition MultiIndex.h:107
void reshape(const size_type &shape)
change the container shape and reset meta data
Definition MultiIndex.h:454
size_type _stride
stride for each index, e.g. if you know {i, j, k} -> flat_index, {i, j + 1, k} = flat_index + stride[...
Definition MultiIndex.h:110
T & at(unsigned int j)
Definition MultiIndex.h:50
iterator begin()
iterators for begin and end of this container
Definition MultiIndex.h:87
unsigned int dim() const
dimension of the container
Definition MultiIndex.h:62
MultiIndex< T > slice(size_type dimension, size_type index) const
Definition MultiIndex.h:290
const size_type & stride() const
Definition MultiIndex.h:78
MultiIndex(const size_type &shape, const std::vector< T > &data)
construct container of a given shape initialized from a flat data blob
Definition MultiIndex.h:256
MultiIndex(const size_type &shape)
construct zero initialized container of a given shape
Definition MultiIndex.h:249
const T & operator[](unsigned int j) const
Definition MultiIndex.h:49
std::vector< T > getRawData() const
get the raw data vector
Definition MultiIndex.h:68
void dataLoad(std::istream &stream, void *context)
Definition MultiIndex.h:413
const_iterator begin() const
Definition MultiIndex.h:89