MADNESS 0.10.1
mTxmq.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 Copyright (C) 2026 MADNESS developers
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20*/
21
22#ifndef MADNESS_TENSOR_MTXMQ_H__INCLUDED
23#define MADNESS_TENSOR_MTXMQ_H__INCLUDED
24
28#include <cstddef>
29#include <type_traits>
30#include <complex>
31#include <vector>
32
33#if !defined(MADNESS_RESTRICT)
34# if defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)
35# define MADNESS_RESTRICT __restrict__
36# else
37# define MADNESS_RESTRICT
38# endif
39#endif
40
41namespace madness {
42
43namespace mTxmq_detail {
44 constexpr long MAX_DIMI = 400;
45 constexpr long MAX_DIMJ = 24;
46 constexpr long MAX_DIMK = 24;
47
48 /// Per-thread grow-on-demand scratch for the complex*real decomposition.
49 ///
50 /// Backed by a reclaimable thread_specific pool rather than a large stack
51 /// array. The four real buffers scale as dimi*(dimj+dimk), which for 3-D
52 /// nonstandard-form blocks (dimi = (2k)^2) already exceeds any sane stack
53 /// budget, and an unconditional array sized for the good case enlarges
54 /// every frame -- including the calls that end up on the heap path.
55 /// Buffers grow monotonically to the largest need seen on that thread and
56 /// are never shared across threads; mTxmq_scratch_clear<T>() reclaims them.
57 template <typename T> struct Scratch { std::vector<T> buf; };
58
59 template <typename T>
61 static ::madness::detail::thread_specific<Scratch<T>> pool;
62 return pool;
63 }
64
65 template <typename T>
66 T* scratch(std::size_t need) {
67 Scratch<T>& s = scratch_pool<T>().local();
68 if (s.buf.size() < need) s.buf.resize(need);
69 return s.buf.data();
70 }
71}
72
73/// Free every thread's mTxmq scratch buffers. Call only at a quiescent point.
74template <typename T>
75void mTxmq_scratch_clear() { mTxmq_detail::scratch_pool<T>().clear(); }
76
77/// Initialize libxsmm and pre-dispatch JIT kernels for the small matrix domain
78/// Calling this is optional; initialization will happen lazily on first call if omitted.
79void mTxmq_init();
80
81/// Reference implementation for verification / fallback
82template <typename aT, typename bT, typename cT>
83void mTxmq_reference(long dimi, long dimj, long dimk,
85 const aT* a,
86 const bT* b,
87 long ldb = -1) {
88 if (ldb == -1) ldb = dimj;
89 // b is dimk x ldb; a row shorter than dimj would read past the end of
90 // every row of b and silently return garbage.
91 MADNESS_CHECK(ldb >= dimj);
92 if (dimi <= 0 || dimj <= 0) return;
93 if (dimk <= 0) {
94 for (long i = 0; i < dimi * dimj; ++i) c[i] = cT(0);
95 return;
96 }
97 for (long i = 0; i < dimi; ++i, c += dimj, ++a) {
98 for (long j = 0; j < dimj; ++j) c[j] = cT(0);
99 const aT *aik_ptr = a;
100 for (long k = 0; k < dimk; ++k, aik_ptr += dimi) {
101 aT aki = *aik_ptr;
102 for (long j = 0; j < dimj; ++j) {
103 c[j] += aki * b[k * ldb + j];
104 }
105 }
106 }
107}
108
109/// Base generic template function matching MADNESS signature:
110/// Matrix = Matrix transpose * matrix
111/// \code
112/// c(i,j) = sum(k) a(k,i)*b(k,j) <------ does not accumulate into C
113/// \endcode
114template <typename T>
115void mTxmq(long dimi, long dimj, long dimk,
117 const T* a,
118 const T* b,
119 long ldb = -1);
120
121/// Explicit template specializations for homogeneous types (implemented in mTxmq.cc)
122template <>
123void mTxmq(long dimi, long dimj, long dimk,
124 double* MADNESS_RESTRICT c,
125 const double* a,
126 const double* b,
127 long ldb);
128
129template <>
130void mTxmq(long dimi, long dimj, long dimk,
131 float* MADNESS_RESTRICT c,
132 const float* a,
133 const float* b,
134 long ldb);
135
136template <>
137void mTxmq(long dimi, long dimj, long dimk,
138 std::complex<double>* MADNESS_RESTRICT c,
139 const std::complex<double>* a,
140 const std::complex<double>* b,
141 long ldb);
142
143template <>
144void mTxmq(long dimi, long dimj, long dimk,
145 std::complex<float>* MADNESS_RESTRICT c,
146 const std::complex<float>* a,
147 const std::complex<float>* b,
148 long ldb);
149
150/// Mixed precision: complex matrix multiplied by real matrix
151/// Decomposes into 2 real mTxmq calls over per-thread scratch (see
152/// mTxmq_detail::scratch), so steady-state calls allocate nothing.
153template <typename T>
154inline void mTxmq(long dimi, long dimj, long dimk,
155 std::complex<T>* MADNESS_RESTRICT c,
156 const std::complex<T>* a,
157 const T* b,
158 long ldb = -1) {
159 if (ldb == -1) ldb = dimj;
160 MADNESS_CHECK(ldb >= dimj);
161 if (dimi <= 0 || dimj <= 0) return;
162 if (dimk <= 0) {
164 return;
165 }
166
167 const long c_sz = dimi * dimj;
168 const long a_sz = dimi * dimk;
169
170 T* Ra = mTxmq_detail::scratch<T>(static_cast<std::size_t>(2 * a_sz + 2 * c_sz));
171 T* Ia = Ra + a_sz;
172 T* Rc = Ia + a_sz;
173 T* Ic = Rc + c_sz;
174
175 const T* a_raw = reinterpret_cast<const T*>(a);
176 for (long i = 0; i < a_sz; ++i) {
177 Ra[i] = a_raw[2 * i];
178 Ia[i] = a_raw[2 * i + 1];
179 }
180
181 mTxmq(dimi, dimj, dimk, Rc, Ra, b, ldb);
182 mTxmq(dimi, dimj, dimk, Ic, Ia, b, ldb);
183
184 T* c_raw = reinterpret_cast<T*>(c);
185 for (long i = 0; i < c_sz; ++i) {
186 c_raw[2 * i] = Rc[i];
187 c_raw[2 * i + 1] = Ic[i];
188 }
189}
190
191/// Generic template definitions for any other unspecialized types
192template <typename T>
193inline void mTxmq(long dimi, long dimj, long dimk,
195 const T* a,
196 const T* b,
197 long ldb) {
198 mTxmq_reference(dimi, dimj, dimk, c, a, b, ldb);
199}
200
201template <typename aT, typename bT, typename cT>
202inline void mTxmq(long dimi, long dimj, long dimk,
204 const aT* a,
205 const bT* b,
206 long ldb = -1) {
207 mTxmq_reference(dimi, dimj, dimk, c, a, b, ldb);
208}
209
210/// Print call profile and shape statistics for mTxmq (automatically called at exit)
212
213/// Reset profiling statistics counters
215
216} // namespace madness
217
218#endif // MADNESS_TENSOR_MTXMQ_H__INCLUDED
Definition thread_specific.h:82
#define MADNESS_RESTRICT
Definition mTxmq.h:37
Macros and tools pertaining to the configuration of MADNESS.
Defines madness::MadnessException for exception handling.
#define MADNESS_CHECK(condition)
Check a condition — even in a release build the condition is always evaluated so it can have side eff...
Definition madness_exception.h:182
constexpr long MAX_DIMI
Definition mTxmq.h:44
::madness::detail::thread_specific< Scratch< T > > & scratch_pool()
Definition mTxmq.h:60
T * scratch(std::size_t need)
Definition mTxmq.h:66
constexpr long MAX_DIMJ
Definition mTxmq.h:45
constexpr long MAX_DIMK
Definition mTxmq.h:46
Namespace for all elements and tools of MADNESS.
Definition DFConvergence.h:9
void print_mtxmq_profile()
Print call profile and shape statistics for mTxmq (automatically called at exit)
Definition mTxmq.cc:546
void mTxmq_init()
Definition mTxmq.cc:548
void mTxmq_scratch_clear()
Free every thread's mTxmq scratch buffers. Call only at a quiescent point.
Definition mTxmq.h:75
void mTxmq_reference(long dimi, long dimj, long dimk, cT *MADNESS_RESTRICT c, const aT *a, const bT *b, long ldb=-1)
Reference implementation for verification / fallback.
Definition mTxmq.h:83
void reset_mtxmq_profile()
Reset profiling statistics counters.
Definition mTxmq.cc:547
static XNonlinearSolver< std::vector< Function< T, NDIM > >, T, vector_function_allocator< T, NDIM > > nonlinear_vector_solver(World &world, const long nvec)
Definition nonlinsol.h:371
void mTxmq(long dimi, long dimj, long dimk, double *MADNESS_RESTRICT c, const double *a, const double *b, long ldb)
Explicit template specializations for homogeneous types (implemented in mTxmq.cc)
Definition mTxmq.cc:551
static const double b
Definition nonlinschro.cc:119
static const double a
Definition nonlinschro.cc:118
static const double c
Definition relops.cc:10
static const long k
Definition rk.cc:44
Definition mTxmq.h:57
std::vector< T > buf
Definition mTxmq.h:57
Reclaimable thread-specific storage (a thread_local you can free).