File: cmtkVector.h

package info (click to toggle)
cmtk 3.3.1p2%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 10,524 kB
  • sloc: cpp: 87,098; ansic: 23,347; sh: 3,896; xml: 1,551; perl: 707; makefile: 334
file content (440 lines) | stat: -rw-r--r-- 11,025 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
/*
//
//  Copyright 1997-2010 Torsten Rohlfing
//
//  Copyright 2004-2011, 2013 SRI International
//
//  This file is part of the Computational Morphometry Toolkit.
//
//  http://www.nitrc.org/projects/cmtk/
//
//  The Computational Morphometry Toolkit is free software: you can
//  redistribute it and/or modify it under the terms of the GNU General Public
//  License as published by the Free Software Foundation, either version 3 of
//  the License, or (at your option) any later version.
//
//  The Computational Morphometry Toolkit is distributed in the hope that it
//  will be useful, but WITHOUT ANY WARRANTY; without even the implied
//  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along
//  with the Computational Morphometry Toolkit.  If not, see
//  <http://www.gnu.org/licenses/>.
//
//  $Revision: 5436 $
//
//  $LastChangedDate: 2018-12-10 19:01:20 -0800 (Mon, 10 Dec 2018) $
//
//  $LastChangedBy: torstenrohlfing $
//
*/

#ifndef __cmtkVector_h_included_
#define __cmtkVector_h_included_

#include <cmtkconfig.h>

#include <stdio.h>
#include <stdlib.h>
#include <cassert>
#include <math.h>
#include <string.h>

#include <algorithm>

#include <Base/cmtkMathUtil.h>
#include <Base/cmtkTypes.h>
#include <System/cmtkSmartPtr.h>

namespace
cmtk
{

/** \addtogroup Base */
//@{

/** Numerical vector class.
 *\author Torsten Rohlfing
 */
template<class T>
class Vector
{
public:
  /// Vector dimension.
  size_t Dim;

  /// Vector elements.
  T *Elements;

  /// This class.
  typedef Vector<T> Self;

  /// Smart pointer to igsFloatVector.
  typedef SmartPointer<Self> SmartPtr;

  /**\name Constructors */
  //@{
  /// Create constant (zero-)vector.
  Vector ( const size_t dim = 0, const T value = 0 ) 
  {
    Dim = dim;
    if ( Dim ) 
      {
      Elements = Memory::ArrayC::Allocate<T>( Dim );
      FreeElements = true;
      if ( value==0 )
	memset( Elements, 0, Dim * sizeof(T) );
      else
	for ( size_t i=0; i<Dim; ++i )
	  Elements[i]=value;
      } 
    else
      {
      Elements = NULL;
      FreeElements = false;
      }
  }

  /** Create vector from existing array.
   */
  Vector ( const size_t dim, T *const elements, const bool freeElements = true ) 
  {
    Dim = dim;
    Elements = elements;
    FreeElements = freeElements;
  }
  
  /// Create vector from other vector (also subvector).
  Vector ( const Vector& other, const size_t len = 0, const size_t from = 0 ) 
  {
    if ( len )
      Dim = std::min( len, other.Dim - from );
    else
      Dim = other.Dim - from;
    
    Elements = Memory::ArrayC::Allocate<T>( Dim );
    FreeElements = true;
    memcpy( Elements, other.Elements + from, Dim * sizeof(T) );
  }
  //@}

  /// Clone (sub)vector.
  Vector* Clone( const size_t len = 0, const size_t from = 0 ) const
  { 
    return new Vector( *this, len, from ); 
  }
  
  /// Destructor.
  ~Vector () 
  {
    if ( Elements && FreeElements ) 
      {
      Memory::ArrayC::Delete( this->Elements );
      }
  }
  
  /** Set vector dimension.
   * If the current vector dimension is not equal to the requested dimension,
   * the elements array is deleted and a new one is allocated. In any case,
   * there is no guarantee that the data stored in the vector before this call
   * remains unchanged. This is even true for initial elements.
   *\param dim The number of elements to be stored in this vector after
   * returning from this function.
   *\param zero If this parameter is true, all vector elements are set to
   * the zero value in their respective data type.
   *\return A reference to this object after changing the dimension.
   */
  Vector& SetDim ( const size_t dim, const bool zero = true ) 
  {
    if ( Dim != dim ) 
      {
      if ( Elements ) 
	{
	Memory::ArrayC::Delete( this->Elements );
	}

      Dim = dim;
      
      if ( Dim ) 
	{
	Elements = Memory::ArrayC::Allocate<T>( Dim );
	} 
      else
	Elements = NULL;
      }
    
    if ( zero && Dim ) 
      {
      memset( Elements, 0, Dim * sizeof(T) );
      }
    
    return *this;
  }

  /** Adjust vector dimension.
   * Unlike SetDim(), this function preserves the values of elements in the
   * vector if they are still in the valid index range after size adjustment.
   *\param dim The number of elements to be stored in this vector after
   * returning from this function.
   *\param zero If this parameter is true, all new vector elements are set to
   * the zero value in their respective data type.
   *\return A reference to this object after changing the dimension.
   */
  Vector& AdjustDimension( const size_t dim, const bool zero = true ) 
  {
    // If old and new size are the same, there is nothing to do.
    if ( Dim != dim ) 
      {
      T* newElements = Memory::ArrayC::Allocate<T>( dim );
      // copy common elements
      memcpy( newElements, this->Elements, sizeof(T) * std::min( dim, Dim ) );

      // reset new elements if so desired
      if ( zero && (dim > Dim) )
	{
	memset( newElements + Dim, 0, sizeof(T) * (dim-Dim) );
	}

      // new set new array.
      this->Dim = dim;
      if ( this->FreeElements )
	{
	Memory::ArrayC::Delete( this->Elements );
	}
      this->Elements = newElements;
      this->FreeElements = true;
      } 
    
    return *this;
  }
  
  /// Vector assignment.
  Vector& operator = ( const Vector& other ) 
  {
    if ( Dim != other.Dim ) {
    if (Elements) 
      {
      Memory::ArrayC::Delete( this->Elements );
      Elements = NULL;
      }
    
    Dim = other.Dim;
    }
    
    if ( Elements == NULL ) 
      {
      Elements = Memory::ArrayC::Allocate<T>( Dim );
      }
    
    memcpy( Elements, other.Elements, Dim * sizeof(T) );
    return *this; 
  }

  /** Copy another vector to given offset.
   *\param other Vector from which the specified elements are copied.
   *\param offs Destination offset. Copying starts at this position in this
   * instance.
   *\param len Number of elements to be copied. If zero, all elements are 
   * copied until the end of one of the vectors is reached.
   */
  void CopyToOffset( const Vector& other, const size_t offs = 0, size_t len = 0 )
  {
    if ( ! len ) 
      len = std::min( this->Dim - offs, other.Dim );
    for ( size_t idx=0; idx<len; ++idx )
      Elements[offs+idx] = other.Elements[idx];
  }

  /// Test for vector equality.
  int operator== ( const Vector& other ) const 
  {
    if ( Dim != other.Dim )
      return 0;
    
    for ( size_t i=0; i<Dim; ++i )
      if ( Elements[i] != other.Elements[i] )
	return 0;
    
    return 1;
  }
  
  /// Test for vector inequality.
  int operator!= ( const Vector& other ) const 
  {
    return !(*this == other );
  }
  
  /// Calculate Euclid's vector norm.
  T EuclidNorm () const 
  { 
    T Result = 0;
    
#ifndef __SUNPRO_CC
#pragma omp parallel for if (Dim>1e4) reduction(+:Result)
#endif
    for ( int i=0; i<static_cast<int>( this->Dim ); ++i ) 
      {
      const T e = Elements[i];
      Result+=e*e;
      }
    
    return sqrt(Result);
  }

  /// Calculate maximum vector norm.
  T MaxNorm () const 
  { 
    T Result = 0;
    
    for ( size_t i=0; i<Dim; ++i ) 
      {
      Result = std::max<T>( Result, fabs( Elements[i] ) );
      }
    
    return Result;
  }

  /// Set all vector elements to zero.
  void Clear() 
  { 
    memset( Elements, 0, Dim * sizeof( *Elements ) ); 
  }

  /// Set vector from C-style array of arbitrary type (that can be converted to vector's element type).
  template<class T2>
  void SetFromArray( const T2* ptr, const size_t dim = 0 )
  {
    const size_t nCopy = dim ? std::min( dim, this->Dim ) : this->Dim;
    for ( size_t i = 0; i < nCopy; ++i )
      {
      this->Elements[i] = static_cast<T>( ptr[i] );
      }
  }

  /// Set all vector elements to constant value.
  void SetAll( const T value )
  {
#ifndef __SUNPRO_CC
#pragma omp parallel for if (Dim>1e5)
#endif
    for ( int i=0; i < static_cast<int>( this->Dim ); ++i ) 
      this->Elements[i] = value;
  }

  /// Get vector element by coordinate index.
  T& operator [] ( const size_t index ) 
  {
    return this->Elements[index];
  }

  /// Get constant vector element by coordinate index.
  const T& operator [] ( const size_t index ) const 
  {
    return this->Elements[index];
  }

  /// Increment vector by another.
  Vector<T>& operator+= ( const Vector<T>& delta ) 
  {
    assert( Dim == delta.Dim );

#ifndef __SUNPRO_CC
#pragma omp parallel for if (Dim>1e4)
#endif
    for ( int i=0; i<static_cast<int>( this->Dim ); ++i )
      Elements[i] += delta.Elements[i];
    
    return *this;
  }

  /// Decrement vector by another.
  Vector<T>& operator-= ( const Vector<T>& delta ) 
  {
    assert( Dim == delta.Dim );
    
#ifndef __SUNPRO_CC
#pragma omp parallel for if (Dim>1e4)
#endif
    for ( int i=0; i < static_cast<int>( this->Dim ); ++i )
      Elements[i] -= delta.Elements[i];
    
    return *this;
  }

  /// Multiply by a scalar.
  Vector<T>& operator*= ( const T a ) 
  {
#ifndef __SUNPRO_CC
#pragma omp parallel for if (Dim>1e4)
#endif
    for ( int i=0; i<static_cast<int>( this->Dim ); ++i )
      this->Elements[i] *= a;
    
    return *this;
  }

  void Print ( FILE *const fp = NULL, const char* format = " %f" ) const 
  {
    if ( fp ) 
      {
      for ( size_t idx=0; idx < Dim; ++idx )
	fprintf( fp, format, (float) Elements[idx] );
      fputs( "\n", fp );
      } 
    else
      {
      for ( size_t idx=0; idx < Dim; ++idx )
	printf( format, (float) Elements[idx] );
      puts( "" );
      }
  }
  
  /** Sort values in the vector.
   * Using the two parameters, from and len, this function can be used to sort
   * only a subrange of values in this vector. In particular, it can be used to 
   * sort the first len elements if from == 0.
   *\param from Index of first element in the range to sort.
   *\param len Number of elements to be sorted.
   */
  void Sort( const size_t from = 0, const size_t len = 0 ) 
  {
    T *ptr = Elements+from;
    if ( len )
      qsort( ptr, len, sizeof( T ), Vector<T>::Compare );
    else
      qsort( ptr, Dim-from, sizeof( T ), Vector<T>::Compare );
  }
  
private:
  /// Flag for memory deallocation of value array.
  bool FreeElements;

  /// Compare two vector elements; this is needed for sorting.
  static int Compare( const void* a, const void* b ) 
  {
    const T *Ta = (const T *) a;
    const T *Tb = (const T *) b;
    return (*Ta > *Tb) - (*Ta < *Tb);
  }
};

/** Shortcut definition.
 * This typedef defines a name for the frequently used vectors over the 
 * Types::Coordinate type. This is used for all kinds of parameters vectors etc.
 */
typedef Vector<Types::Coordinate> CoordinateVector;

/** Shortcut definition.
 * This typedef defines a name for the frequently used vectors over the 
 * float type.
 */
typedef Vector<float> FloatVector;

//@}

} // namespace cmtk

#include "cmtkVector.txx"

#endif // #ifndef __cmtkVector_h_included_