KrisLibrary  1.0.0
arraynd.h
1 #ifndef ARRAY_ND
2 #define ARRAY_ND
3 
4 #include <KrisLibrary/Logger.h>
5 #include "array2d.h"
6 #include "array3d.h"
7 #include <KrisLibrary/utils/IntTuple.h>
8 #include <vector>
9 #include <assert.h>
10 
11 template <class T> class ArrayND;
12 template <class T> class ArrayNDRef;
13 
16 template <class T>
17 class ArrayND
18 {
19  public:
20  ArrayND();
21  ArrayND(const ArrayND<T>& rhs);
22  ArrayND(const Array2D<T>& rhs);
23  ArrayND(const Array3D<T>& rhs);
24  ArrayND(int dim1);
25  ArrayND(int dim1,int dim2);
26  ArrayND(int dim1,int dim2,int dim3);
27  ArrayND(const std::vector<int>& dims);
28  ArrayND(const IntTuple& dims);
29 
30  void clear();
31  inline size_t numDims() const { return dims.size(); }
32  inline size_t numValues() const { return values.size(); }
33  inline const std::vector<int>& size() const { return dims; }
34 
36  void resize(const std::vector<int>& newdims);
37  inline void resize(const IntTuple& dims) { resize(dims.elements); }
38  inline void resize(int dim1) { resize(IntTuple(dim1)); }
39  inline void resize(int dim1,int dim2) { resize(IntTuple(dim1,dim2)); }
40  inline void resize(int dim1,int dim2,int dim3) { resize(IntTuple(dim1,dim2,dim3)); }
41 
42  inline void set(T val) { std::fill(values.begin(),values.end(),val); }
43 
44  const ArrayND<T>& operator = (const ArrayND<T>& rhs);
45  const ArrayND<T>& operator = (const std::vector<T>& rhs);
46  const ArrayND<T>& operator = (const Array2D<T>& rhs);
47  const ArrayND<T>& operator = (const Array3D<T>& rhs);
48 
49  bool operator == (const ArrayND<T>& rhs) const;
50  ArrayNDRef<T> operator [] (int i);
51  T& operator [] (const std::vector<int>& index);
52  const T& operator [] (const std::vector<int>& index) const;
53  inline T& operator [] (const IntTuple& index) { return operator [](index.elements); }
54  inline const T& operator [] (const IntTuple& index) const { return operator [](index.elements); }
55 
56  void getSubArray(const std::vector<int>& imin,const std::vector<int>& imax,ArrayND<T>& subArray) const;
57  void setSubArray(const std::vector<int>& imin,const std::vector<int>& imax,const ArrayND<T>& subArray);
58  void getSlice(const std::vector<int>& dimIndices,ArrayND<T>& slice) const;
59  void setSlice(const std::vector<int>& dimIndices,const ArrayND<T>& slice);
60 
61  int indexToOffset(const std::vector<int>& index) const;
62  inline void indexToOffset(const IntTuple& index) const { return indexToOffset(index.elements); }
63  inline int incOffset(int offset,int dim) const { return offset+strides[dim]; }
64  inline int decOffset(int offset,int dim) const { return offset-strides[dim]; }
65  std::vector<int> offsetToIndex(int offset) const;
66 
67  struct iterator
68  {
69  iterator& operator ++();
70  iterator& operator --();
71  iterator& operator +=(int skip);
72  iterator& operator -=(int skip);
73  void inc(int dim);
74  void inc(int dim,int count);
75  void dec(int dim);
76  void dec(int dim,int count);
77  inline bool operator == (const iterator& it) const { return it.obj == obj && it.offset == offset; }
78  inline bool operator != (const iterator& it) const { return !operator == (it); }
79  inline bool operator < (const iterator& it) const { return it.obj == obj && it.offset > offset; }
80  inline bool operator > (const iterator& it) const { return it.obj == obj && it.offset < offset; }
81  inline int operator - (const iterator& it) const { assert(it.obj == obj); return offset-it.offset; }
82  inline T& operator * () {
83  assert(offset >= 0 && offset<obj->values.size());
84  return obj->values[offset];
85  }
86  inline T* operator -> () {
87  assert(offset >= 0 && offset<obj->values.size());
88  return &obj->values[offset];
89  }
90 
91  ArrayND<T>* obj;
92  std::vector<int> index;
93  int offset;
94  };
95 
96  iterator begin();
97  iterator begin(const std::vector<int>& index);
98  iterator end();
99 
100  std::vector<int> dims;
101  std::vector<int> strides;
102  std::vector<T> values;
103 };
104 
105 template <class T>
106 class ArrayNDRef
107 {
108  public:
109  ArrayNDRef<T>();
110  ArrayNDRef<T>(const ArrayNDRef<T>& rhs);
111  ArrayNDRef<T>(ArrayND<T>* obj,int offset,int curDim);
112  const ArrayNDRef<T>& operator = (T val);
113  const ArrayNDRef<T>& operator = (const ArrayND<T>& val);
114  operator T ();
115  ArrayNDRef<T> operator [] (int i);
116 
117  ArrayND<T>* obj;
118  int offset;
119  int curDim;
120 };
121 
122 template <class T>
123 std::ostream& operator <<(std::ostream& out,const ArrayND<T>& array)
124 {
125  out<<array.dims.size()<<'\t';
126  for(size_t i=0;i<array.dims.size();i++)
127  out<<array.dims[i]<<" ";
128  out<<std::endl;
129  for(size_t i=0;i<array.values.size();i++)
130  out<<array.values[i]<<std::endl;
131  return out;
132 }
133 
134 template <class T>
135 std::istream& operator >>(std::istream& in,ArrayND<T>& array)
136 {
137  std::vector<int> dims;
138  int n;
139  in >> n;
140  if(!in || n < 0) { in.setstate(std::ios::badbit); return in; }
141  dims.resize(n);
142  for(size_t i=0;i<dims.size();i++) {
143  in >> dims[i];
144  if(dims[i] < 0) { in.setstate(std::ios::badbit); return in; }
145  }
146  array.resize(dims);
147  for(size_t i=0;i<array.values.size();i++)
148  in>>array.values[i];
149  return in;
150 }
151 
152 
153 
154 template <class T>
156 {}
157 
158 template <class T>
160  :dims(rhs.dims),strides(rhs.strides),values(rhs.values)
161 {}
162 
163 
164 template <class T>
166  :dims(2),strides(2),values(rhs.getData(),rhs.getData()+rhs.m*rhs.n)
167 {
168  dims[0] = rhs.m;
169  dims[1] = rhs.n;
170  strides[0] = rhs.n;
171  strides[1] = 1;
172 }
173 
174 template <class T>
176  :dims(3),strides(3),values(rhs.getData(),rhs.getData()+rhs.m*rhs.n*rhs.p)
177 {
178  dims[0] = rhs.m;
179  dims[1] = rhs.n;
180  dims[2] = rhs.p;
181  strides[0] = rhs.n*rhs.p;
182  strides[1] = rhs.p;
183  strides[2] = 1;
184 }
185 
186 template <class T>
187 ArrayND<T>::ArrayND(int dim1)
188 {
189  resize(dim1);
190 }
191 
192 template <class T>
193 ArrayND<T>::ArrayND(int dim1,int dim2)
194 {
195  resize(dim1,dim2);
196 }
197 
198 template <class T>
199 ArrayND<T>::ArrayND(int dim1,int dim2,int dim3)
200 {
201  resize(dim1,dim2,dim3);
202 }
203 
204 template <class T>
205 ArrayND<T>::ArrayND(const std::vector<int>& dims)
206 {
207  resize(dims);
208 }
209 
210 template <class T>
211 ArrayND<T>::ArrayND(const IntTuple& dims)
212 {
213  resize(dims);
214 }
215 
216 template <class T>
217 void ArrayND<T>::clear()
218 {
219  dims.clear();
220  strides.clear();
221  values.clear();
222 }
223 
224 template <class T>
225 void ArrayND<T>::resize(const std::vector<int>& newdims)
226 {
227  if(newdims.empty()) {
228  clear();
229  return;
230  }
231  dims = newdims;
232  int nv = 1;
233  for(size_t i=0;i<newdims.size();i++)
234  nv *= newdims[i];
235  values.resize(nv);
236  strides.resize(dims.size());
237  strides[dims.size()-1] = 1;
238  for(size_t i=dims.size()-1;i>0;i--)
239  strides[i-1] = dims[i]*strides[i];
240 }
241 
242 template <class T>
244 {
245  dims = rhs.dims;
246  strides = rhs.strides;
247  values = rhs.value;
248  return *this;
249 }
250 
251 template <class T>
252 const ArrayND<T>& ArrayND<T>::operator = (const std::vector<T>& rhs)
253 {
254  resize(rhs.size());
255  std::copy(rhs.begin(),rhs.end(),values.begin());
256  return *this;
257 }
258 
259 template <class T>
261 {
262  resize(rhs.m,rhs.n);
263  std::copy(rhs.getData(),rhs.getData()+values.size(),values.begin());
264  return *this;
265 }
266 
267 template <class T>
269 {
270  resize(rhs.m,rhs.n,rhs.p);
271  std::copy(rhs.getData(),rhs.getData()+values.size(),values.begin());
272  return *this;
273 }
274 
275 template <class T>
276 bool ArrayND<T>::operator == (const ArrayND<T>& rhs) const
277 {
278  if(dims != rhs.dims) return false;
279  if(values != rhs.values) return false;
280  return true;
281 }
282 
283 template <class T>
285 {
286  assert(!dims.empty());
287  int offset = i*strides[0];
288  return ArrayNDRef<T>(this,offset,0);
289 }
290 
291 
292 template <class T>
293 T& ArrayND<T>::operator [] (const std::vector<int>& index)
294 {
295  int offset=indexToOffset(index);
296  for(size_t i=0;i<index.size();i++)
297  assert(index[i] >= 0 && index[i] < dims[i]);
298  return values[offset];
299 }
300 
301 template <class T>
302 const T& ArrayND<T>::operator [] (const std::vector<int>& index) const
303 {
304  int offset=indexToOffset(index);
305  for(size_t i=0;i<index.size();i++)
306  assert(index[i] >= 0 && index[i] < dims[i]);
307  return values[offset];
308 }
309 
310 /*
311 template <class T>
312 void ArrayND<T>::getSubArray(const std::vector<int>& imin,const std::vector<int>& imax,ArrayND<T>& subArray);
313 template <class T>
314 void ArrayND<T>::setSubArray(const std::vector<int>& imin,const std::vector<int>& imax,const ArrayND<T>& subArray);
315 template <class T>
316 void ArrayND<T>::getSlice(const std::vector<int>& dimIndices,ArrayND<T>& slice);
317 template <class T>
318 void ArrayND<T>::setSlice(const std::vector<int>& dimIndices,ArrayND<T>& slice);
319 */
320 
321 template <class T>
322 int ArrayND<T>::indexToOffset(const std::vector<int>& index) const
323 {
324  assert(index.size()==strides.size());
325  int offset = 0;
326  for(size_t i=0;i<index.size();i++)
327  offset += index[i]*strides[i];
328  return offset;
329 }
330 
331 template <class T>
332 std::vector<int> ArrayND<T>::offsetToIndex(int offset) const
333 {
334  std::vector<int> index(strides.size());
335  for(size_t i=0;i<index.size();i++) {
336  index[i] = offset/strides[i];
337  offset = offset%strides[i];
338  }
339  return index;
340 }
341 
342 template <class T>
344 {
345  iterator res;
346  res.obj = this;
347  res.offset = 0;
348  res.index.resize(dims.size(),0);
349  return res;
350 }
351 
352 template <class T>
353 typename ArrayND<T>::iterator ArrayND<T>::begin(const std::vector<int>& index)
354 {
355  iterator res;
356  res.obj = this;
357  res.offset = indexToOffset(index);
358  res.index = index;
359  return res;
360 }
361 
362 template <class T>
364 {
365  iterator res;
366  res.obj = this;
367  res.offset = int(values.size());
368  res.index.resize(dims.size(),0);
369  res.index[0] = dims[0];
370  return res;
371 }
372 
373 
374 
375 
376 template <class T>
378 {
379  offset++;
380  for(int i=(int)index.size()-1;i>=0;i--) {
381  index[i]++;
382  if(index[i]==obj->dims[i])
383  index[i] = 0;
384  else {
385  assert(index[i] < obj->dims[i]);
386  break;
387  }
388  }
389  return *this;
390 }
391 
392 template <class T>
394 {
395  offset--;
396  for(int i=(int)index.size()-1;i>=0;i--) {
397  index[i]--;
398  if(index[i] < 0)
399  index[i] = obj->dims[i]-1;
400  else {
401  assert(index[i] >= 0);
402  break;
403  }
404  }
405  return *this;
406 }
407 
408 template <class T>
410 {
411  offset+=skip;
412  for(int i=(int)index.size()-1;i>=0;i--) {
413  index[i]+=skip;
414  if(index[i] < obj->dims[i]) break;
415  assert(obj->dims[i] > 0);
416  skip = index[i]/obj->dims[i];
417  index[i]=index[i]%obj->dims[i];
418  }
419  return *this;
420 }
421 
422 template <class T>
424 {
425  offset-=skip;
426  for(int i=(int)index.size()-1;i>=0;i--) {
427  index[i]-=skip;
428  if(index[i] >=0) break;
429  //TODO: faster version of this
430  assert(obj->dims[i] > 0);
431  skip=0;
432  while(index[i] < 0) {
433  skip++;
434  index[i]+=obj->dims[i];
435  }
436  }
437  return *this;
438 }
439 
440 template <class T>
441 void ArrayND<T>::iterator::inc (int dim)
442 {
443  assert(dim >= 0 && dim < (int)index.size());
444  index[dim]++;
445  offset += obj->strides[dim];
446 }
447 
448 template <class T>
449 void ArrayND<T>::iterator::inc (int dim,int count)
450 {
451  assert(dim >= 0 && dim < (int)index.size());
452  index[dim]+=count;
453  offset += count*obj->strides[dim];
454 }
455 
456 template <class T>
457 void ArrayND<T>::iterator::dec (int dim)
458 {
459  assert(dim >= 0 && dim < (int)index.size());
460  index[dim]--;
461  offset -= obj->strides[dim];
462 }
463 
464 template <class T>
465 void ArrayND<T>::iterator::dec (int dim,int count)
466 {
467  assert(dim >= 0 && dim < (int)index.size());
468  index[dim]-=count;
469  offset -= count*obj->strides[dim];
470 }
471 
472 
473 template <class T>
475  :obj(NULL),offset(0),curDim(0)
476 {}
477 
478 template <class T>
480  :obj(rhs.obj),offset(rhs.offset),curDim(rhs.curDim)
481 {}
482 
483 template <class T>
484 ArrayNDRef<T>::ArrayNDRef(ArrayND<T>* _obj,int _offset,int _curDim)
485  :obj(_obj),offset(_offset),curDim(_curDim)
486 {}
487 
488 template <class T>
490 {
491  assert(curDim+1 == (int)obj->dims.size());
492  obj->values[offset] = val;
493  return *this;
494 }
495 
496 template <class T>
498 {
499  assert(curDim+val.dims.size() == (int)obj->dims.size());
500  LOG4CXX_ERROR(KrisLibrary::logger(),"TODO: copy slices\n");
501  abort();
502  return *this;
503 }
504 
505 template <class T>
507 {
508  assert(curDim+1 == (int)obj->dims.size());
509  return obj->values[offset];
510 }
511 
512 template <class T>
514 {
515  assert(curDim+1 < (int)obj->dims.size());
516  return ArrayNDRef<T>(obj,offset+obj->strides[curDim+1]*i,curDim+1);
517 }
518 
519 
520 
521 
522 
523 #endif // ARRAY_ND
An integer tuple class.
Definition: IntTuple.h:14
void resize(const std::vector< int > &newdims)
note: resize is destructive
Definition: arraynd.h:225
A two-dimensional m x n array.
Definition: array2d.h:30
void copy(const T &a, T *out, int n)
Definition: arrayutils.h:34
Definition: arraynd.h:12
An N-D array class.
Definition: arraynd.h:11
The logging system used in KrisLibrary.
Definition: arraynd.h:67
A three-dimensional m x n x parray.
Definition: array3d.h:31