iterative-solver 0.0
 
Loading...
Searching...
No Matches
gemm.h
1#ifndef LINEARALGEBRA_SRC_MOLPRO_LINALG_ARRAY_UTIL_GEMM_H
2#define LINEARALGEBRA_SRC_MOLPRO_LINALG_ARRAY_UTIL_GEMM_H
3#ifdef HAVE_MPI_H
4#include <mpi.h>
5#endif
6#include "BufferManager.h"
7#include "gather_all.h"
8#include <algorithm>
9#include <functional>
10#include <iterator>
11#include <future>
12#include <iostream>
13#include <molpro/Options.h>
14#include <molpro/Profiler.h>
15#include <molpro/cblas.h>
16#include <molpro/linalg/array/DistrArrayDisk.h>
17#include <molpro/linalg/array/type_traits.h>
18#include <molpro/linalg/itsolv/subspace/Matrix.h>
19#include <molpro/linalg/itsolv/wrap.h>
20#include <molpro/linalg/itsolv/wrap_util.h>
21#include <molpro/linalg/options.h>
22#include <numeric>
23#include <stdexcept>
24#include <string>
25#include <utility>
26#include <vector>
27
29
33
35
37template <class A>
38inline constexpr bool is_disk_array_v = std::is_base_of_v<DistrArrayDisk, std::decay_t<A>>;
39
41template <class A>
42auto local_range(const A& a) {
43 return a.distribution().range(BufferManager<std::decay_t<A>>::rank_in(a));
44}
45
46// Building blocks for the buffered operations
47
50template <class T>
51size_t constant_stride(const std::vector<T*>& p, size_t n) {
52 if (p.size() < 2)
53 return n;
54 const auto stride = p[1] - p[0];
55 for (size_t j = 1; j + 1 < p.size(); ++j)
56 if (p[j + 1] - p[j] != stride)
57 return 0;
58 return stride >= std::ptrdiff_t(n) and stride > 0 ? size_t(stride) : 0;
59}
60
62template <class T>
63std::vector<T*> offset_pointers(const std::vector<T*>& bases, size_t lo, size_t g) {
64 auto p = bases;
65 for (auto& el : p)
66 el += g - lo;
67 return p;
68}
69
71template <class T, class A>
72std::vector<T*> local_buffer_pointers(const std::vector<std::reference_wrapper<A>>& aa) {
73 std::vector<T*> p;
74 for (const auto& a : aa)
75 p.push_back(const_cast<T*>(a.get().local_buffer()->data()));
76 return p;
77}
78
80template <class A, class Range>
81void check_local_ranges(const std::vector<std::reference_wrapper<A>>& aa, const Range& range, const std::string& name) {
82 for (const auto& a : aa)
83 if (local_range(a.get()) != range)
84 throw std::out_of_range(name + ": the distributed arrays are distributed differently");
85}
86
92template <class T, class R, class A>
93std::vector<T*> contiguous_pointers(const std::vector<std::reference_wrapper<R>>& rr, const A& q,
94 const std::string& name) {
95 const auto lo = local_range(q).first;
96 std::vector<T*> p;
97 for (const auto& r : rr) {
98 if (size_t(std::size(r.get())) != size_t(q.size()))
99 throw std::out_of_range(name + ": contiguous and distributed arrays are of different size: " +
100 std::to_string(std::size(r.get())) + " " + std::to_string(q.size()));
101 p.push_back(const_cast<T*>(std::data(r.get())) + lo);
102 }
103 return p;
104}
105
116template <class T>
117void gemm_chunk(gemm_type type, size_t n, const T* x, size_t ldx, size_t nx, T* alphadata, const std::vector<T*>& y) {
118 const size_t ny = y.size();
119 if (n == 0 or nx == 0 or ny == 0)
120 return;
121 const auto y_stride = constant_stride(y, n);
122 if (y_stride == 0 and ny > 1) {
123 // yy are not evenly spaced: pack them into one matrix, so that the product is a single dgemm rather than one dgemv
124 // for each of yy
125 thread_local std::vector<T> packed;
126 packed.resize(n * ny);
127 std::vector<T*> p(ny);
128 for (size_t k = 0; k < ny; ++k) {
129 p[k] = packed.data() + k * n;
130 std::copy_n(y[k], n, p[k]);
131 }
132 gemm_chunk(type, n, x, ldx, nx, alphadata, p);
133 if (type == gemm_type::outer)
134 for (size_t k = 0; k < ny; ++k)
135 std::copy_n(p[k], n, y[k]);
136 return;
137 }
138 const auto dims = std::to_string(nx) + ", " + std::to_string(ny) + ", " + std::to_string(n);
139 if (type == gemm_type::outer) {
140 if (y_stride > 0) {
141 auto prof = molpro::Profiler::single()->push("gemm_outer: cblas_dgemm dimensions " + dims);
142 cblas_dgemm(CblasColMajor, CblasNoTrans, CblasTrans, n, ny, nx, 1, x, ldx, alphadata, ny, 1, y[0], y_stride);
143 } else {
144 auto prof = molpro::Profiler::single()->push("gemm_outer: cblas_dgemv dimensions " + dims);
145 for (size_t k = 0; k < ny; ++k)
146 cblas_dgemv(CblasColMajor, CblasNoTrans, n, nx, 1, x, ldx, alphadata + k, ny, 1, y[k], 1);
147 }
148 } else {
149 if (y_stride > 0) {
150 auto prof = molpro::Profiler::single()->push("gemm_inner: cblas_dgemm dimensions " + dims);
151 cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, nx, ny, n, 1, x, ldx, y[0], y_stride, 1, alphadata, nx);
152 } else {
153 auto prof = molpro::Profiler::single()->push("gemm_inner: cblas_dgemv dimensions " + dims);
154 for (size_t k = 0; k < ny; ++k)
155 cblas_dgemv(CblasColMajor, CblasTrans, n, nx, 1, x, ldx, y[k], 1, 1, alphadata + k * nx, 1);
156 }
157 }
158}
159
169template <class AD, class T = typename AD::value_type>
170void gemm_buffered(T* alphadata, const CVecRef<AD>& xx,
171 const std::type_identity_t<std::function<std::vector<T*>(size_t g, size_t n)>>& y_pointers,
172 const std::function<void(size_t g, size_t n)>& y_done, gemm_type type) {
173 auto prof = molpro::Profiler::single()->push("gemm_buffered");
174 if (xx.empty())
175 return;
176 const auto [lo, hi] = local_range(xx.front().get());
177 if (hi <= lo)
178 return;
180 auto number_of_buffers = options->parameter("GEMM_BUFFERS", 2);
181 // BufferManager's buffer_size parameter is the size of ONE chunk (it already multiplies
182 // by number_of_buffers internally to size the total pool) -- do not multiply by
183 // number_of_buffers again here, or each chunk silently grows number_of_buffers-fold.
184 const int buf_size = std::min(int(hi - lo), options->parameter("GEMM_PAGESIZE", 8192));
185 molpro::Profiler::single()->start("gemm: buffer setup");
186 BufferManager buffer(xx, buf_size, number_of_buffers);
187 molpro::Profiler::single()->stop("gemm: buffer setup");
188 for (auto buffer_iterator = buffer.begin(); buffer_iterator != buffer.end(); ++buffer_iterator) {
189 const size_t g = lo + buffer.buffer_offset();
190 const size_t n = buffer.buffer_size();
191 gemm_chunk(type, n, buffer_iterator->data(), buffer.buffer_stride(), xx.size(), alphadata, y_pointers(g, n));
192 if (y_done)
193 y_done(g, n);
194 }
195}
196
202template <class AD, class T = typename AD::value_type>
204gemm_inner_buffered(size_t ny, const CVecRef<AD>& xx,
205 const std::type_identity_t<std::function<std::vector<T*>(size_t g, size_t n)>>& y_pointers,
206 const std::function<void(size_t g, size_t n)>& y_done = {}) {
207 auto prof = molpro::Profiler::single()->push("gemm_inner (buffered)");
208 auto alphas = Matrix<T>({ny, xx.size()});
209 alphas.fill(0);
210 if (ny == 0 or xx.empty())
211 return alphas;
212 const auto [lo, hi] = local_range(xx.front().get());
213 prof += xx.size() * ny * (hi - lo) * 2;
214 auto alphadata = const_cast<T*>(alphas.data().data());
215 gemm_buffered(alphadata, xx, y_pointers, y_done, gemm_type::inner);
216#ifdef HAVE_MPI_H
217 // reduce over the arrays' own communicator, which need not be the global one
218 MPI_Allreduce(MPI_IN_PLACE, alphadata, alphas.size(), MPI_DOUBLE, MPI_SUM, xx.front().get().communicator());
219#endif
220 return alphas;
221}
222
224template <class T>
225void check_gemm_outer_dimensions(const Matrix<T>& alphas, size_t nx, size_t ny, const std::string& name) {
226 if (alphas.rows() != nx)
227 throw std::out_of_range(name + ": dimensions of xx and alphas are different: " + std::to_string(alphas.rows()) +
228 " " + std::to_string(nx));
229 if (alphas.cols() != ny)
230 throw std::out_of_range(name + ": dimensions of yy and alphas are different: " + std::to_string(alphas.cols()) +
231 " " + std::to_string(ny));
232}
233
235template <class T>
237 Matrix<T> result({m.cols(), m.rows()});
239 return result;
240}
241
250template <class AD, class T = typename AD::value_type>
251void gemm_outer_to_distr(const Matrix<T>& alphas, const std::vector<T*>& x_bases, const VecRef<AD>& yy) {
252 if (x_bases.empty() or yy.empty())
253 return;
254 check_gemm_outer_dimensions(alphas, x_bases.size(), yy.size(), "gemm_outer_to_distr");
255 auto prof = molpro::Profiler::single()->push("gemm_outer_to_distr");
256 const auto [lo, hi] = local_range(yy.front().get());
257 check_local_ranges(yy, std::make_pair(lo, hi), "gemm_outer_to_distr");
258 prof += x_bases.size() * yy.size() * (hi - lo) * 2;
259 const auto nx = x_bases.size();
260 const auto ny = yy.size();
261 const bool yy_on_disk = yy.front().get().disk_page_size() > 0;
262 const size_t page = yy_on_disk ? yy.front().get().disk_page_size()
263 : size_t(molpro::linalg::options()->parameter("GEMM_PAGESIZE", 8192));
264 std::vector<T*> y_bases;
265 if (not yy_on_disk)
266 y_bases = local_buffer_pointers<T>(yy);
267 std::vector<T> y_page, x_page;
268 for (size_t g = lo; g < hi; g += page) {
269 const size_t n = std::min(page, hi - g);
270 std::vector<T*> y;
271 if (yy_on_disk) {
272 y_page.resize(n * ny);
273 for (size_t k = 0; k < ny; ++k) {
274 y.push_back(y_page.data() + k * n);
275 yy[k].get().get(g, g + n, y.back());
276 }
277 } else
278 y = offset_pointers(y_bases, lo, g);
279 const auto x = offset_pointers(x_bases, lo, g);
280 auto x_stride = constant_stride(x, n);
281 const T* x_data = x[0];
282 if (x_stride == 0) {
283 x_page.resize(n * nx);
284 for (size_t i = 0; i < nx; ++i)
285 std::copy_n(x[i], n, x_page.data() + i * n);
286 x_data = x_page.data();
287 x_stride = n;
288 }
289 gemm_chunk(gemm_type::outer, n, x_data, x_stride, nx, const_cast<T*>(alphas.data().data()), y);
290 if (yy_on_disk)
291 for (size_t k = 0; k < ny; ++k)
292 yy[k].get().put(g, g + n, y[k]);
293 }
294}
295
296// Buffered: the disk arrays xx are read in chunks through a BufferManager
297
299template <class AL, class T = typename array::mapped_or_value_type_t<AL>>
301 DistrChunks(const VecRef<AL>& yy, gemm_type type) : yy(yy), type(type) {
302 if (not yy.empty() and yy.front().get().disk_page_size() == 0) {
303 lo = local_range(yy.front().get()).first;
304 bases = local_buffer_pointers<T>(yy);
305 }
306 }
307 std::vector<T*> pointers(size_t g, size_t n) {
308 if (not bases.empty())
309 return offset_pointers(bases, lo, g);
310 // on disk: each chunk is read into memory, and written back after an outer product
311 chunk.resize(yy.size() * n);
312 std::vector<T*> p;
313 for (size_t j = 0; j < yy.size(); ++j) {
314 p.push_back(chunk.data() + j * n);
315 yy[j].get().get(g, g + n, p.back());
316 }
317 return p;
318 }
319 void done(size_t g, size_t n) {
320 if (bases.empty() and type == gemm_type::outer)
321 for (size_t j = 0; j < yy.size(); ++j)
322 yy[j].get().put(g, g + n, chunk.data() + j * n);
323 }
324 std::function<std::vector<T*>(size_t, size_t)> pointers_function() {
325 return [this](size_t g, size_t n) { return pointers(g, n); };
326 }
327 std::function<void(size_t, size_t)> done_function() {
328 return [this](size_t g, size_t n) { done(g, n); };
329 }
330 const VecRef<AL>& yy;
332 size_t lo = 0;
333 std::vector<T*> bases;
334 std::vector<T> chunk;
335};
336
337template <class AL, class AD, std::enable_if_t<is_disk_array_v<AD>, int> = 0>
339 const CVecRef<AD>& xx) {
340 auto non_const_yy = molpro::linalg::itsolv::const_cast_wrap(yy);
341 DistrChunks<AL> chunks(non_const_yy, gemm_type::inner);
342 return gemm_inner_buffered(yy.size(), xx, chunks.pointers_function());
343}
344
345template <class AD, class AL, std::enable_if_t<is_disk_array_v<AD> and not is_disk_array_v<AL>, int> = 0>
347 const CVecRef<AL>& yy) {
348 // gemm_inner is the hermitian inner product, so the two orders are conjugate transposes
350}
351
352template <class AL, class AD, std::enable_if_t<is_disk_array_v<AD>, int> = 0>
353void gemm_outer_distr_distr(const Matrix<typename array::mapped_or_value_type_t<AL>> alphas, const CVecRef<AD>& xx,
354 const VecRef<AL>& yy) {
355 if (yy.empty() or xx.empty())
356 return;
357 check_gemm_outer_dimensions(alphas, xx.size(), yy.size(), "gemm_outer_distr_distr");
358 auto prof = molpro::Profiler::single()->push("gemm_outer_distr_distr (buffered)");
359 prof += xx.size() * yy.size() * (local_range(xx[0].get()).second - local_range(xx[0].get()).first) * 2;
361 gemm_buffered(const_cast<typename array::mapped_or_value_type_t<AL>*>(alphas.data().data()), xx,
363}
364
365// Contiguous arrays rr, e.g. std::vector, holding all elements on every process, with distributed arrays qq.
366// Each process works on the local section of qq; rr updated by gemm_outer are then replicated over all processes.
367
369template <class R, class AD>
370Matrix<typename AD::value_type> gemm_inner_contiguous_distr(const CVecRef<R>& rr, const CVecRef<AD>& qq) {
371 using T = typename AD::value_type;
372 if (rr.empty() or qq.empty())
373 return Matrix<T>({rr.size(), qq.size()});
374 const auto& q = qq.front().get();
375 check_local_ranges(qq, local_range(q), "gemm_inner_contiguous_distr");
376 const auto lo = local_range(q).first;
377 const auto bases = contiguous_pointers<T>(rr, q, "gemm_inner_contiguous_distr");
378 return gemm_inner_buffered(rr.size(), qq, [&bases, lo](size_t g, size_t) { return offset_pointers(bases, lo, g); });
379}
380
382template <class AD, class R>
383Matrix<typename AD::value_type> gemm_inner_distr_contiguous(const CVecRef<AD>& qq, const CVecRef<R>& rr) {
385}
386
388template <class AD, class R>
389void gemm_outer_distr_contiguous(const Matrix<typename AD::value_type>& alphas, const CVecRef<AD>& qq,
390 const VecRef<R>& rr) {
391 using T = typename AD::value_type;
392 if (rr.empty() or qq.empty())
393 return;
394 check_gemm_outer_dimensions(alphas, qq.size(), rr.size(), "gemm_outer_distr_contiguous");
395 auto prof = molpro::Profiler::single()->push("gemm_outer_distr_contiguous");
396 const auto& q = qq.front().get();
397 check_local_ranges(qq, local_range(q), "gemm_outer_distr_contiguous");
398 const auto lo = local_range(q).first;
399 prof += qq.size() * rr.size() * (local_range(q).second - lo) * 2;
400 const auto bases = contiguous_pointers<T>(rr, q, "gemm_outer_distr_contiguous");
402 const_cast<T*>(alphas.data().data()), qq,
403 [&bases, lo](size_t g, size_t) { return offset_pointers(bases, lo, g); }, {}, gemm_type::outer);
404 for (const auto& r : rr)
405 gather_all(q.distribution(), q.communicator(), std::data(r.get()));
406}
407
409template <class R, class AD>
410void gemm_outer_contiguous_distr(const Matrix<typename AD::value_type>& alphas, const CVecRef<R>& rr,
411 const VecRef<AD>& qq) {
412 using T = typename AD::value_type;
413 if (rr.empty() or qq.empty())
414 return;
415 gemm_outer_to_distr(alphas, contiguous_pointers<T>(rr, qq.front().get(), "gemm_outer_contiguous_distr"), qq);
416}
417
418// Without buffers, for arrays held in memory
419
420template <class AL, class AR = AL, std::enable_if_t<not is_disk_array_v<AL> and not is_disk_array_v<AR>, int> = 0>
422 const CVecRef<AR>& yy) {
423 // const size_t spacing = 1;
424 using value_type = typename array::mapped_or_value_type_t<AL>;
425 auto mat = Matrix<value_type>({xx.size(), yy.size()});
426 if (xx.size() == 0 || yy.size() == 0)
427 return mat;
428 auto prof = molpro::Profiler::single()->push("gemm_inner_distr_distr (unbuffered)");
429 if (not xx.empty())
430 prof += mat.cols() * mat.rows() * xx.at(0).get().local_buffer()->size() * 2;
431 for (size_t j = 0; j < mat.cols(); ++j) {
432 auto loc_y = yy.at(j).get().local_buffer();
433 for (size_t i = 0; i < mat.rows(); ++i) {
434 auto loc_x = xx.at(i).get().local_buffer();
435 mat(i, j) = std::inner_product(begin(*loc_x), end(*loc_x), begin(*loc_y), (value_type)0);
436 // mat(i,j) += cblas_ddot(end(*loc_x) - begin(*loc_x), begin(*loc_x), spacing, begin(*loc_y), spacing);
437 }
438 }
439#ifdef HAVE_MPI_H
440 MPI_Allreduce(MPI_IN_PLACE, const_cast<value_type*>(mat.data().data()), mat.size(), MPI_DOUBLE, MPI_SUM,
441 xx.at(0).get().communicator());
442#endif
443 return mat;
444}
445
446template <class AL, class AR = AL, std::enable_if_t<not is_disk_array_v<AR>, int> = 0>
447void gemm_outer_distr_distr(const Matrix<typename array::mapped_or_value_type_t<AL>> alphas, const CVecRef<AR>& xx,
448 const VecRef<AL>& yy) {
449 if constexpr (is_disk_array_v<AL>) {
450 // the arrays xx are in memory, and so can be addressed in place, while yy are on disk
451 if (xx.empty() or yy.empty())
452 return;
453 check_local_ranges(xx, local_range(yy.front().get()), "gemm_outer_distr_distr");
455 return;
456 }
457 auto prof = molpro::Profiler::single()->push("gemm_outer_distr_distr (unbuffered)");
458 if (not yy.empty())
459 prof += alphas.rows() * alphas.cols() * yy[0].get().local_buffer()->size() * 2;
460 for (size_t ii = 0; ii < alphas.rows(); ++ii) {
461 auto loc_x = xx.at(ii).get().local_buffer();
462 for (size_t jj = 0; jj < alphas.cols(); ++jj) {
463 auto loc_y = yy[jj].get().local_buffer();
464 for (size_t i = 0; i < loc_y->size(); ++i)
465 (*loc_y)[i] += alphas(ii, jj) * (*loc_x)[i];
466 }
467 }
468}
469
470// Sparse
471
472template <class AL, class AR = AL>
473void gemm_outer_distr_sparse(const Matrix<typename array::mapped_or_value_type_t<AL>> alphas, const CVecRef<AR>& xx,
474 const VecRef<AL>& yy) {
475 // combine the sparse contributions to each yy, so that it is updated in one pass even when it is held on disk
476 for (size_t ii = 0; ii < alphas.cols(); ++ii) {
477 auto combined = std::decay_t<AR>{};
478 for (size_t jj = 0; jj < alphas.rows(); ++jj)
479 for (const auto& [i, v] : xx.at(jj).get())
480 combined[i] += alphas(jj, ii) * v;
481 yy[ii].get().axpy(1, combined);
482 }
483}
484
485template <class AL, class AR = AL>
487 const CVecRef<AR>& yy) {
488 using value_type = typename array::mapped_or_value_type_t<AL>;
489 auto mat = Matrix<value_type>({xx.size(), yy.size()});
490 if (xx.size() == 0 || yy.size() == 0)
491 return mat;
492 const auto [lo, hi] = local_range(xx.at(0).get());
493 for (size_t i = 0; i < mat.rows(); ++i) {
494 const auto& x = xx.at(i).get();
495 // an array in memory is read in place; one on disk has only the elements needed read
496 const bool on_disk = x.disk_page_size() > 0;
497 decltype(x.local_buffer()) loc_x;
498 if (not on_disk)
499 loc_x = x.local_buffer();
500 for (size_t j = 0; j < mat.cols(); ++j) {
501 mat(i, j) = 0;
502 for (auto it = yy.at(j).get().lower_bound(lo); it != yy.at(j).get().end() and it->first < hi; ++it) {
503 value_type xk;
504 if (on_disk)
505 x.get(it->first, it->first + 1, &xk);
506 else
507 xk = (*loc_x)[it->first - lo];
508 mat(i, j) += xk * it->second;
509 }
510 }
511 }
512#ifdef HAVE_MPI_H
513 MPI_Allreduce(MPI_IN_PLACE, const_cast<value_type*>(mat.data().data()), mat.size(), MPI_DOUBLE, MPI_SUM,
514 xx.at(0).get().communicator());
515#endif
516 return mat;
517}
518
519// Handlers
520
521template <class Handler, class AL, class AR = AL>
522void gemm_outer_default(Handler& handler, const Matrix<typename Handler::value_type> alphas, const CVecRef<AR>& xx,
523 const VecRef<AL>& yy) {
524 for (size_t ii = 0; ii < alphas.rows(); ++ii) {
525 for (size_t jj = 0; jj < alphas.cols(); ++jj) {
526 handler.axpy(alphas(ii, jj), xx.at(ii).get(), yy[jj].get());
527 }
528 }
529}
530
531template <class Handler, class AL, class AR = AL>
532Matrix<typename Handler::value_type> gemm_inner_default(Handler& handler, const CVecRef<AL>& xx,
533 const CVecRef<AR>& yy) {
534 auto mat = Matrix<typename Handler::value_type>({xx.size(), yy.size()});
535 if (xx.size() == 0 || yy.size() == 0)
536 return mat;
537 for (size_t ii = 0; ii < mat.rows(); ++ii) {
538 for (size_t jj = 0; jj < mat.cols(); ++jj) {
539 mat(ii, jj) = handler.dot(xx.at(ii).get(), yy.at(jj).get());
540 }
541 }
542 return mat;
543}
544
545} // namespace molpro::linalg::array::util
546
547#endif // LINEARALGEBRA_SRC_MOLPRO_LINALG_ARRAY_UTIL_GEMM_H
BufferManager provides single-buffered or asynchronous double-buffered read access to the data in a c...
Definition BufferManager.h:20
size_t buffer_offset() const
Definition BufferManager.h:77
size_t buffer_size() const
Definition BufferManager.h:67
size_t buffer_stride() const
Definition BufferManager.h:72
Iterator end()
Definition BufferManager.h:142
Iterator begin()
Definition BufferManager.h:140
Matrix container that allows simple data access, slicing, copying and resizing without loosing data.
Definition Matrix.h:32
const std::vector< T > & data() const &
Access the underlying data buffer.
Definition Matrix.h:69
size_t size() const
Definition Matrix.h:172
void fill(T value)
Sets all elements of matrix to value.
Definition Matrix.h:93
index_type rows() const
Definition Matrix.h:169
index_type cols() const
Definition Matrix.h:170
static std::shared_ptr< Profiler > single()
auto begin(Span< T > &x)
Definition Span.h:90
auto end(Span< T > &x)
Definition Span.h:100
Definition ArrayHandler.h:24
void check_local_ranges(const std::vector< std::reference_wrapper< A > > &aa, const Range &range, const std::string &name)
Checks that the distributed arrays aa all have the local section range, so that they can be processed...
Definition gemm.h:81
Matrix< typename AD::value_type > gemm_inner_contiguous_distr(const CVecRef< R > &rr, const CVecRef< AD > &qq)
The overlap matrix (rr.size(), qq.size()) between contiguous arrays rr and distributed arrays qq....
Definition gemm.h:370
constexpr bool is_disk_array_v
Whether arrays of type A are held on disk, and so must be read through buffers rather than local_buff...
Definition gemm.h:38
void gemm_outer_to_distr(const Matrix< T > &alphas, const std::vector< T * > &x_bases, const VecRef< AD > &yy)
yy += alphas^T xx, for arrays xx held in memory and distributed arrays yy held anywhere.
Definition gemm.h:251
Matrix< typename array::mapped_or_value_type_t< AL > > gemm_inner_distr_sparse(const CVecRef< AL > &xx, const CVecRef< AR > &yy)
Definition gemm.h:486
void gemm_buffered(T *alphadata, const CVecRef< AD > &xx, const std::type_identity_t< std::function< std::vector< T * >(size_t g, size_t n)> > &y_pointers, const std::function< void(size_t g, size_t n)> &y_done, gemm_type type)
gemm between distributed arrays xx, read through a BufferManager, and arrays yy, which can be held an...
Definition gemm.h:170
void gather_all(const Distribution< size_t > &distr, MPI_Comm commun, double *first_elem)
Replicate data of a full container on all the processes based on distributed pieces.
Definition gather_all.h:18
Matrix< T > conjugate_transpose(const Matrix< T > &m)
The transpose of an overlap matrix, which for the hermitian inner product is its conjugate transpose.
Definition gemm.h:236
size_t constant_stride(const std::vector< T * > &p, size_t n)
Definition gemm.h:51
void check_gemm_outer_dimensions(const Matrix< T > &alphas, size_t nx, size_t ny, const std::string &name)
Checks the dimensions of the coefficient matrix of gemm_outer.
Definition gemm.h:225
Matrix< typename array::mapped_or_value_type_t< AL > > gemm_inner_distr_distr(const CVecRef< AL > &yy, const CVecRef< AD > &xx)
Definition gemm.h:338
void gemm_outer_distr_sparse(const Matrix< typename array::mapped_or_value_type_t< AL > > alphas, const CVecRef< AR > &xx, const VecRef< AL > &yy)
Definition gemm.h:473
auto local_range(const A &a)
The section [lo, hi) of a distributed array held by this process.
Definition gemm.h:42
void gemm_chunk(gemm_type type, size_t n, const T *x, size_t ldx, size_t nx, T *alphadata, const std::vector< T * > &y)
One chunk of n elements of a gemm between the arrays xx, which are the nx columns of x with leading d...
Definition gemm.h:117
Matrix< T > gemm_inner_buffered(size_t ny, const CVecRef< AD > &xx, const std::type_identity_t< std::function< std::vector< T * >(size_t g, size_t n)> > &y_pointers, const std::function< void(size_t g, size_t n)> &y_done={})
The overlap matrix between arrays yy, accessed as described in gemm_buffered(), and distributed array...
Definition gemm.h:204
void gemm_outer_default(Handler &handler, const Matrix< typename Handler::value_type > alphas, const CVecRef< AR > &xx, const VecRef< AL > &yy)
Definition gemm.h:522
void gemm_outer_contiguous_distr(const Matrix< typename AD::value_type > &alphas, const CVecRef< R > &rr, const VecRef< AD > &qq)
qq += alphas^T rr for contiguous arrays rr and distributed arrays qq. Local.
Definition gemm.h:410
std::vector< T * > offset_pointers(const std::vector< T * > &bases, size_t lo, size_t g)
Pointers to elements [g, ...) of arrays whose local sections, starting at global index lo,...
Definition gemm.h:63
void gemm_outer_distr_contiguous(const Matrix< typename AD::value_type > &alphas, const CVecRef< AD > &qq, const VecRef< R > &rr)
rr += alphas^T qq for contiguous arrays rr and distributed arrays qq. Collective.
Definition gemm.h:389
std::vector< T * > contiguous_pointers(const std::vector< std::reference_wrapper< R > > &rr, const A &q, const std::string &name)
Pointers to the elements of contiguous arrays rr, offset to the start of the local section of the dis...
Definition gemm.h:93
std::vector< T * > local_buffer_pointers(const std::vector< std::reference_wrapper< A > > &aa)
Pointers to the start of the local sections of distributed arrays held in memory.
Definition gemm.h:72
gemm_type
Definition gemm.h:34
@ outer
Definition gemm.h:34
@ inner
Definition gemm.h:34
Matrix< typename AD::value_type > gemm_inner_distr_contiguous(const CVecRef< AD > &qq, const CVecRef< R > &rr)
The overlap matrix (qq.size(), rr.size()) between distributed arrays qq and contiguous arrays rr....
Definition gemm.h:383
void gemm_outer_distr_distr(const Matrix< typename array::mapped_or_value_type_t< AL > > alphas, const CVecRef< AD > &xx, const VecRef< AL > &yy)
Definition gemm.h:353
Matrix< typename Handler::value_type > gemm_inner_default(Handler &handler, const CVecRef< AL > &xx, const CVecRef< AR > &yy)
Definition gemm.h:532
typename mapped_or_value_type< A >::type mapped_or_value_type_t
Definition type_traits.h:38
void conjugate_transpose_copy(ML &&ml, const MR &mr)
Copies the conjugate transpose of mr into ml.
Definition Matrix.h:299
std::vector< std::reference_wrapper< const A > > CVecRef
Definition wrap.h:14
auto const_cast_wrap(ForwardIt begin, ForwardIt end)
Takes a begin and end iterators and returns a vector of const-casted references to each element.
Definition wrap.h:42
std::vector< std::reference_wrapper< A > > VecRef
Definition wrap.h:11
const std::shared_ptr< const molpro::Options > options()
Get the Options object associated with iterative-solver.
Definition linalg_options.cpp:4
The pointers to, and on completion the write-back of, chunks of distributed arrays yy for gemm_buffer...
Definition gemm.h:300
std::vector< T * > pointers(size_t g, size_t n)
Definition gemm.h:307
std::function< std::vector< T * >(size_t, size_t)> pointers_function()
Definition gemm.h:324
std::vector< T * > bases
Definition gemm.h:333
std::vector< T > chunk
Definition gemm.h:334
std::function< void(size_t, size_t)> done_function()
Definition gemm.h:327
size_t lo
Definition gemm.h:332
const VecRef< AL > & yy
Definition gemm.h:330
void done(size_t g, size_t n)
Definition gemm.h:319
const gemm_type type
Definition gemm.h:331
DistrChunks(const VecRef< AL > &yy, gemm_type type)
Definition gemm.h:301