MADNESS 0.10.1
mxm.h
Go to the documentation of this file.
1/*
2 This file is part of MADNESS.
3
4 Copyright (C) 2007,2010 Oak Ridge National Laboratory
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 For more information please contact:
21
22 Robert J. Harrison
23 Oak Ridge National Laboratory
24 One Bethel Valley Road
25 P.O. Box 2008, MS-6367
26
27 email: harrisonrj@ornl.gov
28 tel: 865-241-3937
29 fax: 865-572-0680
30
31
32 $Id$
33*/
34
35#ifndef MADNESS_TENSOR_MXM_H__INCLUDED
36#define MADNESS_TENSOR_MXM_H__INCLUDED
37
40
41#define HAVE_FAST_BLAS
42#ifdef HAVE_FAST_BLAS
43//#ifdef HAVE_INTEL_MKL
45#endif
46
47/// \file tensor/mxm.h
48/// \brief Internal use only
49
50// This file is ONLY included into tensor.cc ... separated here just
51// to shrink file size. Don't try to include anywhere else
52
53// Due to both flakey compilers and performance concerns,
54// we use a simple reference implementation of the mxm
55// routines for all except T=double.
56
57
58namespace madness {
59
60 // Start with reference implementations. Then provide optimized implementations, falling back to reference if not available on specific platforms
61
62 /// Matrix \c += Matrix * matrix reference implementation (slow but correct)
63 template <typename T, typename Q, typename S>
64 static inline void mxm_reference(long dimi, long dimj, long dimk,
66 const S* MADNESS_RESTRICT b) {
67 /*
68 c(i,j) = c(i,j) + sum(k) a(i,k)*b(k,j)
69
70 where it is assumed that the last index in each array is has unit
71 stride and the dimensions are as provided.
72 */
73
74 for (long i=0; i<dimi; ++i) {
75 for (long k=0; k<dimk; ++k) {
76 for (long j=0; j<dimj; ++j) {
77 c[i*dimj+j] += a[i*dimk+k]*b[k*dimj+j];
78 }
79 }
80 }
81 }
82
83
84 /// Matrix \c += Matrix transpose * matrix ... reference implementation (slow but correct)
85 template <typename T, typename Q, typename S>
86 static inline
87 void mTxm_reference(long dimi, long dimj, long dimk,
89 const S* MADNESS_RESTRICT b) {
90 /*
91 c(i,j) = c(i,j) + sum(k) a(k,i)*b(k,j)
92
93 where it is assumed that the last index in each array is has unit
94 stride and the dimensions are as provided.
95
96 i loop might be long in anticipated application
97 */
98
99 for (long k=0; k<dimk; ++k) {
100 for (long j=0; j<dimj; ++j) {
101 for (long i=0; i<dimi; ++i) {
102 c[i*dimj+j] += a[k*dimi+i]*b[k*dimj+j];
103 }
104 }
105 }
106 }
107
108 /// Matrix \c += Matrix * matrix transpose ... reference implementation (slow but correct)
109 template <typename T, typename Q, typename S>
110 static inline void mxmT_reference (long dimi, long dimj, long dimk,
112 const S* MADNESS_RESTRICT b) {
113 /*
114 c(i,j) = c(i,j) + sum(k) a(i,k)*b(j,k)
115
116 where it is assumed that the last index in each array is has unit
117 stride and the dimensions are as provided.
118
119 i loop might be long in anticipated application
120 */
121
122 for (long i=0; i<dimi; ++i) {
123 for (long j=0; j<dimj; ++j) {
124 T sum = 0;
125 for (long k=0; k<dimk; ++k) {
126 sum += a[i*dimk+k]*b[j*dimk+k];
127 }
128 c[i*dimj+j] += sum;
129 }
130 }
131 }
132
133 /// Matrix \c += Matrix transpose * matrix transpose reference implementation (slow but correct)
134 template <typename T, typename Q, typename S>
135 static inline void mTxmT_reference(long dimi, long dimj, long dimk,
137 const S* MADNESS_RESTRICT b) {
138 /*
139 c(i,j) = c(i,j) + sum(k) a(k,i)*b(j,k)
140
141 where it is assumed that the last index in each array is has unit
142 stride and the dimensions are as provided.
143 */
144
145 for (long i=0; i<dimi; ++i) {
146 for (long j=0; j<dimj; ++j) {
147 for (long k=0; k<dimk; ++k) {
148 c[i*dimj+j] += a[k*dimi+i]*b[j*dimk+k];
149 }
150 }
151 }
152 }
153
154
155#if defined(HAVE_FAST_BLAS) && !defined(HAVE_INTEL_MKL)
156 // MKL provides support for mixed real/complex operations but most other libraries do not
157
158 /// Matrix += Matrix * matrix ... BLAS/MKL interface version
159
160 /// Does \c C=C+A*B
161 /// \code
162 /// c(i,j) = c(i,j) + sum(k) a(i,k)*b(k,j)
163 /// \endcode
164 template <typename T>
165 void mxm(long dimi, long dimj, long dimk,
166 T* MADNESS_RESTRICT c, const T* a, const T* b) {
167 const T one = 1.0; // alpha in *gemm
168 cblas::gemm(cblas::NoTrans,cblas::NoTrans,dimj,dimi,dimk,one,b,dimj,a,dimk,one,c,dimj);
169 }
170
171 /// Matrix += Matrix transpose * matrix ... MKL interface version
172
173 /// Does \c C=C+AT*B
174 /// \code
175 /// c(i,j) = c(i,j) + sum(k) a(k,i)*b(k,j)
176 /// \endcode
177 template <typename T>
178 void mTxm(long dimi, long dimj, long dimk,
179 T* MADNESS_RESTRICT c, const T* a, const T* b) {
180 const T one = 1.0; // alpha in *gemm
181 cblas::gemm(cblas::NoTrans,cblas::Trans,dimj,dimi,dimk,one,b,dimj,a,dimi,one,c,dimj);
182 }
183
184 /// Matrix += Matrix * matrix transpose ... MKL interface version
185
186 /// Does \c C=C+A*BT
187 /// \code
188 /// c(i,j) = c(i,j) + sum(k) a(i,k)*b(j,k)
189 /// \endcode
190 template <typename T>
191 void mxmT(long dimi, long dimj, long dimk,
192 T* MADNESS_RESTRICT c, const T* a, const T* b) {
193 const T one = 1.0; // alpha in *gemm
194 cblas::gemm(cblas::Trans,cblas::NoTrans,dimj,dimi,dimk,one,b,dimk,a,dimk,one,c,dimj);
195 }
196
197 /// Matrix += Matrix transpose * matrix transpose ... MKL interface version
198
199 /// Does \c C=C+AT*BT
200 /// \code
201 /// c(i,j) = c(i,j) + sum(k) a(k,i)*b(j,k)
202 /// \endcode
203 template <typename T>
204 void mTxmT(long dimi, long dimj, long dimk,
205 T* MADNESS_RESTRICT c, const T* a, const T* b) {
206 const T one = 1.0; // alpha in *gemm
207 cblas::gemm(cblas::Trans,cblas::Trans,dimj,dimi,dimk,one,b,dimk,a,dimi,one,c,dimj);
208 }
209
210#endif
211
212#ifdef HAVE_INTEL_MKL
213 /// Matrix += Matrix * matrix ... MKL interface version
214
215 /// Does \c C=C+A*B
216 /// \code
217 /// c(i,j) = c(i,j) + sum(k) a(i,k)*b(k,j)
218 /// \endcode
219 template <typename aT, typename bT, typename cT>
220 void mxm(long dimi, long dimj, long dimk,
221 cT* MADNESS_RESTRICT c, const aT* a, const bT* b) {
222 const cT one = 1.0; // alpha in *gemm
223 cblas::gemm(cblas::NoTrans,cblas::NoTrans,dimj,dimi,dimk,one,b,dimj,a,dimk,one,c,dimj);
224 }
225
226 /// Matrix += Matrix transpose * matrix ... MKL interface version
227
228 /// Does \c C=C+AT*B
229 /// \code
230 /// c(i,j) = c(i,j) + sum(k) a(k,i)*b(k,j)
231 /// \endcode
232 template <typename aT, typename bT, typename cT>
233 void mTxm(long dimi, long dimj, long dimk,
234 cT* MADNESS_RESTRICT c, const aT* a, const bT* b) {
235 const cT one = 1.0; // alpha in *gemm
236 cblas::gemm(cblas::NoTrans,cblas::Trans,dimj,dimi,dimk,one,b,dimj,a,dimi,one,c,dimj);
237 }
238
239 /// Matrix += Matrix * matrix transpose ... MKL interface version
240
241 /// Does \c C=C+A*BT
242 /// \code
243 /// c(i,j) = c(i,j) + sum(k) a(i,k)*b(j,k)
244 /// \endcode
245 template <typename aT, typename bT, typename cT>
246 void mxmT(long dimi, long dimj, long dimk,
247 cT* MADNESS_RESTRICT c, const aT* a, const bT* b) {
248 const cT one = 1.0; // alpha in *gemm
249 cblas::gemm(cblas::Trans,cblas::NoTrans,dimj,dimi,dimk,one,b,dimk,a,dimk,one,c,dimj);
250 }
251
252 /// Matrix += Matrix transpose * matrix transpose ... MKL interface version
253
254 /// Does \c C=C+AT*BT
255 /// \code
256 /// c(i,j) = c(i,j) + sum(k) a(k,i)*b(j,k)
257 /// \endcode
258 template <typename aT, typename bT, typename cT>
259 void mTxmT(long dimi, long dimj, long dimk,
260 cT* MADNESS_RESTRICT c, const aT* a, const bT* b) {
261 const cT one = 1.0; // alpha in *gemm
262 cblas::gemm(cblas::Trans,cblas::Trans,dimj,dimi,dimk,one,b,dimk,a,dimi,one,c,dimj);
263 }
264
265#else
266
267 // Fall back to reference implementations
268
269 template <typename T, typename Q, typename S>
270 static inline void mxm(long dimi, long dimj, long dimk,
272 const S* MADNESS_RESTRICT b) {
273 mxm_reference(dimi, dimj, dimk, c, a, b);
274 }
275
276 template <typename T, typename Q, typename S>
277 static inline
278 void mTxm(long dimi, long dimj, long dimk,
280 const S* MADNESS_RESTRICT b) {
281 mTxm_reference(dimi, dimj, dimk, c, a, b);
282 }
283
284 template <typename T, typename Q, typename S>
285 static inline void mxmT(long dimi, long dimj, long dimk,
287 const S* MADNESS_RESTRICT b) {
288 mxmT_reference(dimi, dimj, dimk, c, a, b);
289 }
290
291 template <typename T, typename Q, typename S>
292 static inline void mTxmT(long dimi, long dimj, long dimk,
294 const S* MADNESS_RESTRICT b) {
295 mTxmT_reference(dimi, dimj, dimk, c, a, b);
296 }
297
298 // The following are restricted to double only
299
300 /// Matrix transpose * matrix (hand unrolled version)
301
302 template <>
303 inline void mTxm(long dimi, long dimj, long dimk,
304 double* MADNESS_RESTRICT c, const double* MADNESS_RESTRICT a,
305 const double* MADNESS_RESTRICT b) {
306 /*
307 c(i,j) = c(i,j) + sum(k) a(k,i)*b(k,j) <--- NOTE ACCUMULATION INTO C
308
309 where it is assumed that the last index in each array is has unit
310 stride and the dimensions are as provided.
311
312 i loop might be long in anticipated application
313
314 4-way unrolled k loop ... empirically fastest on PIII
315 compared to 2/3 way unrolling (though not by much).
316 */
317
318 long dimk4 = (dimk/4)*4;
319 for (long i=0; i<dimi; ++i,c+=dimj) {
320 const double* ai = a+i;
321 const double* p = b;
322 for (long k=0; k<dimk4; k+=4,ai+=4*dimi,p+=4*dimj) {
323 double ak0i = ai[0 ];
324 double ak1i = ai[dimi];
325 double ak2i = ai[dimi+dimi];
326 double ak3i = ai[dimi+dimi+dimi];
327 const double* bk0 = p;
328 const double* bk1 = p+dimj;
329 const double* bk2 = p+dimj+dimj;
330 const double* bk3 = p+dimj+dimj+dimj;
331 for (long j=0; j<dimj; ++j) {
332 c[j] += ak0i*bk0[j] + ak1i*bk1[j] + ak2i*bk2[j] + ak3i*bk3[j];
333 }
334 }
335 for (long k=dimk4; k<dimk; ++k) {
336 double aki = a[k*dimi+i];
337 const double* bk = b+k*dimj;
338 for (long j=0; j<dimj; ++j) {
339 c[j] += aki*bk[j];
340 }
341 }
342 }
343 }
344
345
346
347 /// Matrix * matrix transpose (hand unrolled version)
348
349 template <>
350 inline void mxmT(long dimi, long dimj, long dimk,
351 double* MADNESS_RESTRICT c,
352 const double* MADNESS_RESTRICT a, const double* MADNESS_RESTRICT b) {
353 /*
354 c(i,j) = c(i,j) + sum(k) a(i,k)*b(j,k)
355
356 where it is assumed that the last index in each array is has unit
357 stride and the dimensions are as provided.
358
359 j loop might be long in anticipated application
360
361 Unrolled i loop. Empirically fastest on PIII compared
362 to unrolling j, or both i&j.
363 */
364
365 long dimi2 = (dimi/2)*2;
366 for (long i=0; i<dimi2; i+=2) {
367 const double* ai0 = a+i*dimk;
368 const double* ai1 = a+i*dimk+dimk;
369 double* MADNESS_RESTRICT ci0 = c+i*dimj;
370 double* MADNESS_RESTRICT ci1 = c+i*dimj+dimj;
371 for (long j=0; j<dimj; ++j) {
372 double sum0 = 0;
373 double sum1 = 0;
374 const double* bj = b + j*dimk;
375 for (long k=0; k<dimk; ++k) {
376 sum0 += ai0[k]*bj[k];
377 sum1 += ai1[k]*bj[k];
378 }
379 ci0[j] += sum0;
380 ci1[j] += sum1;
381 }
382 }
383 for (long i=dimi2; i<dimi; ++i) {
384 const double* ai = a+i*dimk;
385 double* MADNESS_RESTRICT ci = c+i*dimj;
386 for (long j=0; j<dimj; ++j) {
387 double sum = 0;
388 const double* bj = b+j*dimk;
389 for (long k=0; k<dimk; ++k) {
390 sum += ai[k]*bj[k];
391 }
392 ci[j] += sum;
393 }
394 }
395 }
396
397 /// Matrix * matrix (hand unrolled version)
398 template <>
399 inline void mxm(long dimi, long dimj, long dimk,
400 double* MADNESS_RESTRICT c, const double* MADNESS_RESTRICT a, const double* MADNESS_RESTRICT b) {
401 /*
402 c(i,j) = c(i,j) + sum(k) a(i,k)*b(k,j)
403
404 where it is assumed that the last index in each array is has unit
405 stride and the dimensions are as provided.
406
407 4-way unrolled k loop ... empirically fastest on PIII
408 compared to 2/3 way unrolling (though not by much).
409 */
410
411 long dimk4 = (dimk/4)*4;
412 for (long i=0; i<dimi; ++i, c+=dimj,a+=dimk) {
413 const double* p = b;
414 for (long k=0; k<dimk4; k+=4,p+=4*dimj) {
415 double aik0 = a[k ];
416 double aik1 = a[k+1];
417 double aik2 = a[k+2];
418 double aik3 = a[k+3];
419 const double* bk0 = p;
420 const double* bk1 = bk0+dimj;
421 const double* bk2 = bk1+dimj;
422 const double* bk3 = bk2+dimj;
423 for (long j=0; j<dimj; ++j) {
424 c[j] += aik0*bk0[j] + aik1*bk1[j] + aik2*bk2[j] + aik3*bk3[j];
425 }
426 }
427 for (long k=dimk4; k<dimk; ++k) {
428 double aik = a[k];
429 for (long j=0; j<dimj; ++j) {
430 c[j] += aik*b[k*dimj+j];
431 }
432 }
433 }
434 }
435
436 /// Matrix transpose * matrix transpose (hand tiled and unrolled)
437 template <>
438 inline void mTxmT(long dimi, long dimj, long dimk,
439 double* MADNESS_RESTRICT csave, const double* MADNESS_RESTRICT asave, const double* MADNESS_RESTRICT b) {
440 /*
441 c(i,j) = c(i,j) + sum(k) a(k,i)*b(j,k)
442
443 where it is assumed that the last index in each array is has unit
444 stride and the dimensions are as provided.
445
446 Tiled k, copy row of a into temporary, and unroll j once.
447 */
448
449 const int ktile=32;
450 double ai[ktile];
451 long dimj2 = (dimj/2)*2;
452
453 for (long klo=0; klo<dimk; klo+=ktile, asave+=ktile*dimi, b+=ktile) {
454 long khi = klo+ktile;
455 if (khi > dimk) khi = dimk;
456 long nk = khi-klo;
457
458 const double * MADNESS_RESTRICT a = asave;
459 double * MADNESS_RESTRICT c = csave;
460 for (long i=0; i<dimi; ++i,c+=dimj,++a) {
461 const double* q = a;
462 for (long k=0; k<nk; ++k,q+=dimi) ai[k] = *q;
463
464 const double* bj0 = b;
465 for (long j=0; j<dimj2; j+=2,bj0+=2*dimk) {
466 const double* bj1 = bj0+dimk;
467 double sum0 = 0;
468 double sum1 = 0;
469 for (long k=0; k<nk; ++k) {
470 sum0 += ai[k]*bj0[k];
471 sum1 += ai[k]*bj1[k];
472 }
473 c[j ] += sum0;
474 c[j+1] += sum1;
475 }
476
477 for (long j=dimj2; j<dimj; ++j,bj0+=dimk) {
478 double sum = 0;
479 for (long k=0; k<nk; ++k) {
480 sum += ai[k]*bj0[k];
481 }
482 c[j] += sum;
483 }
484 }
485 }
486 }
487
488#endif // HAVE_INTEL_MKL
489
490}
491#endif // MADNESS_TENSOR_MXM_H__INCLUDED
double q(double t)
Definition DKops.h:18
Define BLAS like functions.
char * p(char *buf, const char *name, int k, int initial_level, double thresh, int order)
Definition derivatives.cc:72
#define MADNESS_RESTRICT
Definition mTxmq.h:37
Macros and tools pertaining to the configuration of MADNESS.
void gemm(const CBLAS_TRANSPOSE OpA, const CBLAS_TRANSPOSE OpB, const integer m, const integer n, const integer k, const float alpha, const float *a, const integer lda, const float *b, const integer ldb, const float beta, float *c, const integer ldc)
Multiplies a matrix by a vector.
Definition cblas.h:352
@ NoTrans
Definition cblas_types.h:65
@ Trans
Definition cblas_types.h:66
Namespace for all elements and tools of MADNESS.
Definition DFConvergence.h:9
static void mTxm_reference(long dimi, long dimj, long dimk, T *MADNESS_RESTRICT c, const Q *MADNESS_RESTRICT a, const S *MADNESS_RESTRICT b)
Matrix += Matrix transpose * matrix ... reference implementation (slow but correct)
Definition mxm.h:87
void mTxmT(long dimi, long dimj, long dimk, T *MADNESS_RESTRICT c, const T *a, const T *b)
Matrix += Matrix transpose * matrix transpose ... MKL interface version.
Definition mxm.h:204
void mxm(long dimi, long dimj, long dimk, T *MADNESS_RESTRICT c, const T *a, const T *b)
Matrix += Matrix * matrix ... BLAS/MKL interface version.
Definition mxm.h:165
static void mxm_reference(long dimi, long dimj, long dimk, T *MADNESS_RESTRICT c, const Q *MADNESS_RESTRICT a, const S *MADNESS_RESTRICT b)
Matrix += Matrix * matrix reference implementation (slow but correct)
Definition mxm.h:64
void mTxm(long dimi, long dimj, long dimk, T *MADNESS_RESTRICT c, const T *a, const T *b)
Matrix += Matrix transpose * matrix ... MKL interface version.
Definition mxm.h:178
static void mxmT_reference(long dimi, long dimj, long dimk, T *MADNESS_RESTRICT c, const Q *MADNESS_RESTRICT a, const S *MADNESS_RESTRICT b)
Matrix += Matrix * matrix transpose ... reference implementation (slow but correct)
Definition mxm.h:110
static void mTxmT_reference(long dimi, long dimj, long dimk, T *MADNESS_RESTRICT c, const Q *MADNESS_RESTRICT a, const S *MADNESS_RESTRICT b)
Matrix += Matrix transpose * matrix transpose reference implementation (slow but correct)
Definition mxm.h:135
void mxmT(long dimi, long dimj, long dimk, T *MADNESS_RESTRICT c, const T *a, const T *b)
Matrix += Matrix * matrix transpose ... MKL interface version.
Definition mxm.h:191
static const double b
Definition nonlinschro.cc:119
static const double a
Definition nonlinschro.cc:118
double Q(double a)
Definition relops.cc:20
static const double c
Definition relops.cc:10
static const long k
Definition rk.cc:44
AtomicInt sum
Definition test_atomicint.cc:46
constexpr coord_t one(1.0)