QUDA  v0.5.0
A library for QCD on GPUs
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
quda_matrix.h
Go to the documentation of this file.
1 #ifndef _QUDA_MATRIX_H_
2 #define _QUDA_MATRIX_H_
3 
4 #include <cstdio>
5 #include <cstdlib>
6 #include <iostream>
7 #include <iomanip>
8 #include <cuda.h>
9 
10 namespace quda{
11 
12  // Given a real type T, returns the corresponding complex type
13  template<class T>
14  struct ComplexTypeId;
15 
16  template<>
17  struct ComplexTypeId<float>
18  {
19  typedef float2 Type;
20  };
21 
22  template<>
23  struct ComplexTypeId<double>
24  {
25  typedef double2 Type;
26  };
27 
28  template<class T>
29  struct RealTypeId;
30 
31  template<>
32  struct RealTypeId<float2>
33  {
34  typedef float Type;
35  };
36 
37  template<>
38  struct RealTypeId<double2>
39  {
40  typedef double Type;
41  };
42 
43 
44  template<class T, class U>
46  {
47  typedef T Type;
48  };
49 
50 
51  template<>
52  struct PromoteTypeId<float2, float>
53  {
54  typedef float2 Type;
55  };
56 
57 
58  template<>
59  struct PromoteTypeId<float, float2>
60  {
61  typedef float2 Type;
62  };
63 
64 
65  template<>
66  struct PromoteTypeId<double2, double>
67  {
68  typedef double2 Type;
69  };
70 
71 
72  template<>
73  struct PromoteTypeId<double, double2>
74  {
75  typedef double2 Type;
76  };
77 
78  template<>
79  struct PromoteTypeId<double,int>
80  {
81  typedef double Type;
82  };
83 
84  template<>
85  struct PromoteTypeId<int,double>
86  {
87  typedef double Type;
88  };
89 
90  template<>
91  struct PromoteTypeId<float,int>
92  {
93  typedef float Type;
94  };
95 
96  template<>
97  struct PromoteTypeId<int,float>
98  {
99  typedef float Type;
100  };
101 
102 
103 
104 
105  template<class Cmplx>
106  __device__ __host__ inline
107  Cmplx makeComplex(const typename RealTypeId<Cmplx>::Type & a, const typename RealTypeId<Cmplx>::Type & b)
108  {
109  Cmplx z;
110  z.x = a; z.y = b;
111  return z;
112  }
113 
114 
115  __device__ __host__ inline
116  double2 makeComplex(const double & a, const double & b){
117  return make_double2(a,b);
118  }
119 
120  __device__ __host__ inline
121  float2 makeComplex(const float & a, const float & b){
122  return make_float2(a,b);
123  }
124 
125 
126  template<class Cmplx>
127  __device__ __host__ inline Cmplx & operator+=(Cmplx & a, const Cmplx & b){
128  a.x += b.x;
129  a.y += b.y;
130  return a;
131  }
132 
133 
134  template<class Cmplx>
135  __device__ __host__ inline Cmplx operator+(const Cmplx & a, const Cmplx & b){
136  return makeComplex(a.x+b.x,a.y+b.y);
137  }
138 
139  template<class Cmplx>
140  __device__ __host__ inline Cmplx operator-(const Cmplx & a, const Cmplx & b)
141  {
142  return makeComplex(a.x-b.x,a.y-b.y);
143  }
144 
145  template<class Cmplx>
146  __device__ __host__ inline Cmplx operator*(const Cmplx & a, const typename RealTypeId<Cmplx>::Type & scalar)
147  {
148  return makeComplex(a.x*scalar,a.y*scalar);
149  }
150 
151  template<class Cmplx>
152  __device__ __host__ inline Cmplx operator/(const Cmplx & a, const typename RealTypeId<Cmplx>::Type & scalar)
153  {
154  return makeComplex(a.x/scalar,a.y/scalar);
155  }
156 
157  template<class Cmplx>
158  __device__ __host__ inline Cmplx operator+(const Cmplx & a, const typename RealTypeId<Cmplx>::Type & scalar)
159  {
160  return makeComplex(a.x+scalar,a.y);
161  }
162 
163  template<class Cmplx>
164  __device__ __host__ inline Cmplx operator+(const typename RealTypeId<Cmplx>::Type & scalar, const Cmplx & a)
165  {
166  return makeComplex(a.x+scalar,a.y);
167  }
168 
169  template<class Cmplx>
170  __device__ __host__ inline Cmplx operator-(const Cmplx & a, const typename RealTypeId<Cmplx>::Type & scalar)
171  {
172  return makeComplex(a.x-scalar,a.y);
173  }
174 
175  template<class Cmplx>
176  __device__ __host__ inline Cmplx operator-(const typename RealTypeId<Cmplx>::Type & scalar, const Cmplx & a)
177  {
178  return makeComplex(scalar-a.x,-a.y);
179  }
180 
181 
182  template<class Cmplx>
183  __device__ __host__ inline Cmplx operator*(const typename RealTypeId<Cmplx>::Type & scalar, const Cmplx & b)
184  {
185  return operator*(b,scalar);
186  }
187 
188  template<class Cmplx>
189  __device__ __host__ inline Cmplx operator*(const Cmplx & a, const Cmplx & b)
190  {
191  return makeComplex(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x);
192  }
193 
194  template<class Cmplx>
195  __device__ __host__ inline Cmplx conj(const Cmplx & a)
196  {
197  return makeComplex(a.x,-a.y);
198  }
199 
200  __device__ __host__ inline double conj(const double & a)
201  {
202  return a;
203  }
204 
205  __device__ __host__ inline float conj(const float & a)
206  {
207  return a;
208  }
209 
210 
211 
212  template<class Cmplx>
213  __device__ __host__ inline
214  Cmplx getPreciseInverse(const Cmplx & z){
215  typename RealTypeId<Cmplx>::Type ratio, max, denom;
216  if( fabs(z.x) > fabs(z.y) ){ max = z.x; ratio = z.y/max; }else{ max=z.y; ratio = z.x/max; }
217  denom = max*max*(1 + ratio*ratio);
218  return makeComplex(z.x/denom, -z.y/denom);
219  }
220 
221 
222  // for printing
223  inline std::ostream & operator << (std::ostream & os, const float2 & z){
224  os << "(" << z.x << "," << z.y << ")";
225  return os;
226  }
227 
228  inline std::ostream & operator << (std::ostream & os, const double2 & z){
229  os << "(" << z.x << "," << z.y << ")";
230  return os;
231  }
232 
233 
234 
235  template<class T>
236  struct Zero
237  {
238  //static const T val;
239  __device__ __host__ inline
240  static T val();
241  };
242 
243  template<>
244  __device__ __host__ inline
246  {
247  return make_float2(0.,0.);
248  }
249 
250  template<>
251  __device__ __host__ inline
253  {
254  return make_double2(0.,0.);
255  }
256 
257 
258 
259  template<class T>
260  struct Identity
261  {
262  __device__ __host__ inline
263  static T val();
264  };
265 
266  template<>
267  __device__ __host__ inline
269  return make_float2(1.,0.);
270  }
271 
272  template<>
273  __device__ __host__ inline
275  return make_double2(1.,0.);
276  }
277 
278  template<int N>
279  __device__ __host__ inline
280  int index(int i, int j)
281  {
282  return i*N + j;
283  }
284 
285  template<class T, int N>
286  class Matrix
287  {
288  public:
289  T data[N*N];
290 
291  __device__ __host__ inline T const & operator()(int i, int j) const{
292  return data[index<N>(i,j)];
293  }
294 
295  __device__ __host__ inline T & operator()(int i, int j){
296  return data[index<N>(i,j)];
297  }
298  };
299 
300  template<class T>
301  __device__ __host__ inline T getTrace(const Matrix<T,3>& a)
302  {
303  return a(0,0) + a(1,1) + a(2,2);
304  }
305 
306 
307  template<class T>
308  __device__ __host__ inline T getDeterminant(const Matrix<T,3> & a){
309 
310  T result;
311  result = a(0,0)*(a(1,1)*a(2,2) - a(2,1)*a(1,2))
312  - a(0,1)*(a(1,0)*a(2,2) - a(1,2)*a(2,0))
313  + a(0,2)*(a(1,0)*a(2,1) - a(1,1)*a(2,0));
314 
315  return result;
316  }
317 
318  template<class T, int N>
319  __device__ __host__ inline Matrix<T,N> operator+(const Matrix<T,N> & a, const Matrix<T,N> & b)
320  {
321  Matrix<T,N> result;
322  for(int i=0; i<N*N; i++){
323  result.data[i] = a.data[i] + b.data[i];
324  }
325  return result;
326  }
327 
328 
329  template<class T, int N>
330  __device__ __host__ inline Matrix<T,N> operator+=(Matrix<T,N> & a, const Matrix<T,N> & b)
331  {
332  for(int i=0; i<N*N; i++){
333  a.data[i] += b.data[i];
334  }
335  return a;
336  }
337 
338 
339 
340  template<class T, int N>
341  __device__ __host__ inline Matrix<T,N> operator-(const Matrix<T,N> & a, const Matrix<T,N> & b)
342  {
343  Matrix<T,N> result;
344  for(int i=0; i<N*N; i++){
345  result.data[i] = a.data[i] - b.data[i];
346  }
347  return result;
348  }
349 
350 
351 
352  template<class T, int N, class S>
353  __device__ __host__ inline Matrix<T,N> operator*(const S & scalar, const Matrix<T,N> & a){
354  Matrix<T,N> result;
355  for(int i=0; i<N*N; ++i){
356  result.data[i] = scalar*a.data[i];
357  }
358  return result;
359  }
360 
361 
362  template<class T, int N, class S>
363  __device__ __host__ inline Matrix<T,N> operator*(const Matrix<T,N> & a, const S & scalar){
364  return scalar*a;
365  }
366 
367 
368 
369  template<class T>
370  __device__ __host__ inline
372  {
373  // The compiler has a hard time unrolling nested loops,
374  // so here I do it by hand.
375  // I could do something more sophisticated in the future.
376  Matrix<T,3> result;
377  result(0,0) = a(0,0)*b(0,0) + a(0,1)*b(1,0) + a(0,2)*b(2,0);
378  result(0,1) = a(0,0)*b(0,1) + a(0,1)*b(1,1) + a(0,2)*b(2,1);
379  result(0,2) = a(0,0)*b(0,2) + a(0,1)*b(1,2) + a(0,2)*b(2,2);
380  result(1,0) = a(1,0)*b(0,0) + a(1,1)*b(1,0) + a(1,2)*b(2,0);
381  result(1,1) = a(1,0)*b(0,1) + a(1,1)*b(1,1) + a(1,2)*b(2,1);
382  result(1,2) = a(1,0)*b(0,2) + a(1,1)*b(1,2) + a(1,2)*b(2,2);
383  result(2,0) = a(2,0)*b(0,0) + a(2,1)*b(1,0) + a(2,2)*b(2,0);
384  result(2,1) = a(2,0)*b(0,1) + a(2,1)*b(1,1) + a(2,2)*b(2,1);
385  result(2,2) = a(2,0)*b(0,2) + a(2,1)*b(1,2) + a(2,2)*b(2,2);
386  return result;
387  }
388 
389 
390  // This is so that I can multiply real and complex matrices
391  template<class T, class U>
392  __device__ __host__ inline
394  {
396  result(0,0) = a(0,0)*b(0,0) + a(0,1)*b(1,0) + a(0,2)*b(2,0);
397  result(0,1) = a(0,0)*b(0,1) + a(0,1)*b(1,1) + a(0,2)*b(2,1);
398  result(0,2) = a(0,0)*b(0,2) + a(0,1)*b(1,2) + a(0,2)*b(2,2);
399  result(1,0) = a(1,0)*b(0,0) + a(1,1)*b(1,0) + a(1,2)*b(2,0);
400  result(1,1) = a(1,0)*b(0,1) + a(1,1)*b(1,1) + a(1,2)*b(2,1);
401  result(1,2) = a(1,0)*b(0,2) + a(1,1)*b(1,2) + a(1,2)*b(2,2);
402  result(2,0) = a(2,0)*b(0,0) + a(2,1)*b(1,0) + a(2,2)*b(2,0);
403  result(2,1) = a(2,0)*b(0,1) + a(2,1)*b(1,1) + a(2,2)*b(2,1);
404  result(2,2) = a(2,0)*b(0,2) + a(2,1)*b(1,2) + a(2,2)*b(2,2);
405  return result;
406  }
407 
408 
409 
410  template<class T>
411  __device__ __host__ inline
413  {
414  Matrix<T,2> result;
415  result(0,0) = a(0,0)*b(0,0) + a(0,1)*b(1,0);
416  result(0,1) = a(0,0)*b(0,1) + a(0,1)*b(1,1);
417  result(1,0) = a(1,0)*b(0,0) + a(1,1)*b(1,0);
418  result(1,1) = a(1,0)*b(0,1) + a(1,1)*b(1,1);
419  return result;
420  }
421 
422 
423  template<class T, int N>
424  __device__ __host__ inline
425  Matrix<T,N> conj(const Matrix<T,N> & other){
426  Matrix<T,N> result;
427  for(int i=0; i<N; ++i){
428  for(int j=0; j<N; ++j){
429  result(i,j) = conj(other(j,i));
430  }
431  }
432  return result;
433  }
434 
435 
436  template<class T>
437  __device__ __host__ inline
439  {
440 
441  const T & det = getDeterminant(u);
442  const T & det_inv = getPreciseInverse(det);
443 
444  T temp;
445 
446  temp = u(1,1)*u(2,2) - u(1,2)*u(2,1);
447  (*uinv)(0,0) = (det_inv*temp);
448 
449  temp = u(0,2)*u(2,1) - u(0,1)*u(2,2);
450  (*uinv)(0,1) = (temp*det_inv);
451 
452  temp = u(0,1)*u(1,2) - u(0,2)*u(1,1);
453  (*uinv)(0,2) = (temp*det_inv);
454 
455  temp = u(1,2)*u(2,0) - u(1,0)*u(2,2);
456  (*uinv)(1,0) = (det_inv*temp);
457 
458  temp = u(0,0)*u(2,2) - u(0,2)*u(2,0);
459  (*uinv)(1,1) = (temp*det_inv);
460 
461  temp = u(0,2)*u(1,0) - u(0,0)*u(1,2);
462  (*uinv)(1,2) = (temp*det_inv);
463 
464  temp = u(1,0)*u(2,1) - u(1,1)*u(2,0);
465  (*uinv)(2,0) = (det_inv*temp);
466 
467  temp = u(0,1)*u(2,0) - u(0,0)*u(2,1);
468  (*uinv)(2,1) = (temp*det_inv);
469 
470  temp = u(0,0)*u(1,1) - u(0,1)*u(1,0);
471  (*uinv)(2,2) = (temp*det_inv);
472 
473  return;
474  }
475 
476 
477 
478  template<class T, int N>
479  __device__ __host__ inline
481 
482  for(int i=0; i<N; ++i){
483  (*m)(i,i) = 1;
484  for(int j=i+1; j<N; ++j){
485  (*m)(i,j) = (*m)(j,i) = 0;
486  }
487  }
488  return;
489  }
490 
491 
492  template<int N>
493  __device__ __host__ inline
495 
496  for(int i=0; i<N; ++i){
497  (*m)(i,i) = make_float2(1,0);
498  for(int j=i+1; j<N; ++j){
499  (*m)(i,j) = (*m)(j,i) = make_float2(0.,0.);
500  }
501  }
502  return;
503  }
504 
505 
506  template<int N>
507  __device__ __host__ inline
509 
510  for(int i=0; i<N; ++i){
511  (*m)(i,i) = make_double2(1,0);
512  for(int j=i+1; j<N; ++j){
513  (*m)(i,j) = (*m)(j,i) = make_double2(0.,0.);
514  }
515  }
516  return;
517  }
518 
519 
520  // Need to write more generic code for this!
521  template<class T, int N>
522  __device__ __host__ inline
524 
525  for(int i=0; i<N; ++i){
526  for(int j=0; j<N; ++j){
527  (*m)(i,j) = 0;
528  }
529  }
530  return;
531  }
532 
533 
534  template<int N>
535  __device__ __host__ inline
537 
538  for(int i=0; i<N; ++i){
539  for(int j=0; j<N; ++j){
540  (*m)(i,j) = make_float2(0.,0.);
541  }
542  }
543  return;
544  }
545 
546 
547  template<int N>
548  __device__ __host__ inline
550 
551  for(int i=0; i<N; ++i){
552  for(int j=0; j<N; ++j){
553  (*m)(i,j) = make_double2(0.,0.);
554  }
555  }
556  return;
557  }
558 
559 
560 
561 
562 
563  // Matrix and array are very similar
564  // Maybe I should factor out the similar
565  // code. However, I want to make sure that
566  // the compiler knows to store the
567  // data elements in registers, so I won't do
568  // it right now.
569  template<class T, int N>
570  class Array
571  {
572  private:
573  T data[N];
574 
575  public:
576  // access function
577  __device__ __host__ inline
578  T const & operator[](int i) const{
579  return data[i];
580  }
581 
582  // assignment function
583  __device__ __host__ inline
584  T & operator[](int i){
585  return data[i];
586  }
587  };
588 
589 
590  template<class T, int N>
591  __device__ __host__ inline
592  void copyColumn(const Matrix<T,N>& m, int c, Array<T,N>* a)
593  {
594  for(int i=0; i<N; ++i){
595  (*a)[i] = m(i,c); // c is the column index
596  }
597  return;
598  }
599 
600 
601  template<class T, int N>
602  __device__ __host__ inline
603  void outerProd(const Array<T,N>& a, const Array<T,N> & b, Matrix<T,N>* m){
604  for(int i=0; i<N; ++i){
605  const T conjb_i = conj(b[i]);
606  for(int j=0; j<N; ++j){
607  (*m)(j,i) = a[j]*conjb_i; // we reverse the ordering of indices because it cuts down on the number of function calls
608  }
609  }
610  return;
611  }
612 
613 
614  // Need some print utilities
615  template<class T, int N>
616  std::ostream & operator << (std::ostream & os, const Matrix<T,N> & m){
617  for(int i=0; i<N; ++i){
618  for(int j=0; j<N; ++j){
619  os << m(i,j) << " ";
620  }
621  if(i<N-1) os << std::endl;
622  }
623  return os;
624  }
625 
626 
627  template<class T, int N>
628  std::ostream & operator << (std::ostream & os, const Array<T,N> & a){
629  for(int i=0; i<N; ++i){
630  os << a[i] << " ";
631  }
632  return os;
633  }
634 
635 
636  template<class T>
637  __device__ inline
638  void loadLinkVariableFromArray(const T* const array, int dir, int idx, int stride, Matrix<T,3> *link)
639  {
640  for(int i=0; i<9; ++i){
641  link->data[i] = array[idx + (dir*9 + i)*stride];
642  }
643  return;
644  }
645 
646 
647  __device__ inline
648  void loadLinkVariableFromArray(const float2* const array, int dir, int idx, int stride, Matrix<double2,3> *link)
649  {
650  float2 single_temp;
651  for(int i=0; i<9; ++i){
652  single_temp = array[idx + (dir*9 + i)*stride];
653  link->data[i].x = single_temp.x;
654  link->data[i].y = single_temp.y;
655  }
656  return;
657  }
658 
659 
660 
661 
662 
663  template<class T>
664  __device__ inline
665  void writeLinkVariableToArray(const Matrix<T,3> & link, int dir, int idx, int stride, T* const array)
666  {
667  for(int i=0; i<9; ++i){
668  array[idx + (dir*9 + i)*stride] = link.data[i];
669  }
670  return;
671  }
672 
673 
674 
675 
676  __device__ inline
677  void writeLinkVariableToArray(const Matrix<double2,3> & link, int dir, int idx, int stride, float2* const array)
678  {
679  float2 single_temp;
680 
681  for(int i=0; i<9; ++i){
682  single_temp.x = link.data[i].x;
683  single_temp.y = link.data[i].y;
684  array[idx + (dir*9 + i)*stride] = single_temp;
685  }
686  return;
687  }
688 
689 
690  template<class Cmplx>
691  __device__ __host__ inline
693  {
694 
695  const Cmplx & det = getDeterminant(u);
696  const Cmplx & det_inv = getPreciseInverse(det);
697 
698  Cmplx temp;
699 
700  temp = u(1,1)*u(2,2) - u(1,2)*u(2,1);
701  (*uinv)(0,0) = (det_inv*temp);
702 
703  temp = u(0,2)*u(2,1) - u(0,1)*u(2,2);
704  (*uinv)(0,1) = (temp*det_inv);
705 
706  temp = u(0,1)*u(1,2) - u(0,2)*u(1,1);
707  (*uinv)(0,2) = (temp*det_inv);
708 
709  temp = u(1,2)*u(2,0) - u(1,0)*u(2,2);
710  (*uinv)(1,0) = (det_inv*temp);
711 
712  temp = u(0,0)*u(2,2) - u(0,2)*u(2,0);
713  (*uinv)(1,1) = (temp*det_inv);
714 
715  temp = u(0,2)*u(1,0) - u(0,0)*u(1,2);
716  (*uinv)(1,2) = (temp*det_inv);
717 
718  temp = u(1,0)*u(2,1) - u(1,1)*u(2,0);
719  (*uinv)(2,0) = (det_inv*temp);
720 
721  temp = u(0,1)*u(2,0) - u(0,0)*u(2,1);
722  (*uinv)(2,1) = (temp*det_inv);
723 
724  temp = u(0,0)*u(1,1) - u(0,1)*u(1,0);
725  (*uinv)(2,2) = (temp*det_inv);
726 
727  return;
728  }
729  // template this!
730  inline void copyArrayToLink(Matrix<float2,3>* link, float* array){
731  for(int i=0; i<3; ++i){
732  for(int j=0; j<3; ++j){
733  (*link)(i,j).x = array[(i*3+j)*2];
734  (*link)(i,j).y = array[(i*3+j)*2 + 1];
735  }
736  }
737  return;
738  }
739 
740  template<class Cmplx, class Real>
741  inline void copyArrayToLink(Matrix<Cmplx,3>* link, Real* array){
742  for(int i=0; i<3; ++i){
743  for(int j=0; j<3; ++j){
744  (*link)(i,j).x = array[(i*3+j)*2];
745  (*link)(i,j).y = array[(i*3+j)*2 + 1];
746  }
747  }
748  return;
749  }
750 
751 
752  // and this!
753  inline void copyLinkToArray(float* array, const Matrix<float2,3>& link){
754  for(int i=0; i<3; ++i){
755  for(int j=0; j<3; ++j){
756  array[(i*3+j)*2] = link(i,j).x;
757  array[(i*3+j)*2 + 1] = link(i,j).y;
758  }
759  }
760  return;
761  }
762 
763  // and this!
764  template<class Cmplx, class Real>
765  inline void copyLinkToArray(Real* array, const Matrix<Cmplx,3>& link){
766  for(int i=0; i<3; ++i){
767  for(int j=0; j<3; ++j){
768  array[(i*3+j)*2] = link(i,j).x;
769  array[(i*3+j)*2 + 1] = link(i,j).y;
770  }
771  }
772  return;
773  }
774 
775 
776 
777  // and this!
778  template<class Cmplx>
779  __host__ __device__ inline
780  void printLink(const Matrix<Cmplx,3>& link){
781 #if (!defined(__CUDA_ARCH__) || (__COMPUTE_CAPABILITY__>=200))
782  printf("(%lf, %lf)\t", link(0,0).x, link(0,0).y);
783  printf("(%lf, %lf)\t", link(0,1).x, link(0,1).y);
784  printf("(%lf, %lf)\n", link(0,2).x, link(0,2).y);
785  printf("(%lf, %lf)\t", link(1,0).x, link(1,0).y);
786  printf("(%lf, %lf)\t", link(1,1).x, link(1,1).y);
787  printf("(%lf, %lf)\n", link(1,2).x, link(1,2).y);
788  printf("(%lf, %lf)\t", link(2,0).x, link(2,0).y);
789  printf("(%lf, %lf)\t", link(2,1).x, link(2,1).y);
790  printf("(%lf, %lf)\n", link(2,2).x, link(2,2).y);
791  printf("\n");
792 #endif
793  }
794 
795 } // end namespace quda
796 #endif // _QUDA_MATRIX_H_