Subversion Repositories gelsvn

Rev

Rev 382 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
595 jab 1
/* ----------------------------------------------------------------------- *
2
 * This file is part of GEL, http://www.imm.dtu.dk/GEL
3
 * Copyright (C) the authors and DTU Informatics
4
 * For license and list of authors, see ../../doc/intro.pdf
5
 * ----------------------------------------------------------------------- */
6
 
7
 /** @file ArithMatFloat.h
8
  * Abstract matrix class
9
  */
10
 
2 bj 11
#ifndef __CGLA_ARITHMATFLOAT_H__
12
#define __CGLA_ARITHMATFLOAT_H__
13
 
14
#include <vector>
15
#include <iostream>
382 jab 16
#include <numeric>
2 bj 17
 
18
#include "CGLA.h"
19
 
20
 
12 jab 21
namespace CGLA 
22
{
2 bj 23
 
89 jab 24
  /** \brief Basic class template for matrices.
2 bj 25
 
12 jab 26
  In this template a matrix is defined as an array of vectors. This may
27
  not in all cases be the most efficient but it has the advantage that 
28
  it is possible to use the double subscripting notation:
2 bj 29
 
12 jab 30
  T x = m[i][j]
2 bj 31
 
12 jab 32
  This template should be used through inheritance just like the 
33
  vector template */
45 jab 34
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 35
    class ArithMatFloat
36
    { 
37
    public:
2 bj 38
 
12 jab 39
      /// Horizontal vector type
40
      typedef HVT HVectorType;
2 bj 41
 
12 jab 42
      /// Vertical vector type
43
      typedef VVT VVectorType;
2 bj 44
 
12 jab 45
      /// The type of a matrix element
46
      typedef typename HVT::ScalarType ScalarType;
2 bj 47
 
12 jab 48
    protected:
2 bj 49
 
12 jab 50
      /// The actual contents of the matrix.
51
      HVT data[ROWS];
2 bj 52
 
12 jab 53
    protected:
2 bj 54
 
12 jab 55
      /// Construct 0 matrix
56
      ArithMatFloat() 
57
	{
10 jab 58
#ifndef NDEBUG
43 jrf 59
	  std::fill_n(data, ROWS, HVT(CGLA_INIT_VALUE));
10 jab 60
#endif
12 jab 61
	}
2 bj 62
 
12 jab 63
      /// Construct a matrix where all entries are the same.
64
      explicit ArithMatFloat(ScalarType x)
65
	{
43 jrf 66
	  std::fill_n(data, ROWS, HVT(x));
12 jab 67
	}
2 bj 68
 
12 jab 69
      /// Construct a matrix where all rows are the same.
70
      explicit ArithMatFloat(HVT _a)
71
	{
43 jrf 72
	  std::fill_n(data, ROWS, _a);
12 jab 73
	}
2 bj 74
 
12 jab 75
      /// Construct a matrix with two rows.
76
      ArithMatFloat(HVT _a, HVT _b)
77
	{
78
	  assert(ROWS==2);
79
	  data[0] = _a;
80
	  data[1] = _b;
81
	}
2 bj 82
 
12 jab 83
      /// Construct a matrix with three rows.
84
      ArithMatFloat(HVT _a, HVT _b, HVT _c)
85
	{
86
	  assert(ROWS==3);
87
	  data[0] = _a;
88
	  data[1] = _b;
89
	  data[2] = _c;
90
	}
2 bj 91
 
12 jab 92
      /// Construct a matrix with four rows.
93
      ArithMatFloat(HVT _a, HVT _b, HVT _c, HVT _d)
94
	{
95
	  assert(ROWS==4);
96
	  data[0] = _a;
97
	  data[1] = _b;
98
	  data[2] = _c;
99
	  data[3] = _d;
100
	}
2 bj 101
 
12 jab 102
    public:
2 bj 103
 
12 jab 104
      /// Get vertical dimension of matrix 
45 jab 105
      static unsigned int get_v_dim() {return VVT::get_dim();}
2 bj 106
 
12 jab 107
      /// Get horizontal dimension of matrix
45 jab 108
      static unsigned int get_h_dim() {return HVT::get_dim();}
2 bj 109
 
110
 
12 jab 111
      /** Get const pointer to data array.
112
	  This function may be useful when interfacing with some other API 
113
	  such as OpenGL (TM). */
114
      const ScalarType* get() const 
115
	{
116
	  return data[0].get();
117
	}
2 bj 118
 
12 jab 119
      /** Get pointer to data array.
120
	  This function may be useful when interfacing with some other API 
121
	  such as OpenGL (TM). */
122
      ScalarType* get()
123
	{
124
	  return data[0].get();
125
	}
2 bj 126
 
12 jab 127
      //----------------------------------------------------------------------
128
      // index operators
129
      //----------------------------------------------------------------------
2 bj 130
 
12 jab 131
      /// Const index operator. Returns i'th row of matrix.
45 jab 132
      const HVT& operator [] ( unsigned int i ) const
12 jab 133
	{
134
	  assert(i<ROWS);
135
	  return data[i];
136
	}
2 bj 137
 
12 jab 138
      /// Non-const index operator. Returns i'th row of matrix.
45 jab 139
      HVT& operator [] ( unsigned int i ) 
12 jab 140
	{
141
	  assert(i<ROWS);
142
	  return data[i];
143
	}
2 bj 144
 
12 jab 145
      //----------------------------------------------------------------------
2 bj 146
 
12 jab 147
      /// Equality operator. 
148
      bool operator==(const MT& v) const 
149
	{
43 jrf 150
	  return std::inner_product(data, &data[ROWS], &v[0], true,
151
				    std::logical_and<bool>(), std::equal_to<HVT>());
12 jab 152
	}
2 bj 153
 
12 jab 154
      /// Inequality operator.
155
      bool operator!=(const MT& v) const 
156
	{
157
	  return !(*this==v);
158
	}
2 bj 159
 
12 jab 160
      //----------------------------------------------------------------------
2 bj 161
 
12 jab 162
      /// Multiply scalar onto matrix. All entries are multiplied by scalar.
163
      const MT operator * (ScalarType k) const
164
	{
165
	  MT v_new;
595 jab 166
	  std::transform(data, &data[ROWS], &v_new[0], std::bind2nd(std::multiplies<HVT>(), HVT(k)));
12 jab 167
	  return v_new;
168
	}
2 bj 169
 
12 jab 170
      /// Divide all entries in matrix by scalar.
171
      const MT operator / (ScalarType k) const
172
	{
173
	  MT v_new;
595 jab 174
	  std::transform(data, &data[ROWS], &v_new[0], std::bind2nd(std::divides<HVT>(), HVT(k)));
12 jab 175
	  return v_new;      
176
	}
2 bj 177
 
12 jab 178
      /// Assignment multiplication of matrix by scalar.
179
      const MT& operator *=(ScalarType k) 
180
	{
595 jab 181
	  std::transform(data, &data[ROWS], data, std::bind2nd(std::multiplies<HVT>(), HVT(k)));
12 jab 182
	  return static_cast<const MT&>(*this);
183
	}
2 bj 184
 
12 jab 185
      /// Assignment division of matrix by scalar.
186
      const MT& operator /=(ScalarType k) 
187
	{ 
595 jab 188
	  std::transform(data, &data[ROWS], data, std::bind2nd(std::divides<HVT>(), HVT(k)));
12 jab 189
	  return static_cast<const MT&>(*this);
190
	}
2 bj 191
 
12 jab 192
      //----------------------------------------------------------------------
2 bj 193
 
12 jab 194
      /// Add two matrices. 
195
      const MT operator + (const MT& m1) const
196
	{
197
	  MT v_new;
43 jrf 198
	  std::transform(data, &data[ROWS], &m1[0], &v_new[0], std::plus<HVT>());
12 jab 199
	  return v_new;
200
	}
2 bj 201
 
12 jab 202
      /// Subtract two matrices.
203
      const MT operator - (const MT& m1) const
2 bj 204
	{
12 jab 205
	  MT v_new;
43 jrf 206
	  std::transform(data, &data[ROWS], &m1[0], &v_new[0], std::minus<HVT>());
12 jab 207
	  return v_new;
2 bj 208
	}
209
 
12 jab 210
      /// Assigment addition of matrices.
211
      const MT& operator +=(const MT& v) 
2 bj 212
	{
43 jrf 213
	  std::transform(data, &data[ROWS], &v[0], data, std::plus<HVT>());
12 jab 214
	  return static_cast<const MT&>(*this);
2 bj 215
	}
216
 
12 jab 217
      /// Assigment subtraction of matrices.
218
      const MT& operator -=(const MT& v) 
2 bj 219
	{
43 jrf 220
	  std::transform(data, &data[ROWS], &v[0], data, std::minus<HVT>());
12 jab 221
	  return static_cast<const MT&>(*this);
2 bj 222
	}
223
 
12 jab 224
      //----------------------------------------------------------------------
225
 
226
      /// Negate matrix.
227
      const MT operator - () const
2 bj 228
	{
12 jab 229
	  MT v_new;
43 jrf 230
	  std::transform(data, &data[ROWS], &v_new[0], std::negate<HVT>());
12 jab 231
	  return v_new;
2 bj 232
	}
12 jab 233
    };
2 bj 234
 
12 jab 235
  /// Multiply scalar onto matrix
45 jab 236
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 237
    inline const MT operator * (double k, const ArithMatFloat<VVT,HVT,MT,ROWS>& v) 
238
    {
239
      return v * k;
240
    }
241
 
242
  /// Multiply scalar onto matrix
45 jab 243
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 244
    inline const MT operator * (float k, const ArithMatFloat<VVT,HVT,MT,ROWS>& v) 
245
    {
246
      return v * k;
247
    }
248
 
249
  /// Multiply scalar onto matrix
45 jab 250
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 251
    inline const MT operator * (int k, const ArithMatFloat<VVT,HVT,MT,ROWS>& v) 
252
    {
253
      return v * k;
254
    }
255
 
256
  /// Multiply vector onto matrix 
45 jab 257
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 258
    inline VVT operator*(const ArithMatFloat<VVT,HVT,MT,ROWS>& m,const HVT& v) 
259
    {
260
      VVT v2;
45 jab 261
      for(unsigned int i=0;i<ROWS;i++) v2[i] = dot(m[i], v);
12 jab 262
      return v2;
263
    }
264
 
265
 
2 bj 266
#ifndef WIN32
12 jab 267
  /** Multiply two arbitrary matrices. 
268
      In principle, this function could return a matrix, but in general
269
      the new matrix will be of a type that is different from either of
270
      the two matrices that are multiplied together. We do not want to 
271
      return an ArithMatFloat - so it seems best to let the return value be
272
      a reference arg.
2 bj 273
 
12 jab 274
      This template can only be instantiated if the dimensions of the
275
      matrices match -- i.e. if the multiplication can actually be
276
      carried out. This is more type safe than the win32 version below.
277
  */
2 bj 278
 
12 jab 279
  template <class VVT, class HVT, 
280
    class HV1T, class VV2T,
281
    class MT1, class MT2, class MT,
45 jab 282
    unsigned int ROWS1, unsigned int ROWS2>
12 jab 283
    inline void mul(const ArithMatFloat<VVT,HV1T,MT1,ROWS1>& m1,
284
		    const ArithMatFloat<VV2T,HVT,MT2,ROWS2>& m2,
285
		    ArithMatFloat<VVT,HVT,MT,ROWS1>& m)
286
    {
45 jab 287
      unsigned int cols = ArithMatFloat<VVT,HVT,MT,ROWS1>::get_h_dim();
288
      for(unsigned int i=0;i<ROWS1;i++)
289
	for(unsigned int j=0;j<cols;j++)
12 jab 290
	  {
291
	    m[i][j] = 0;
45 jab 292
	    for(unsigned int k=0;k<ROWS2;k++)
12 jab 293
	      m[i][j] += m1[i][k] * m2[k][j]; 
294
	  }
295
    }
2 bj 296
 
297
 
12 jab 298
  /** Transpose. See the discussion on mul if you are curious as to why
299
      I don't simply return the transpose. */
45 jab 300
  template <class VVT, class HVT, class M1T, class M2T, unsigned int ROWS, unsigned int COLS>
12 jab 301
    inline void transpose(const ArithMatFloat<VVT,HVT,M1T,ROWS>& m,
302
			  ArithMatFloat<HVT,VVT,M2T,COLS>& m_new)
303
    {
45 jab 304
      for(unsigned int i=0;i<M2T::get_v_dim();++i)
305
	for(unsigned int j=0;j<M2T::get_h_dim();++j)
12 jab 306
	  m_new[i][j] = m[j][i];
307
    }
2 bj 308
 
309
#else
310
 
12 jab 311
  //----------------- win32 -------------------------------
312
  // Visual studio is not good at deducing the args. to these template functions.
313
  // This means that you can call the two functions below with 
314
  // matrices of wrong dimension.
2 bj 315
 
12 jab 316
  template <class M1, class M2, class M>
317
    inline void mul(const M1& m1, const M2& m2, M& m)
318
    {
45 jab 319
      unsigned int cols = M::get_h_dim();
320
      unsigned int rows1 = M1::get_v_dim();
321
      unsigned int rows2 = M2::get_v_dim();
2 bj 322
 
45 jab 323
      for(unsigned int i=0;i<rows1;++i)
324
	for(unsigned int j=0;j<cols;++j)
12 jab 325
	  {
326
	    m[i][j] = 0;
45 jab 327
	    for(unsigned int k=0;k<rows2;++k)
12 jab 328
	      m[i][j] += m1[i][k] * m2[k][j];
329
	  }
330
    }
2 bj 331
 
332
 
12 jab 333
  /** Transpose. See the discussion on mul if you are curious as to why
334
      I don't simply return the transpose. */
335
  template <class M1, class M2>
336
    inline void transpose(const M1& m1, M2& m2)
337
    {
45 jab 338
      for(unsigned int i=0;i<M2::get_v_dim();++i)
339
	for(unsigned int j=0;j<M2::get_h_dim();++j)
12 jab 340
	  m2[i][j] = m1[j][i];
341
    }
2 bj 342
 
343
#endif
344
 
12 jab 345
  /** Compute the outer product of a and b: a * transpose(b). This is 
346
      a matrix with a::rows and b::columns. */
45 jab 347
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 348
    void outer_product(const VVT& a, const HVT& b, 
349
		       ArithMatFloat<VVT,HVT,MT,ROWS>& m)
350
    {
45 jab 351
      unsigned int R = VVT::get_dim();
352
      unsigned int C = HVT::get_dim();
353
      for(unsigned int i=0;i<R;++i)
354
	for(unsigned int j=0;j<C;++j)
12 jab 355
	  {
356
	    m[i][j] = a[i] * b[j];
357
	  }
358
    }
2 bj 359
 
46 jrf 360
  /** Compute the outer product of a and b using an arbitrary 
361
      binary operation: op(a, transpose(b)). This is 
362
      a matrix with a::rows and b::columns. */
363
  template <class VVT, class HVT, class MT, int ROWS, class BinOp>
364
    void outer_product(const VVT& a, const HVT& b, 
365
		       ArithMatFloat<VVT,HVT,MT,ROWS>& m, BinOp op)
366
    {
367
      int R = VVT::get_dim();
368
      int C = HVT::get_dim();
369
      for(int i=0;i<R;++i)
370
	for(int j=0;j<C;++j)
371
	  {
372
	    m[i][j] = op(a[i], b[j]);
373
	  }
374
    }
375
 
12 jab 376
  /** Copy a matrix to another matrix, cell by cell.
377
      This conversion that takes a const matrix as first argument
378
      (source) and a non-const matrix as second argument
379
      (destination). The contents of the first matrix is simply copied
380
      to the second matrix. 
2 bj 381
 
12 jab 382
      However, if the first matrix is	larger than the second,
383
      the cells outside the range of the destination are simply not
384
      copied. If the destination is larger, the cells outside the 
385
      range of the source matrix are not touched.
2 bj 386
 
12 jab 387
      An obvious use of this function is to copy a 3x3 rotation matrix
388
      into a 4x4 transformation matrix.
389
  */
2 bj 390
 
12 jab 391
  template <class M1, class M2>
392
    void copy_matrix(const M1& inmat, M2& outmat)
393
    {
45 jab 394
      const unsigned int R = s_min(inmat.get_v_dim(), outmat.get_v_dim());
395
      const unsigned int C = s_min(inmat.get_h_dim(), outmat.get_h_dim());
396
      for(unsigned int i=0;i<R;++i)
397
	for(unsigned int j=0;j<C;++j)
12 jab 398
	  outmat[i][j] = inmat[i][j];
399
    }
2 bj 400
 
12 jab 401
  /** Put to operator */
45 jab 402
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 403
    inline std::ostream& 
404
    operator<<(std::ostream&os, const ArithMatFloat<VVT,HVT,MT,ROWS>& m)
405
    {
406
      os << "[\n";
45 jab 407
      for(unsigned int i=0;i<ROWS;i++) os << "  " << m[i] << "\n";
12 jab 408
      os << "]\n";
409
      return os;
410
    }
2 bj 411
 
12 jab 412
  /** Get from operator */
45 jab 413
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 414
    inline std::istream& operator>>(std::istream&is, 
415
				    const ArithMatFloat<VVT,HVT,MT,ROWS>& m)
416
    {
45 jab 417
      for(unsigned int i=0;i<ROWS;i++) is>>m[i];
12 jab 418
      return is;
419
    }
2 bj 420
}
421
#endif