MADNESS 0.10.1
vmra.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 $Id$
32*/
33#ifndef MADNESS_MRA_VMRA_H__INCLUDED
34#define MADNESS_MRA_VMRA_H__INCLUDED
35
36/*!
37 \file vmra.h
38 \brief Defines operations on vectors of Functions
39 \ingroup mra
40
41 This file defines a number of operations on vectors of functions.
42 Assume v is a vector of NDIM-D functions of a certain type.
43
44
45 Operations on array of functions
46
47 *) copying: deep copying of vectors of functions to vector of functions
48 \code
49 vector2 = copy(world, vector1,fence);
50 \endcode
51
52 *) compress: convert multiwavelet representation to legendre representation
53 \code
54 compress(world, vector, fence);
55 \endcode
56
57 *) reconstruct: convert representation to multiwavelets
58 \code
59 reconstruct(world, vector, fence);
60 \endcode
61
62 *) make_nonstandard: convert to non-standard form
63 \code
64 make_nonstandard(world, v, fence);
65 \endcode
66
67 *) standard: convert to standard form
68 \code
69 standard(world, v, fence);
70 \endcode
71
72 *) truncate: truncating vectors of functions to desired precision
73 \code
74 truncate(world, v, tolerance, fence);
75 \endcode
76
77
78 *) zero function: create a vector of zero functions of length n
79 \code
80 v=zero(world, n);
81 \endcode
82
83 *) transform: transform a representation from one basis to another
84 \code
85 transform(world, vector, tensor, tolerance, fence )
86 \endcode
87
88 Setting thresh-hold for precision
89
90 *) set_thresh: setting a finite thresh-hold for a vector of functions
91 \code
92 void set_thresh(World& world, std::vector< Function<T,NDIM> >& v, double thresh, bool fence=true);
93 \endcode
94
95 Arithmetic Operations on arrays of functions
96
97 *) conjugation: conjugate a vector of complex functions
98
99 *) add
100 *) sub
101 *) mul
102 - mul_sparse
103 *) square
104 *) gaxpy
105 *) apply
106
107 Norms, inner-products, blas-1 like operations on vectors of functions
108
109 *) inner
110 *) matrix_inner
111 *) norm_tree
112 *) normalize
113 *) norm2
114 - norm2s
115 *) scale(world, v, alpha);
116
117
118
119
120*/
121
122#include <madness/mra/mra.h>
125#include <cstdio>
126
127namespace madness {
128
129
130 /// get tree state of a vector of functions
131
132 /// @return TreeState::unknown if the vector is empty or if the functions have different tree states
133 template <typename T, std::size_t NDIM>
135 if (v.size()==0) return TreeState::unknown;
136 // return unknown if any function is not initialized
137 if (std::any_of(v.begin(), v.end(), [](const Function<T,NDIM>& f) {return not f.is_initialized();})) {
138 return TreeState::unknown;
139 }
140 TreeState state=v[0].get_impl()->get_tree_state();
141 for (const auto& f : v) {
142 if (f.get_impl()->get_tree_state()!=state) state=TreeState::unknown;
143 }
144 return state;
145 }
146
147 /// Compress a vector of functions
148 template <typename T, std::size_t NDIM>
149 void compress(World& world,
150 const std::vector< Function<T,NDIM> >& v,
151 bool fence=true) {
154 }
155
156
157 /// reconstruct a vector of functions
158
159 /// implies fence
160 /// return v for chaining
161 template <typename T, std::size_t NDIM>
162 const std::vector< Function<T,NDIM> >& reconstruct(const std::vector< Function<T,NDIM> >& v) {
164 }
165
166 /// compress a vector of functions
167
168 /// implies fence
169 /// return v for chaining
170 template <typename T, std::size_t NDIM>
171 const std::vector< Function<T,NDIM> >& compress(const std::vector< Function<T,NDIM> >& v) {
173 }
174
175 /// Reconstruct a vector of functions
176 template <typename T, std::size_t NDIM>
177 void reconstruct(World& world,
178 const std::vector< Function<T,NDIM> >& v,
179 bool fence=true) {
182 }
183
184 /// change tree_state of a vector of functions to redundant
185 template <typename T, std::size_t NDIM>
187 const std::vector< Function<T,NDIM> >& v,
188 bool fence=true) {
189
192 }
193
194 /// refine the functions according to the autorefine criteria
195 template <typename T, std::size_t NDIM>
196 void refine(World& world, const std::vector<Function<T,NDIM> >& vf,
197 bool fence=true) {
198 for (const auto& f : vf) f.refine(false);
199 if (fence) world.gop.fence();
200 }
201
202 /// refine all functions to a common (finest) level
203
204 /// if functions are not initialized (impl==NULL) they are ignored
205 template <typename T, std::size_t NDIM>
206 void refine_to_common_level(World& world, std::vector<Function<T,NDIM> >& vf,
207 bool fence=true) {
208
209 reconstruct(world,vf);
211 std::vector<FunctionImpl<T,NDIM>*> v_ptr;
212
213 // push initialized function pointers into the vector v_ptr
214 for (unsigned int i=0; i<vf.size(); ++i) {
215 if (vf[i].is_initialized()) v_ptr.push_back(vf[i].get_impl().get());
216 }
217
218 // sort and remove duplicates to not confuse the refining function
219 std::sort(v_ptr.begin(),v_ptr.end());
220 typename std::vector<FunctionImpl<T, NDIM>*>::iterator it;
221 it = std::unique(v_ptr.begin(), v_ptr.end());
222 v_ptr.resize( std::distance(v_ptr.begin(),it) );
223
224 std::vector< Tensor<T> > c(v_ptr.size());
225 v_ptr[0]->refine_to_common_level(v_ptr, c, key0);
226 if (fence) v_ptr[0]->world.gop.fence();
227 if (VERIFY_TREE)
228 for (unsigned int i=0; i<vf.size(); i++) vf[i].verify_tree();
229 }
230
231 /// Generates non-standard form of a vector of functions
232 template <typename T, std::size_t NDIM>
234 std::vector< Function<T,NDIM> >& v,
235 bool fence= true) {
238 }
239
240
241 /// Generates standard form of a vector of functions
242 template <typename T, std::size_t NDIM>
243 void standard(World& world,
244 std::vector< Function<T,NDIM> >& v,
245 bool fence=true) {
248 }
249
250
251 /// change tree state of the functions
252
253 /// might not respect fence
254 /// @return v for chaining
255 template <typename T, std::size_t NDIM>
256 const std::vector<Function<T,NDIM>>& change_tree_state(const std::vector<Function<T,NDIM>>& v,
257 const TreeState finalstate,
258 const bool fence=true) {
259 // fast return
260 if (v.size()==0) return v;
261 if (get_tree_state(v)==finalstate) return v;
262
263 // find initialized function with world
265 for (const auto& f : v)
266 if (f.is_initialized()) {
267 dummy=f;
268 break;
269 }
270 if (not dummy.is_initialized()) return v;
271 World& world=dummy.world();
272
273
274 // if a tree state cannot directly be changed to finalstate, we need to go via intermediate
275 auto change_initial_to_intermediate =[](const std::vector<Function<T,NDIM>>& v,
278 int must_fence=0;
279 for (auto& f : v) {
280 if (f.is_initialized() and f.get_impl()->get_tree_state()==initialstate) {
281 f.change_tree_state(intermediatestate,false);
282 must_fence=1;
283 }
284 }
285 return must_fence;
286 };
287
288 int do_fence=0;
289 if (finalstate==compressed) {
291 }
292 if (finalstate==nonstandard) {
295 }
300 }
301 if (finalstate==redundant) {
305 }
306 if (do_fence>0) world.gop.fence();
307
308 for (unsigned int i=0; i<v.size(); ++i) v[i].change_tree_state(finalstate,fence);
309 if (fence) world.gop.fence();
310
311 return v;
312 }
313
314 /// ensure v has the requested tree state, change the tree state of v if necessary and no fence is given
315 template<typename T, std::size_t NDIM>
317 const TreeState state, bool fence) {
318 // fast return
319 if (get_tree_state(v)==state) return true;;
320
321 // if there is a fence we can simply change the tree state, might be a no-op
322 if (fence) change_tree_state(v,state,true);
323
324 // check success, throw if not
325 bool ok=get_tree_state(v)==state;
326 if (not ok) {
327 print("ensure_tree_state_respecting_fence failed");
328 throw std::runtime_error("ensure_tree_state_respecting_fence failed");
329 }
330 return ok;
331 }
332
333 /// Truncates a vector of functions
334 template <typename T, std::size_t NDIM>
335 void truncate(World& world,
336 std::vector< Function<T,NDIM> >& v,
337 double tol=0.0,
338 bool fence=true) {
340
341 // truncate in compressed form only for low-dimensional functions
342 // compression is very expensive if low-rank tensor approximations are used
343 if (NDIM<4) compress(world, v);
344
345 for (auto& vv: v) {
346 vv.truncate(tol, false);
347 }
348
349 if (fence) world.gop.fence();
350 }
351
352 /// Truncates a vector of functions
353
354 /// @return the truncated vector for chaining
355 template <typename T, std::size_t NDIM>
356 std::vector< Function<T,NDIM> > truncate(std::vector< Function<T,NDIM> > v,
357 double tol=0.0, bool fence=true) {
358 if (v.size()>0) truncate(v[0].world(),v,tol,fence);
359 return v;
360 }
361
362 /// reduces the tensor rank of the coefficient tensor (if applicable)
363
364 /// @return the vector for chaining
365 template <typename T, std::size_t NDIM>
366 std::vector< Function<T,NDIM> > reduce_rank(std::vector< Function<T,NDIM> > v,
367 double thresh=0.0, bool fence=true) {
368 if (v.size()==0) return v;
369 for (auto& vv : v) vv.reduce_rank(thresh,false);
370 if (fence) v[0].world().gop.fence();
371 return v;
372 }
373
374
375 /// Pre-stages the neighbor coefficients that differentiating v with each of grad will need
376
377 /// Differentiating then serves those neighbors locally instead of fetching them one at a time.
378 /// One halo per function holds every operator's pushes, so it pays when several functions are
379 /// differentiated together. `clear_halo` frees them afterwards.
380 template <typename T, std::size_t NDIM>
381 void stage_halo(World& world,
382 const std::vector< std::shared_ptr< Derivative<T,NDIM> > >& grad,
383 const std::vector< Function<T,NDIM> >& v,
384 bool fence=true)
385 {
386 for (const auto& f : v) MADNESS_CHECK(f.is_reconstructed());
387 for (const auto& D : grad)
388 for (const auto& f : v) D->stage_halo(f.get_impl().get(), false);
389 if (fence) world.gop.fence();
390 }
391
392 /// Discards the neighbor halos staged on v
393
394 /// Requires a quiescent window: it frees tables the derivative may still be reading.
395 template <typename T, std::size_t NDIM>
396 void clear_halo(const std::vector< Function<T,NDIM> >& v)
397 {
398 for (const auto& f : v) f.get_impl()->halo_clear();
399 }
400
401 /// Applies a derivative operator to a vector of functions
402 template <typename T, std::size_t NDIM>
403 std::vector< Function<T,NDIM> >
404 apply(World& world,
405 const Derivative<T,NDIM>& D,
406 const std::vector< Function<T,NDIM> >& v,
407 bool fence=true)
408 {
409 reconstruct(world, v);
410 std::vector< Function<T,NDIM> > df(v.size());
411 for (unsigned int i=0; i<v.size(); ++i) {
412 df[i] = D(v[i],false);
413 }
414 if (fence) world.gop.fence();
415 return df;
416 }
417
418 /// Generates a vector of zero functions with a given tree state
419 template <typename T, std::size_t NDIM>
420 std::vector< Function<T,NDIM> >
421 zero_functions_tree_state(World& world, int n, const TreeState state, bool fence=true) {
422 std::vector< Function<T,NDIM> > r(n);
423 for (int i=0; i<n; ++i) {
424 if (state==compressed)
425 r[i] = Function<T,NDIM>(FunctionFactory<T,NDIM>(world).fence(false).compressed(true).initial_level(1));
426 else if (state==reconstructed)
427 r[i] = Function<T,NDIM>(FunctionFactory<T,NDIM>(world).fence(false));
428 else {
429 print("zero_functions_tree_state: unknown tree state");
430 throw std::runtime_error("zero_functions_tree_state: unknown tree state");
431 }
432 }
433
434 if (n && fence) world.gop.fence();
435 return r;
436
437 }
438
439 /// Generates a vector of zero functions (reconstructed)
440 template <typename T, std::size_t NDIM>
441 std::vector< Function<T,NDIM> >
442 zero_functions(World& world, int n, bool fence=true) {
444 }
445
446 /// Generates a vector of zero functions (compressed)
447 template <typename T, std::size_t NDIM>
448 std::vector< Function<T,NDIM> >
449 zero_functions_compressed(World& world, int n, bool fence=true) {
450 return zero_functions_tree_state<T,NDIM>(world,n,compressed,fence);
451 }
452
453 /// Generates a vector of zero functions, either compressed or reconstructed, depending on tensor type
454 template <typename T, std::size_t NDIM>
455 std::vector< Function<T,NDIM> >
456 zero_functions_auto_tree_state(World& world, int n, bool fence=true) {
458 return zero_functions_tree_state<T,NDIM>(world,n,state,fence);
459 }
460
461
462
463 /// orthonormalize the vectors
464 template<typename T, std::size_t NDIM>
465 std::vector<Function<T,NDIM>> orthonormalize(const std::vector<Function<T,NDIM> >& vf_in) {
466 if (vf_in.size()==0) return std::vector<Function<T,NDIM>>();
467 World& world=vf_in.front().world();
468 auto vf=copy(world,vf_in);
469 normalize(world,vf);
470 if (vf.size()==1) return copy(world,vf_in);
471 double maxq;
472 double trantol=0.0;
473 auto Q2=[](const Tensor<T>& s) {
474 Tensor<T> Q = -0.5*s;
475 for (int i=0; i<s.dim(0); ++i) Q(i,i) += 1.5;
476 return Q;
477 };
478
479 do {
480 Tensor<T> Q = Q2(matrix_inner(world, vf, vf));
481 maxq=0.0;
482 for (int i=0; i<Q.dim(0); ++i)
483 for (int j=0; j<i; ++j)
484 maxq = std::max(maxq,std::abs(Q(i,j)));
485
486 vf = transform(world, vf, Q, trantol, true);
487 truncate(world, vf);
488
489 } while (maxq>0.01);
490 normalize(world,vf);
491 return vf;
492 }
493
494
495 /// symmetric orthonormalization (see e.g. Szabo/Ostlund)
496
497 /// @param[in] the vector to orthonormalize
498 /// @param[in] overlap matrix
499 template <typename T, std::size_t NDIM>
500 std::vector<Function<T,NDIM> > orthonormalize_symmetric(
501 const std::vector<Function<T,NDIM> >& v,
502 const Tensor<T>& ovlp,
503 double lindep = 1e-12) {
504 if(v.empty()) return v;
505
506 World& world = v.front().world();
507 const size_t n = v.size();
508
509 Tensor<T> U;
511 syev(ovlp, U, s);
512 lindep *= s(s.size() - 1); // eigenvalues are in ascending order
513
514 // transform s to s^{-1/2} in-place
515 int rank = 0, nlindep = 0;
516 for(size_t i = 0; i < n; ++i) {
517 const auto s_i = s(i);
518 s(i) = 1.0 / sqrt(s_i);
519 (s_i > lindep) ? rank++ : nlindep++;
520 }
521 MADNESS_ASSERT(size_t(nlindep + rank) == n);
522
523 // warn of linearly dependent vectors and values
524 if (nlindep > 0) {
525 if (world.rank() == 0)
526 print("WARNING: linear dependencies detected in ", nlindep,
527 " functions, rank = ", rank);
528 }
529
530 // save Ut before U gets modified with s^{-1/2}
531 const Tensor<T> Ut = conj_transpose(U);
532
533 for(size_t i = 0; i < n; ++i){
534 for(size_t j = 0; j < n; ++j){
535 U(i, j) = U(i, j) * s(j);
536 }
537 }
538
539 Tensor<T> X = inner(U, Ut, 1, 0);
540
541 return transform(world, v, X);
542 }
543
544 /// convenience routine for symmetric orthonormalization (see e.g. Szabo/Ostlund)
545 /// overlap matrix is calculated
546 /// @param[in] the vector to orthonormalize
547 template <typename T, std::size_t NDIM>
548 std::vector<Function<T,NDIM> > orthonormalize_symmetric(const std::vector<Function<T,NDIM> >& v,
549 double lindep = 1e-12){
550 if(v.empty()) return v;
551
552 Tensor<T> ovlp = matrix_inner(v.front().world(), v, v, /* sym= */ true);
553
555 }
556
557 /// canonical orthonormalization (see e.g. Szabo/Ostlund)
558 /// @param[in] the vector to orthonormalize
559 /// @param[in] overlap matrix
560 /// @param[in] lindep linear dependency threshold relative to largest eigenvalue
561 template <typename T, std::size_t NDIM>
562 std::vector<Function<T,NDIM> > orthonormalize_canonical(
563 const std::vector<Function<T,NDIM> >& v,
564 const Tensor<T>& ovlp,
565 double lindep = 1e-12) {
566 if(v.empty()) return v;
567
568 World& world = v.front().world();
569 const size_t n = v.size();
570
571 Tensor<T> U;
573 syev(ovlp, U, s);
574 lindep *= s(s.size() - 1); // eigenvalues are in ascending order
575
576 // transform s to s^{-1/2} in-place
577 int rank = 0, nlindep = 0;
578 for(size_t i = 0; i < n; ++i) {
579 const auto s_i = s(i);
580 if (s_i > lindep) {
581 s(i) = 1.0 / sqrt(s_i);
582 rank++;
583 } else {
584 nlindep++;
585 }
586 }
587 MADNESS_ASSERT(size_t(nlindep + rank) == n);
588
589 // remove linearly dependent vectors and values
590 if (nlindep > 0) {
591 if (world.rank() == 0)
592 print("Linear dependencies detected: removed ", nlindep,
593 " functions, rank = ", rank);
594 U = U(_, Slice(nlindep, -1));
595 s = s(Slice(nlindep, -1));
596 }
597
598 // modify U in-place, U is now transformation matrix (U * s^{-1/2})
599 for(size_t i = 0; i < n; ++i){
600 for(size_t j = 0; j < rank; ++j){
601 U(i, j) = U(i, j) * s(j);
602 }
603 }
604
605 return transform(world, v, U);
606 }
607
608 /// convenience routine for canonical routine for symmetric orthonormalization (see e.g. Szabo/Ostlund)
609 /// overlap matrix is calculated
610 /// @param[in] the vector to orthonormalize
611 template <typename T, std::size_t NDIM>
612 std::vector<Function<T,NDIM> > orthonormalize_canonical(const std::vector<Function<T,NDIM> >& v,
613 double lindep = 1e-12){
614 if(v.empty()) return v;
615
616 Tensor<T> ovlp = matrix_inner(v.front().world(), v, v, /* sym= */ true);
617
619 }
620
621 /// cholesky orthonormalization without pivoting
622 /// @param[in] the vector to orthonormalize
623 /// @param[in] overlap matrix, destroyed on return!
624 template <typename T, std::size_t NDIM>
625 std::vector<Function<T,NDIM> > orthonormalize_cd(
626 const std::vector<Function<T,NDIM> >& v,
627 Tensor<T>& ovlp) {
628
629 if (v.empty()) return v;
630
631 cholesky(ovlp); // destroys ovlp and gives back Upper ∆ Matrix from CD
632
636
637 World& world=v.front().world();
638 return transform(world, v, U);
639
640 }
641
642 /// convenience routine for cholesky orthonormalization without pivoting
643 /// @param[in] the vector to orthonormalize
644 /// @param[in] overlap matrix
645 template <typename T, std::size_t NDIM>
646 std::vector<Function<T,NDIM> > orthonormalize_cd(const std::vector<Function<T,NDIM> >& v){
647 if(v.empty()) return v;
648
649 World& world=v.front().world();
650 Tensor<T> ovlp = matrix_inner(world, v, v, /* sym= */ true);
651
652 return orthonormalize_cd(v,ovlp);
653 }
654
655 /// @param[in] the vector to orthonormalize
656 /// @param[in] overlap matrix, will be destroyed on return!
657 /// @param[in] tolerance for numerical rank reduction
658 /// @param[out] pivoting vector, no allocation on input needed
659 /// @param[out] rank
660 /// @return orthonormalized vector (may or may not be truncated)
661 template <typename T, std::size_t NDIM>
662 std::vector<Function<T,NDIM> > orthonormalize_rrcd(
663 const std::vector<Function<T,NDIM> >& v,
665 const double tol,
667 int& rank) {
668
669 if (v.empty()) {
670 return v;
671 }
672
673 rr_cholesky(ovlp,tol,piv,rank); // destroys ovlp and gives back Upper ∆ Matrix from CCD
674
675 // rearrange and truncate the functions according to the pivoting of the rr_cholesky
676 std::vector<Function<T,NDIM> > pv(rank);
677 for(integer i=0;i<rank;++i){
678 pv[i]=v[piv[i]];
679 }
680 ovlp=ovlp(Slice(0,rank-1),Slice(0,rank-1));
681
685
686 World& world=v.front().world();
687 return transform(world, pv, U);
688 }
689
690 /// convenience routine for orthonormalize_cholesky: orthonormalize_cholesky without information on pivoting and rank
691 /// @param[in] the vector to orthonormalize
692 /// @param[in] overlap matrix
693 /// @param[in] tolerance for numerical rank reduction
694 template <typename T, std::size_t NDIM>
695 std::vector<Function<T,NDIM> > orthonormalize_rrcd(const std::vector<Function<T,NDIM> >& v, Tensor<T> ovlp , const double tol) {
697 int rank;
698 return orthonormalize_rrcd(v,ovlp,tol,piv,rank);
699 }
700
701 /// convenience routine for orthonormalize_cholesky: computes the overlap matrix and then calls orthonormalize_cholesky
702 /// @param[in] the vector to orthonormalize
703 /// @param[in] tolerance for numerical rank reduction
704 template <typename T, std::size_t NDIM>
705 std::vector<Function<T,NDIM> > orthonormalize_rrcd(const std::vector<Function<T,NDIM> >& v, const double tol) {
706 if (v.empty()) {
707 return v;
708 }
709 // compute overlap
710 World& world=v.front().world();
711 Tensor<T> ovlp = matrix_inner(world, v, v, /* sym= */ true);
712 return orthonormalize_rrcd(v,ovlp,tol);
713 }
714
715 /// combine two vectors
716 template <typename T, std::size_t NDIM>
717 std::vector<Function<T,NDIM> > append(const std::vector<Function<T,NDIM> > & lhs, const std::vector<Function<T,NDIM> > & rhs){
718 std::vector<Function<T,NDIM> > v=lhs;
719 for (std::size_t i = 0; i < rhs.size(); ++i) v.push_back(rhs[i]);
720 return v;
721 }
722
723 template <typename T, std::size_t NDIM>
724 std::vector<Function<T,NDIM> > flatten(const std::vector< std::vector<Function<T,NDIM> > >& vv){
725 std::vector<Function<T,NDIM> >result;
726 for(const auto& x:vv) result=append(result,x);
727 return result;
728 }
729
730 template<typename T, std::size_t NDIM>
731 std::vector<std::shared_ptr<FunctionImpl<T,NDIM>>> get_impl(const std::vector<Function<T,NDIM>>& v) {
732 std::vector<std::shared_ptr<FunctionImpl<T,NDIM>>> result;
733 for (auto& f : v) result.push_back(f.get_impl());
734 return result;
735 }
736
737 template<typename T, std::size_t NDIM>
738 void set_impl(std::vector<Function<T,NDIM>>& v, const std::vector<std::shared_ptr<FunctionImpl<T,NDIM>>> vimpl) {
739 MADNESS_CHECK(vimpl.size()==v.size());
740 for (std::size_t i=0; i<vimpl.size(); ++i) v[i].set_impl(vimpl[i]);
741 }
742
743 template<typename T, std::size_t NDIM>
744 std::vector<Function<T,NDIM>> impl2function(const std::vector<std::shared_ptr<FunctionImpl<T,NDIM>>> vimpl) {
745 std::vector<Function<T,NDIM>> v(vimpl.size());
746 for (std::size_t i=0; i<vimpl.size(); ++i) v[i].set_impl(vimpl[i]);
747 return v;
748 }
749
750
751 /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i]
752
753 /// Uses sparsity in the transformation matrix --- set small elements to
754 /// zero to take advantage of this.
755 template <typename T, typename R, std::size_t NDIM>
756 std::vector< Function<TENSOR_RESULT_TYPE(T,R),NDIM> >
758 const std::vector< Function<T,NDIM> >& v,
759 const Tensor<R>& c,
760 bool fence=true) {
761
763 typedef TENSOR_RESULT_TYPE(T,R) resultT;
764 int n = v.size(); // n is the old dimension
765 int m = c.dim(1); // m is the new dimension
766 MADNESS_CHECK(n==c.dim(0));
767
768 std::vector< Function<resultT,NDIM> > vc = zero_functions_compressed<resultT,NDIM>(world, m);
769 compress(world, v);
770
771 for (int i=0; i<m; ++i) {
772 for (int j=0; j<n; ++j) {
773 if (c(j,i) != R(0.0)) vc[i].gaxpy(resultT(1.0),v[j],resultT(c(j,i)),false);
774 }
775 }
776
777 if (fence) world.gop.fence();
778 return vc;
779 }
780
781 /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i]
782
783 /// all trees are in reconstructed state, final trees have to be summed down if no fence is present
784 template <typename T, typename R, std::size_t NDIM>
785 std::vector< Function<TENSOR_RESULT_TYPE(T,R),NDIM> >
787 const std::vector< Function<T,NDIM> >& v,
788 const Tensor<R>& c,
789 bool fence=true) {
790
792 typedef TENSOR_RESULT_TYPE(T,R) resultT;
793 int n = v.size(); // n is the old dimension
794 int m = c.dim(1); // m is the new dimension
795 MADNESS_CHECK(n==c.dim(0));
796
797 // if we fence set the right tree state here, otherwise it has to be correct from the start.
799 for (const auto& vv : v) MADNESS_CHECK_THROW(
800 vv.get_impl()->get_tree_state()==reconstructed,"trees have to be reconstructed in transform_reconstructed");
801
802 std::vector< Function<resultT,NDIM> > result = zero_functions<resultT,NDIM>(world, m);
803
804 for (int i=0; i<m; ++i) {
805 result[i].get_impl()->set_tree_state(redundant_after_merge);
806 for (int j=0; j<n; ++j) {
807 if (c(j,i) != R(0.0)) v[j].get_impl()->accumulate_trees(*(result[i].get_impl()),resultT(c(j,i)),true);
808 }
809 }
810
811 // if we fence we can as well finish the job here. Otherwise no harm done, as the tree state is well-defined.
812 if (fence) {
813 world.gop.fence();
814 // for (auto& r : vc) r.sum_down(false);
815 for (auto& r : result) r.get_impl()->finalize_sum();
816 world.gop.fence();
817 }
818 return result;
819 }
820
821 /// this version of transform uses Function::vtransform and screens
822 /// using both elements of `c` and `v`
823 template <typename L, typename R, std::size_t NDIM>
824 std::vector< Function<TENSOR_RESULT_TYPE(L,R),NDIM> >
825 transform(World& world, const std::vector< Function<L,NDIM> >& v,
826 const Tensor<R>& c, double tol, bool fence=true) {
828 MADNESS_ASSERT(v.size() == (unsigned int)(c.dim(0)));
829
830 std::vector< Function<TENSOR_RESULT_TYPE(L,R),NDIM> > vresult
832
833 compress(world, v, true);
834 vresult[0].vtransform(v, c, vresult, tol, fence);
835 return vresult;
836 }
837
838 template <typename T, typename R, std::size_t NDIM>
839 std::vector< Function<TENSOR_RESULT_TYPE(T,R),NDIM> >
841 const std::vector< Function<T,NDIM> >& v,
842 const DistributedMatrix<R>& c,
843 bool fence=true) {
845
846 typedef TENSOR_RESULT_TYPE(T,R) resultT;
847 long n = v.size(); // n is the old dimension
848 long m = c.rowdim(); // m is the new dimension
849 MADNESS_ASSERT(n==c.coldim());
850
851 // new(i) = sum(j) old(j) c(j,i)
852
853 Tensor<T> tmp(n,m);
854 c.copy_to_replicated(tmp); // for debugging
855 tmp = transpose(tmp);
856
857 std::vector< Function<resultT,NDIM> > vc = zero_functions_compressed<resultT,NDIM>(world, m);
858 compress(world, v);
859
860 for (int i=0; i<m; ++i) {
861 for (int j=0; j<n; ++j) {
862 if (tmp(j,i) != R(0.0)) vc[i].gaxpy(1.0,v[j],tmp(j,i),false);
863 }
864 }
865
866 if (fence) world.gop.fence();
867 return vc;
868 }
869
870
871 /// Scales inplace a vector of functions by distinct values
872 template <typename T, typename Q, std::size_t NDIM>
873 void scale(World& world,
874 std::vector< Function<T,NDIM> >& v,
875 const std::vector<Q>& factors,
876 bool fence=true) {
878 for (unsigned int i=0; i<v.size(); ++i) v[i].scale(factors[i],false);
879 if (fence) world.gop.fence();
880 }
881
882 /// Scales inplace a vector of functions by the same
883 template <typename T, typename Q, std::size_t NDIM>
884 void scale(World& world,
885 std::vector< Function<T,NDIM> >& v,
886 const Q factor,
887 bool fence=true) {
889 for (unsigned int i=0; i<v.size(); ++i) v[i].scale(factor,false);
890 if (fence) world.gop.fence();
891 }
892
893 /// Computes the 2-norms of a vector of functions
894 template <typename T, std::size_t NDIM>
895 std::vector<double> norm2s(World& world,
896 const std::vector< Function<T,NDIM> >& v) {
898 std::vector<double> norms(v.size());
900 for (unsigned int i=0; i<v.size(); ++i) norms[i] = v[i].norm2sq_local();
901 world.gop.sum(&norms[0], norms.size());
902 for (unsigned int i=0; i<v.size(); ++i) norms[i] = sqrt(norms[i]);
903 world.gop.fence();
904 return norms;
905 }
906 /// Computes the 2-norms of a vector of functions
907 template <typename T, std::size_t NDIM>
908 Tensor<double> norm2s_T(World& world, const std::vector<Function<T, NDIM>>& v) {
910 Tensor<double> norms(v.size());
912 for (unsigned int i = 0; i < v.size(); ++i) norms[i] = v[i].norm2sq_local();
913 world.gop.sum(&norms[0], norms.size());
914 for (unsigned int i = 0; i < v.size(); ++i) norms[i] = sqrt(norms[i]);
915 world.gop.fence();
916 return norms;
917 }
918
919 /// Computes the 2-norm of a vector of functions
920 template <typename T, std::size_t NDIM>
921 double norm2(World& world,const std::vector< Function<T,NDIM> >& v) {
923 if (v.size()==0) return 0.0;
925 std::vector<double> norms(v.size());
926 for (unsigned int i=0; i<v.size(); ++i) norms[i] = v[i].norm2sq_local();
927 world.gop.sum(&norms[0], norms.size());
928 for (unsigned int i=1; i<v.size(); ++i) norms[0] += norms[i];
929 world.gop.fence();
930 return sqrt(norms[0]);
931 }
932
933 inline double conj(double x) {
934 return x;
935 }
936
937 inline double conj(float x) {
938 return x;
939 }
940
941// !!! FIXME: this task is broken because FunctionImpl::inner_local forces a
942// future on return from WorldTaskQueue::reduce, which will causes a deadlock if
943// run inside a task. This behavior must be changed before this task can be used
944// again.
945//
946// template <typename T, typename R, std::size_t NDIM>
947// struct MatrixInnerTask : public TaskInterface {
948// Tensor<TENSOR_RESULT_TYPE(T,R)> result; // Must be a copy
949// const Function<T,NDIM>& f;
950// const std::vector< Function<R,NDIM> >& g;
951// long jtop;
952//
953// MatrixInnerTask(const Tensor<TENSOR_RESULT_TYPE(T,R)>& result,
954// const Function<T,NDIM>& f,
955// const std::vector< Function<R,NDIM> >& g,
956// long jtop)
957// : result(result), f(f), g(g), jtop(jtop) {}
958//
959// void run(World& world) {
960// for (long j=0; j<jtop; ++j) {
961// result(j) = f.inner_local(g[j]);
962// }
963// }
964//
965// private:
966// /// Get the task id
967//
968// /// \param id The id to set for this task
969// virtual void get_id(std::pair<void*,unsigned short>& id) const {
970// PoolTaskInterface::make_id(id, *this);
971// }
972// }; // struct MatrixInnerTask
973
974
975
976 template <typename T, std::size_t NDIM>
978 const std::vector< Function<T,NDIM> >& f,
979 const std::vector< Function<T,NDIM> >& g,
980 bool sym=false)
981 {
984 const int64_t n = A.coldim();
985 const int64_t m = A.rowdim();
986 MADNESS_ASSERT(int64_t(f.size()) == n && int64_t(g.size()) == m);
987
988 // Assume we can always create an ichunk*jchunk matrix locally
989 const int ichunk = 1000;
990 const int jchunk = 1000; // 1000*1000*8 = 8 MBytes
991 for (int64_t ilo=0; ilo<n; ilo+=ichunk) {
992 int64_t ihi = std::min(ilo + ichunk, n);
993 std::vector< Function<T,NDIM> > ivec(f.begin()+ilo, f.begin()+ihi);
994 for (int64_t jlo=0; jlo<m; jlo+=jchunk) {
995 int64_t jhi = std::min(jlo + jchunk, m);
996 std::vector< Function<T,NDIM> > jvec(g.begin()+jlo, g.begin()+jhi);
997
998 Tensor<T> P = matrix_inner(A.get_world(), ivec, jvec);
999 A.copy_from_replicated_patch(ilo, ihi - 1, jlo, jhi - 1, P);
1000 }
1001 }
1002 return A;
1003 }
1004
1005 /// Computes the matrix inner product of two function vectors - q(i,j) = inner(f[i],g[j])
1006
1007 /// For complex types symmetric is interpreted as Hermitian.
1008
1009 /// The current parallel loop is non-optimal but functional.
1010 template <typename T, typename R, std::size_t NDIM>
1012 const std::vector< Function<T,NDIM> >& f,
1013 const std::vector< Function<R,NDIM> >& g,
1014 bool sym=false)
1015 {
1016 world.gop.fence();
1017 auto tensor_type = [](const std::vector<Function<T,NDIM>>& v) {
1018 return v.front().get_impl()->get_tensor_type();
1019 };
1020 TreeState operating_state=tensor_type(f)==TT_FULL ? compressed : redundant;
1021 ensure_tree_state_respecting_fence(f,operating_state,true);
1022 ensure_tree_state_respecting_fence(g,operating_state,true);
1023
1024 std::vector<const FunctionImpl<T,NDIM>*> left(f.size());
1025 std::vector<const FunctionImpl<R,NDIM>*> right(g.size());
1026 for (unsigned int i=0; i<f.size(); i++) left[i] = f[i].get_impl().get();
1027 for (unsigned int i=0; i<g.size(); i++) right[i]= g[i].get_impl().get();
1028
1030
1031 world.gop.fence();
1032 world.gop.sum(r.ptr(),f.size()*g.size());
1033
1034 return r;
1035 }
1036
1037 /// Computes the matrix inner product of two function vectors - q(i,j) = inner(f[i],g[j])
1038
1039 /// For complex types symmetric is interpreted as Hermitian.
1040 ///
1041 /// The current parallel loop is non-optimal but functional.
1042 template <typename T, typename R, std::size_t NDIM>
1044 const std::vector< Function<T,NDIM> >& f,
1045 const std::vector< Function<R,NDIM> >& g,
1046 bool sym=false) {
1048 long n=f.size(), m=g.size();
1049 Tensor< TENSOR_RESULT_TYPE(T,R) > r(n,m);
1050 if (sym) MADNESS_ASSERT(n==m);
1051
1052 world.gop.fence();
1053 compress(world, f);
1054 if ((void*)(&f) != (void*)(&g)) compress(world, g);
1055
1056 for (long i=0; i<n; ++i) {
1057 long jtop = m;
1058 if (sym) jtop = i+1;
1059 for (long j=0; j<jtop; ++j) {
1060 r(i,j) = f[i].inner_local(g[j]);
1061 if (sym) r(j,i) = conj(r(i,j));
1062 }
1063 }
1064
1065// for (long i=n-1; i>=0; --i) {
1066// long jtop = m;
1067// if (sym) jtop = i+1;
1068// world.taskq.add(new MatrixInnerTask<T,R,NDIM>(r(i,_), f[i], g, jtop));
1069// }
1070 world.gop.fence();
1071 world.gop.sum(r.ptr(),n*m);
1072
1073// if (sym) {
1074// for (int i=0; i<n; ++i) {
1075// for (int j=0; j<i; ++j) {
1076// r(j,i) = conj(r(i,j));
1077// }
1078// }
1079// }
1080 return r;
1081 }
1082
1083 /// Computes the element-wise inner product of two function vectors - q(i) = inner(f[i],g[i])
1084
1085 /// works in reconstructed or compressed state, state is chosen based on TensorType
1086 template <typename T, typename R, std::size_t NDIM>
1088 const std::vector< Function<T,NDIM> >& f,
1089 const std::vector< Function<R,NDIM> >& g) {
1091 long n=f.size(), m=g.size();
1092 MADNESS_CHECK(n==m);
1093 Tensor< TENSOR_RESULT_TYPE(T,R) > r(n);
1094 if (n==0) return r;
1095
1096 auto tensor_type = [](const std::vector<Function<T,NDIM>>& v) {
1097 return v.front().get_impl()->get_tensor_type();
1098 };
1099 TreeState operating_state=tensor_type(f)==TT_FULL ? compressed : redundant;
1100 ensure_tree_state_respecting_fence(f,operating_state,true);
1101 ensure_tree_state_respecting_fence(g,operating_state,true);
1102
1103 for (long i=0; i<n; ++i) r(i) = f[i].inner_local(g[i]);
1104
1105 world.taskq.fence();
1106 world.gop.sum(r.ptr(),n);
1107 world.gop.fence();
1108 return r;
1109 }
1110
1111
1112 /// Computes the inner product of a function with a function vector - q(i) = inner(f,g[i])
1113
1114 /// works in reconstructed or compressed state, state is chosen based on TensorType
1115 template <typename T, typename R, std::size_t NDIM>
1117 const Function<T,NDIM>& f,
1118 const std::vector< Function<R,NDIM> >& g) {
1120 long n=g.size();
1121 Tensor< TENSOR_RESULT_TYPE(T,R) > r(n);
1122
1123 auto tensor_type = [](const std::vector<Function<T,NDIM>>& v) {
1124 return v.front().get_impl()->get_tensor_type();
1125 };
1126 TreeState operating_state=tensor_type(g)==TT_FULL ? compressed : redundant;
1127 f.change_tree_state(operating_state,false);
1128 ensure_tree_state_respecting_fence(g,operating_state,true);
1129 world.gop.fence();
1130
1131 for (long i=0; i<n; ++i) {
1132 r(i) = f.inner_local(g[i]);
1133 }
1134
1135 world.taskq.fence();
1136 world.gop.sum(r.ptr(),n);
1137 world.gop.fence();
1138 return r;
1139 }
1140
1141 /// inner function with right signature for the nonlinear solver
1142 /// this is needed for the KAIN solvers and other functions
1143 template <typename T, typename R, std::size_t NDIM>
1144 TENSOR_RESULT_TYPE(T,R) inner( const std::vector< Function<T,NDIM> >& f,
1145 const std::vector< Function<R,NDIM> >& g){
1146 MADNESS_ASSERT(f.size()==g.size());
1147 if(f.empty()) return 0.0;
1148 else return inner(f[0].world(),f,g).sum();
1149 }
1150
1151
1152 /// Multiplies a function against a vector of functions --- q[i] = a * v[i]
1153 template <typename T, typename R, std::size_t NDIM>
1154 std::vector< Function<TENSOR_RESULT_TYPE(T,R), NDIM> >
1155 mul(World& world,
1156 const Function<T,NDIM>& a,
1157 const std::vector< Function<R,NDIM> >& v,
1158 bool fence=true) {
1160 make_redundant(world, v, false);
1161 a.make_redundant(false);
1162 world.gop.fence();
1163 return vmulXX(a, v, 0.0, fence);
1164 }
1165
1166 /// Multiplies a function against a vector of functions using sparsity of a and v[i] --- q[i] = a * v[i]
1167 ///
1168 /// Box pairs whose estimated contribution falls below the tolerance are skipped instead
1169 /// of being multiplied. Both inputs are made redundant; the screening reads their
1170 /// norm_tree and dnorm_tree.
1171 ///
1172 /// Leaves both inputs in redundant form. Function is a shallow handle, so this is visible
1173 /// to the caller: logically const, not bitwise const. Converting back is not free, so a
1174 /// caller that reuses the operands afterwards must do it itself.
1175 ///
1176 /// @param[in] tol target absolute accuracy of the product; the safety margin is applied
1177 /// internally (FunctionImpl::MUL_SCREENING_SAFETY), so pass the accuracy
1178 /// wanted, not a pre-scaled value. tol=0 multiplies exactly. The criterion
1179 /// estimates the neglected cross terms rather than bounding them: the error
1180 /// tracks tol up to a measured O(1-20) constant and decays as ~tol^0.75
1181 /// rather than ~tol (see test_mul_sparse.cc). The meaning differs from the
1182 /// earlier norm_tree-based screen, so a previously tuned value needs
1183 /// re-checking.
1184 /// @param[in] do_make_redundant if false, both inputs must already be redundant
1185 template <typename T, typename R, std::size_t NDIM>
1186 std::vector< Function<TENSOR_RESULT_TYPE(T,R), NDIM> >
1188 const Function<T,NDIM>& a,
1189 const std::vector< Function<R,NDIM> >& v,
1190 double tol,
1191 bool fence=true,
1192 bool do_make_redundant=true) {
1194 if (do_make_redundant) {
1195 make_redundant(world, v, false);
1196 a.make_redundant(false);
1197 world.gop.fence();
1198 } else if (!v.empty()) {
1199 MADNESS_CHECK_THROW(a.get_impl()->get_tree_state() == TreeState::redundant,
1200 "mul_sparse: left input must be redundant when do_make_redundant=false");
1202 "mul_sparse: right inputs must be redundant when do_make_redundant=false");
1203 }
1204 return vmulXX(a, v, tol, fence);
1205 }
1206
1207
1208 /// Outer product of a vector of functions with a vector of functions using sparsity
1209
1210 /// \tparam T type parameter for first factor
1211 /// \tparam R type parameter for second factor
1212 /// \tparam NDIM dimension of first and second factors
1213 /// \param world the world
1214 /// \param f first vector of functions
1215 /// \param g second vector of functions
1216 /// \param tol target absolute accuracy of each product; see mul_sparse for the
1217 /// semantics, including the internal safety margin and tol=0
1218 /// \param fence force fence (will always fence if necessary)
1219 /// \param symm if true, only compute f(i) * g(j) for j<=i
1220 /// \return fg(i,j) = f(i) * g(j), as a vector of vectors
1221 template <typename T, typename R, std::size_t NDIM>
1222 std::vector<std::vector<Function<TENSOR_RESULT_TYPE(T, R), NDIM> > >
1224 const std::vector<Function<R, NDIM> > &f,
1225 const std::vector<Function<R, NDIM> > &g,
1226 double tol,
1227 bool fence = true,
1228 bool symm = false) {
1230 bool same=(&f == &g);
1231 make_redundant(world, f, false);
1232 if (not same) make_redundant(world, g, false);
1233 world.gop.fence();
1234
1235 std::vector<std::vector<Function<R,NDIM> > >result(f.size());
1236 std::vector<Function<R,NDIM>> g_i;
1237 for (int64_t i=f.size()-1; i>=0; --i) {
1238 if (!symm)
1239 result[i]= vmulXX(f[i], g, tol, false);
1240 else {
1241 if (g_i.empty()) g_i = g;
1242 g_i.resize(i+1); // this shrinks g_i down to single function for i=0
1243 result[i]= vmulXX(f[i], g_i, tol, false);
1244 }
1245 }
1246 if (fence) world.gop.fence();
1247 return result;
1248 }
1249
1250 /// Makes the norm tree for all functions in a vector
1251 template <typename T, std::size_t NDIM>
1252 void norm_tree(World& world,
1253 const std::vector< Function<T,NDIM> >& v,
1254 bool fence=true)
1255 {
1257 for (unsigned int i=0; i<v.size(); ++i) {
1258 v[i].norm_tree(false);
1259 }
1260 if (fence) world.gop.fence();
1261 }
1262
1263 /// Multiplies two vectors of functions q[i] = a[i] * b[i]
1264
1265 /// @param[in] tol 0 (the default) multiplies exactly; see mul_sparse to screen
1266 template <typename T, typename R, std::size_t NDIM>
1267 std::vector< Function<TENSOR_RESULT_TYPE(T,R), NDIM> >
1268 mul(World& world,
1269 const std::vector< Function<T,NDIM> >& a,
1270 const std::vector< Function<R,NDIM> >& b,
1271 bool fence=true,
1272 bool do_make_redundant=true,
1273 double tol=0.0) {
1275 if (do_make_redundant) {
1276 // prepare once, not once per pair: mul_sparse fences whenever it prepares.
1277 // Redundant inputs make the second call a no-op, so no aliasing check is needed.
1278 make_redundant(world, a, false);
1279 make_redundant(world, b, false);
1280 world.gop.fence();
1281 }
1282 std::vector< Function<TENSOR_RESULT_TYPE(T,R),NDIM> > q(a.size());
1283 for (unsigned int i=0; i<a.size(); ++i) {
1284 q[i] = mul(a[i], b[i], false, false, tol);
1285 }
1286 if (fence) world.gop.fence();
1287 return q;
1288 }
1289
1290
1291 /// multiply a high-dimensional function with a low-dimensional function
1292
1293 /// @param[in] f NDIM function of NDIM dimensions
1294 /// @param[in] g LDIM function of LDIM
1295 /// @param[in] v dimension indices of f to multiply
1296 /// @return h[i](0,1,2,3) = f(0,1,2,3) * g[i](1,2,3) for v={1,2,3}
1297 template<typename T, std::size_t NDIM, std::size_t LDIM>
1298 std::vector<Function<T,NDIM> > partial_mul(const Function<T,NDIM> f, const std::vector<Function<T,LDIM> > g,
1299 const int particle) {
1300
1301 World& world=f.world();
1302 std::vector<Function<T,NDIM> > result(g.size());
1303 for (auto& r : result) r.set_impl(f, false);
1304
1305 FunctionImpl<T,NDIM>* fimpl=f.get_impl().get();
1306// fimpl->make_redundant(false);
1307 fimpl->change_tree_state(redundant,false);
1308 make_redundant(world,g,false);
1309 world.gop.fence();
1310
1311 for (std::size_t i=0; i<result.size(); ++i) {
1312 FunctionImpl<T,LDIM>* gimpl=g[i].get_impl().get();
1313 result[i].get_impl()->multiply(fimpl,gimpl,particle); // stupid naming inconsistency
1314 }
1315 world.gop.fence();
1316
1317 fimpl->undo_redundant(false);
1318 for (auto& ig : g) ig.get_impl()->undo_redundant(false);
1319 world.gop.fence();
1320 return result;
1321 }
1322
1323 template<typename T, std::size_t NDIM, std::size_t LDIM>
1324 std::vector<Function<T,NDIM> > multiply(const Function<T,NDIM> f, const std::vector<Function<T,LDIM> > g,
1325 const std::tuple<int,int,int> v) {
1326 return partial_mul<T,NDIM,LDIM>(f,g,std::array<int,3>({std::get<0>(v),std::get<1>(v),std::get<2>(v)}));
1327 }
1328
1329
1330/// Computes the square of a vector of functions --- q[i] = v[i]**2
1331 template <typename T, std::size_t NDIM>
1332 std::vector< Function<T,NDIM> >
1334 const std::vector< Function<T,NDIM> >& v,
1335 bool fence=true) {
1336 return mul<T,T,NDIM>(world, v, v, fence);
1337// std::vector< Function<T,NDIM> > vsq(v.size());
1338// for (unsigned int i=0; i<v.size(); ++i) {
1339// vsq[i] = square(v[i], false);
1340// }
1341// if (fence) world.gop.fence();
1342// return vsq;
1343 }
1344
1345
1346 /// Computes the square of a vector of functions --- q[i] = abs(v[i])**2
1347 template <typename T, std::size_t NDIM>
1348 std::vector< Function<typename Tensor<T>::scalar_type,NDIM> >
1349 abssq(World& world,
1350 const std::vector< Function<T,NDIM> >& v,
1351 bool fence=true) {
1352 typedef typename Tensor<T>::scalar_type scalartype;
1353 reconstruct(world,v);
1354 std::vector<Function<scalartype,NDIM> > result(v.size());
1355 for (size_t i=0; i<v.size(); ++i) result[i]=abs_square(v[i],false);
1356 if (fence) world.gop.fence();
1357 return result;
1358 }
1359
1360
1361 /// Sets the threshold in a vector of functions
1362 template <typename T, std::size_t NDIM>
1363 void set_thresh(World& world, std::vector< Function<T,NDIM> >& v, double thresh, bool fence=true) {
1364 for (unsigned int j=0; j<v.size(); ++j) {
1365 v[j].set_thresh(thresh,false);
1366 }
1367 if (fence) world.gop.fence();
1368 }
1369
1370 /// Returns the complex conjugate of the vector of functions
1371 template <typename T, std::size_t NDIM>
1372 std::vector< Function<T,NDIM> >
1373 conj(World& world,
1374 const std::vector< Function<T,NDIM> >& v,
1375 bool fence=true) {
1377 std::vector< Function<T,NDIM> > r = copy(world, v); // Currently don't have oop conj
1378 for (unsigned int i=0; i<v.size(); ++i) {
1379 r[i].conj(false);
1380 }
1381 if (fence) world.gop.fence();
1382 return r;
1383 }
1384
1385 /// Returns a deep copy of a vector of functions
1386 template <typename T, typename R, std::size_t NDIM>
1387 std::vector< Function<R,NDIM> > convert(World& world,
1388 const std::vector< Function<T,NDIM> >& v, bool fence=true) {
1390 std::vector< Function<R,NDIM> > r(v.size());
1391 for (unsigned int i=0; i<v.size(); ++i) {
1392 r[i] = convert<T,R,NDIM>(v[i], false);
1393 }
1394 if (fence) world.gop.fence();
1395 return r;
1396 }
1397
1398
1399 /// Returns a deep copy of a vector of functions
1400 template <typename T, std::size_t NDIM>
1401 std::vector< Function<T,NDIM> >
1402 copy(World& world,
1403 const std::vector< Function<T,NDIM> >& v,
1404 bool fence=true) {
1406 std::vector< Function<T,NDIM> > r(v.size());
1407 for (unsigned int i=0; i<v.size(); ++i) {
1408 r[i] = copy(v[i], false);
1409 }
1410 if (fence) world.gop.fence();
1411 return r;
1412 }
1413
1414
1415 /// Returns a deep copy of a vector of functions
1416 template <typename T, std::size_t NDIM>
1417 std::vector< Function<T,NDIM> >
1418 copy(const std::vector< Function<T,NDIM> >& v, bool fence=true) {
1420 std::vector< Function<T,NDIM> > r(v.size());
1421 if (v.size()>0) r=copy(v.front().world(),v,fence);
1422 return r;
1423 }
1424
1425 /// Returns a vector of `n` deep copies of a function
1426 template <typename T, std::size_t NDIM>
1427 std::vector< Function<T,NDIM> >
1429 const Function<T,NDIM>& v,
1430 const unsigned int n,
1431 bool fence=true) {
1433 std::vector< Function<T,NDIM> > r(n);
1434 for (unsigned int i=0; i<n; ++i) {
1435 r[i] = copy(v, false);
1436 }
1437 if (fence) world.gop.fence();
1438 return r;
1439 }
1440
1441 /// Create a new copy of the function with different distribution and optional
1442 /// fence
1443
1444 /// Works in either basis. Different distributions imply
1445 /// asynchronous communication and the optional fence is
1446 /// collective.
1447 //
1448 /// Returns a deep copy of a vector of functions
1449
1450 template <typename T, std::size_t NDIM>
1451 std::vector<Function<T, NDIM>> copy(World& world,
1452 const std::vector<Function<T, NDIM>>& v,
1453 const std::shared_ptr<WorldDCPmapInterface<Key<NDIM>>>& pmap,
1454 bool fence = true) {
1456 std::vector<Function<T, NDIM>> r(v.size());
1457 for (unsigned int i = 0; i < v.size(); ++i) {
1458 r[i] = copy(v[i], pmap, false);
1459 }
1460 if (fence) world.gop.fence();
1461 return r;
1462 }
1463
1464 /// Returns new vector of functions --- q[i] = a[i] + b[i]
1465 template <typename T, typename R, std::size_t NDIM>
1466 std::vector< Function<TENSOR_RESULT_TYPE(T,R), NDIM> >
1467 add(World& world,
1468 const std::vector< Function<T,NDIM> >& a,
1469 const std::vector< Function<R,NDIM> >& b,
1470 bool fence=true) {
1472 MADNESS_ASSERT(a.size() == b.size());
1473 compress(world, a);
1474 compress(world, b);
1475
1476 std::vector< Function<TENSOR_RESULT_TYPE(T,R),NDIM> > r(a.size());
1477 for (unsigned int i=0; i<a.size(); ++i) {
1478 r[i] = add(a[i], b[i], false);
1479 }
1480 if (fence) world.gop.fence();
1481 return r;
1482 }
1483
1484 /// Returns new vector of functions --- q[i] = a + b[i]
1485 template <typename T, typename R, std::size_t NDIM>
1486 std::vector< Function<TENSOR_RESULT_TYPE(T,R), NDIM> >
1487 add(World& world,
1488 const Function<T,NDIM> & a,
1489 const std::vector< Function<R,NDIM> >& b,
1490 bool fence=true) {
1492 a.compress();
1493 compress(world, b);
1494
1495 std::vector< Function<TENSOR_RESULT_TYPE(T,R),NDIM> > r(b.size());
1496 for (unsigned int i=0; i<b.size(); ++i) {
1497 r[i] = add(a, b[i], false);
1498 }
1499 if (fence) world.gop.fence();
1500 return r;
1501 }
1502 template <typename T, typename R, std::size_t NDIM>
1503 inline std::vector< Function<TENSOR_RESULT_TYPE(T,R), NDIM> >
1504 add(World& world,
1505 const std::vector< Function<R,NDIM> >& b,
1506 const Function<T,NDIM> & a,
1507 bool fence=true) {
1508 return add(world, a, b, fence);
1509 }
1510
1511 /// Returns new vector of functions --- q[i] = a[i] - b[i]
1512 template <typename T, typename R, std::size_t NDIM>
1513 std::vector< Function<TENSOR_RESULT_TYPE(T,R), NDIM> >
1514 sub(World& world,
1515 const std::vector< Function<T,NDIM> >& a,
1516 const std::vector< Function<R,NDIM> >& b,
1517 bool fence=true) {
1519 MADNESS_ASSERT(a.size() == b.size());
1520 compress(world, a);
1521 compress(world, b);
1522
1523 std::vector< Function<TENSOR_RESULT_TYPE(T,R),NDIM> > r(a.size());
1524 for (unsigned int i=0; i<a.size(); ++i) {
1525 r[i] = sub(a[i], b[i], false);
1526 }
1527 if (fence) world.gop.fence();
1528 return r;
1529 }
1530
1531 /// Returns new function --- q = sum_i f[i]
1532 template <typename T, std::size_t NDIM>
1533 Function<T, NDIM> sum(World& world, const std::vector<Function<T,NDIM> >& f,
1534 bool fence=true) {
1535
1536 compress(world, f);
1538
1539 for (unsigned int i=0; i<f.size(); ++i) r.gaxpy(1.0,f[i],1.0,false);
1540 if (fence) world.gop.fence();
1541 return r;
1542 }
1543
1544 template <typename T, std::size_t NDIM>
1546 const std::vector<Function<T, NDIM>>& f,
1547 const std::vector<Function<T, NDIM>>& g,
1548 bool sym=false)
1549 {
1552 const int64_t n = A.coldim();
1553 const int64_t m = A.rowdim();
1554 MADNESS_ASSERT(int64_t(f.size()) == n && int64_t(g.size()) == m);
1555
1556 // Assume we can always create an ichunk*jchunk matrix locally
1557 const int ichunk = 1000;
1558 const int jchunk = 1000; // 1000*1000*8 = 8 MBytes
1559 for (int64_t ilo = 0; ilo < n; ilo += ichunk) {
1560 int64_t ihi = std::min(ilo + ichunk, n);
1561 std::vector<Function<T, NDIM>> ivec(f.begin() + ilo, f.begin() + ihi);
1562 for (int64_t jlo = 0; jlo < m; jlo += jchunk) {
1563 int64_t jhi = std::min(jlo + jchunk, m);
1564 std::vector<Function<T, NDIM>> jvec(g.begin() + jlo, g.begin() + jhi);
1565
1566 Tensor<T> P = matrix_dot(A.get_world(), ivec, jvec, sym);
1567 A.copy_from_replicated_patch(ilo, ihi - 1, jlo, jhi - 1, P);
1568 }
1569 }
1570 return A;
1571 }
1572
1573 /// Computes the matrix dot product of two function vectors - q(i,j) = dot(f[i],g[j])
1574
1575 /// For complex types symmetric is interpreted as Hermitian.
1576 ///
1577 /// The current parallel loop is non-optimal but functional.
1578 template <typename T, typename R, std::size_t NDIM>
1580 const std::vector<Function<T, NDIM>>& f,
1581 const std::vector<Function<R, NDIM>>& g,
1582 bool sym=false)
1583 {
1584 world.gop.fence();
1585 compress(world, f);
1586 // if ((void*)(&f) != (void*)(&g)) compress(world, g);
1587 compress(world, g);
1588
1589 std::vector<const FunctionImpl<T, NDIM>*> left(f.size());
1590 std::vector<const FunctionImpl<R, NDIM>*> right(g.size());
1591 for (unsigned int i = 0; i < f.size(); i++) left[i] = f[i].get_impl().get();
1592 for (unsigned int i = 0; i < g.size(); i++) right[i] = g[i].get_impl().get();
1593
1595
1596 world.gop.fence();
1597 world.gop.sum(r.ptr(), f.size() * g.size());
1598
1599 return r;
1600 }
1601
1602 /// Computes the matrix dot product of two function vectors - q(i,j) = dot(f[i],g[j])
1603
1604 /// For complex types symmetric is interpreted as Hermitian.
1605 ///
1606 /// The current parallel loop is non-optimal but functional.
1607 template <typename T, typename R, std::size_t NDIM>
1609 const std::vector< Function<T,NDIM> >& f,
1610 const std::vector< Function<R,NDIM> >& g,
1611 bool sym=false) {
1613 long n=f.size(), m=g.size();
1614 Tensor< TENSOR_RESULT_TYPE(T,R) > r(n,m);
1615 if (sym) MADNESS_ASSERT(n==m);
1616
1617 world.gop.fence();
1618 compress(world, f);
1619 if ((void*)(&f) != (void*)(&g)) compress(world, g);
1620
1621 for (long i=0; i<n; ++i) {
1622 long jtop = m;
1623 if (sym) jtop = i+1;
1624 for (long j=0; j<jtop; ++j) {
1625 if (sym) {
1626 r(j,i) = f[i].dot_local(g[j]);
1627 if (i != j)
1628 r(i,j) = conj(r(j,i));
1629 } else
1630 r(i,j) = f[i].dot_local(g[j]);
1631 }
1632 }
1633
1634 world.gop.fence();
1635 world.gop.sum(r.ptr(),n*m);
1636
1637 return r;
1638 }
1639
1640 /// Multiplies and sums two vectors of functions r = \sum_i a[i] * b[i]
1641
1642 /// @param[in] tol 0 (the default) multiplies exactly; see mul_sparse to screen
1643 template <typename T, typename R, std::size_t NDIM>
1644 Function<TENSOR_RESULT_TYPE(T,R), NDIM>
1645 dot(World& world,
1646 const std::vector< Function<T,NDIM> >& a,
1647 const std::vector< Function<R,NDIM> >& b,
1648 bool fence=true,
1649 bool do_make_redundant=true,
1650 double tol=0.0) {
1651 MADNESS_CHECK(a.size()==b.size());
1652 return sum(world,mul(world,a,b,true,do_make_redundant,tol),fence);
1653 }
1654
1655
1656
1657 /// out-of-place gaxpy for two vectors: result[i] = alpha * a[i] + beta * b[i]
1658 template <typename T, typename Q, typename R, std::size_t NDIM>
1659 std::vector<Function<TENSOR_RESULT_TYPE(Q,TENSOR_RESULT_TYPE(T,R)),NDIM> >
1661 const std::vector< Function<T,NDIM> >& a,
1662 Q beta,
1663 const std::vector< Function<R,NDIM> >& b,
1664 bool fence=true) {
1665
1666 MADNESS_ASSERT(a.size() == b.size());
1667 typedef TENSOR_RESULT_TYPE(Q,TENSOR_RESULT_TYPE(T,R)) resultT;
1668 if (a.size()==0) return std::vector<Function<resultT,NDIM> >();
1669
1670 auto tensor_type = [](const std::vector<Function<T,NDIM>>& v) {
1671 return v.front().get_impl()->get_tensor_type();
1672 };
1673
1674 // gaxpy can be done either in reconstructed or in compressed state
1675 World& world=a[0].world();
1676 std::vector<Function<resultT,NDIM> > result(a.size());
1677
1678 TreeState operating_state=tensor_type(a)==TT_FULL ? compressed : reconstructed;
1679 try {
1680 ensure_tree_state_respecting_fence(a,operating_state,fence);
1681 ensure_tree_state_respecting_fence(b,operating_state,fence);
1682 } catch (...) {
1683 print("could not respect fence in gaxpy");
1684 change_tree_state(a,operating_state,true);
1685 change_tree_state(b,operating_state,true);
1686 }
1687
1688 if (operating_state==compressed) {
1689 for (unsigned int i=0; i<a.size(); ++i) result[i]=gaxpy_oop(alpha, a[i], beta, b[i], false);
1690 } else {
1691 for (unsigned int i=0; i<a.size(); ++i) result[i]=gaxpy_oop_reconstructed(alpha, a[i], beta, b[i], false);
1692 }
1693
1694 if (fence) world.gop.fence();
1695 return result;
1696 }
1697
1698
1699 /// out-of-place gaxpy for a vectors and a function: result[i] = alpha * a[i] + beta * b
1700 template <typename T, typename Q, typename R, std::size_t NDIM>
1701 std::vector<Function<TENSOR_RESULT_TYPE(Q,TENSOR_RESULT_TYPE(T,R)),NDIM> >
1703 const std::vector< Function<T,NDIM> >& a,
1704 Q beta,
1705 const Function<R,NDIM>& b,
1706 bool fence=true) {
1707
1708 typedef TENSOR_RESULT_TYPE(Q,TENSOR_RESULT_TYPE(T,R)) resultT;
1709 if (a.size()==0) return std::vector<Function<resultT,NDIM> >();
1710
1711 World& world=a[0].world();
1712 try {
1714 // ensure_tree_state_respecting_fence({b},compressed,fence);
1716 } catch (...) {
1717 print("could not respect fence in gaxpy_oop");
1718 compress(world,a);
1719 b.compress();
1720 }
1721 std::vector<Function<resultT,NDIM> > result(a.size());
1722 for (unsigned int i=0; i<a.size(); ++i) {
1723 result[i]=gaxpy_oop(alpha, a[i], beta, b, false);
1724 }
1725 if (fence) world.gop.fence();
1726 return result;
1727 }
1728
1729
1730 /// Generalized A*X+Y for vectors of functions ---- a[i] = alpha*a[i] + beta*b[i]
1731 template <typename T, typename Q, typename R, std::size_t NDIM>
1732 void gaxpy(Q alpha, std::vector<Function<T,NDIM>>& a, Q beta, const std::vector<Function<R,NDIM>>& b, const bool fence) {
1733 if (a.size() == 0) return;
1734 World& world=a.front().world();
1735 gaxpy(world,alpha,a,beta,b,fence);
1736 }
1737
1738 /// Generalized A*X+Y for vectors of functions ---- a[i] = alpha*a[i] + beta*b[i]
1739 template <typename T, typename Q, typename R, std::size_t NDIM>
1740 void gaxpy(World& world,
1741 Q alpha,
1742 std::vector< Function<T,NDIM> >& a,
1743 Q beta,
1744 const std::vector< Function<R,NDIM> >& b,
1745 bool fence=true) {
1747 MADNESS_ASSERT(a.size() == b.size());
1748 if (a.empty()) return;
1749
1750 auto tensor_type = [](const std::vector<Function<T,NDIM>>& v) {
1751 return v.front().get_impl()->get_tensor_type();
1752 };
1753
1754 // gaxpy can be done either in reconstructed or in compressed state
1755 bool do_in_reconstructed_state=tensor_type(a)!=TT_FULL;
1757
1758 if (operating_state==compressed) {
1759 // this is strict: both vectors have to be compressed
1760 try {
1761 ensure_tree_state_respecting_fence(a,operating_state,fence);
1762 ensure_tree_state_respecting_fence(b,operating_state,fence);
1763 } catch (...) {
1764 print("could not respect fence in gaxpy");
1765 change_tree_state(a,operating_state,true);
1766 change_tree_state(b,operating_state,true);
1767 }
1768 MADNESS_CHECK_THROW(get_tree_state(a)==get_tree_state(b),"gaxpy requires same tree state for all functions");
1769 MADNESS_CHECK_THROW(get_tree_state(a)==operating_state,"gaxpy requires reconstructed/compressed tree state for all functions");
1770 } else {
1771 // both vectors can be reconstructed or redundant_after_merge, and they don't have to be the same
1775 try {
1776 ensure_tree_state_respecting_fence(a,operating_state,fence);
1777 } catch (...) {
1778 print("could not respect fence in gaxpy for a");
1780 }
1781 }
1783 try {
1784 ensure_tree_state_respecting_fence(b,operating_state,fence);
1785 } catch (...) {
1786 print("could not respect fence in gaxpy for b");
1788 }
1789 }
1790 }
1791
1792 // finally do the work
1793 for (unsigned int i=0; i<a.size(); ++i) {
1794 a[i].gaxpy(alpha, b[i], beta, false);
1795 }
1796 if (fence and (get_tree_state(a)==redundant_after_merge)) {
1797 for (unsigned int i=0; i<a.size(); ++i) a[i].get_impl()->finalize_sum();
1798 }
1799
1800 if (fence) world.gop.fence();
1801 }
1802
1803
1804 /// Applies a vector of operators to a vector of functions --- q[i] = apply(op[i],f[i])
1805 template <typename opT, typename R, std::size_t NDIM>
1806 std::vector< Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM> >
1807 apply(World& world,
1808 const std::vector< std::shared_ptr<opT> >& op,
1809 const std::vector< Function<R,NDIM> > f) {
1810
1812 MADNESS_ASSERT(f.size()==op.size());
1813
1814 std::vector< Function<R,NDIM> >& ncf = *const_cast< std::vector< Function<R,NDIM> >* >(&f);
1815
1816// reconstruct(world, f);
1817 make_nonstandard(world, ncf);
1818
1819 std::vector< Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM> > result(f.size());
1820 for (unsigned int i=0; i<f.size(); ++i) {
1821 result[i] = apply_only(*op[i], f[i], false);
1822 result[i].get_impl()->set_tree_state(nonstandard_after_apply);
1823 }
1824
1825 world.gop.fence();
1826
1827 standard(world, ncf, false); // restores promise of logical constness
1828 reconstruct(result);
1829 world.gop.fence();
1830
1831 return result;
1832 }
1833
1834
1835 /// Applies an operator to a vector of functions --- q[i] = apply(op,f[i])
1836 template <typename T, typename R, std::size_t NDIM, std::size_t KDIM>
1837 std::vector< Function<TENSOR_RESULT_TYPE(T,R), NDIM> >
1839 const std::vector< Function<R,NDIM> > f) {
1840 return apply(op.get_world(),op,f);
1841 }
1842
1843
1844 /// Applies an operator to a vector of functions --- q[i] = apply(op,f[i])
1845 template <typename T, typename R, std::size_t NDIM, std::size_t KDIM>
1846 std::vector< Function<TENSOR_RESULT_TYPE(T,R), NDIM> >
1847 apply(World& world,
1849 const std::vector< Function<R,NDIM> > f) {
1851
1852 std::vector< Function<R,NDIM> >& ncf = *const_cast< std::vector< Function<R,NDIM> >* >(&f);
1853 bool print_timings=(NDIM==6) and (world.rank()==0) and op.print_timings;
1854
1855 double wall0=wall_time();
1856// reconstruct(world, f);
1857 make_nonstandard(world, ncf);
1858 double wall1=wall_time();
1859 if (print_timings) printf("timer: %20.20s %8.2fs\n", "make_nonstandard", wall1-wall0);
1860
1861 std::vector< Function<TENSOR_RESULT_TYPE(T,R), NDIM> > result(f.size());
1862 for (unsigned int i=0; i<f.size(); ++i) {
1863 result[i] = apply_only(op, f[i], false);
1864 }
1865
1866 world.gop.fence();
1867
1868 // restores promise of logical constness
1869 if (op.destructive()) {
1870 for (auto& ff : ncf) ff.clear(false);
1871 world.gop.fence();
1872 } else {
1873 reconstruct(world,f);
1874 }
1875
1876 // svd-tensor requires some cleanup after apply
1877 if (result[0].get_impl()->get_tensor_type()==TT_2D) {
1878 for (auto& r : result) r.get_impl()->finalize_apply();
1879 }
1880
1881 if (print_timings) {
1882 for (auto& r : result) r.get_impl()->print_timer();
1883 op.print_timer();
1884 }
1885 reconstruct(world, result);
1886
1887 return result;
1888 }
1889
1890 /// Normalizes a vector of functions --- v[i] = v[i].scale(1.0/v[i].norm2())
1891 template <typename T, std::size_t NDIM>
1892 void normalize(World& world, std::vector< Function<T,NDIM> >& v, bool fence=true) {
1894 std::vector<double> nn = norm2s(world, v);
1895 for (unsigned int i=0; i<v.size(); ++i) v[i].scale(1.0/nn[i],false);
1896 if (fence) world.gop.fence();
1897 }
1898
1899 template <typename T, std::size_t NDIM>
1900 void print_size(World &world, const std::vector<Function<T,NDIM> > &v, const std::string &msg = "vectorfunction" ){
1901 if(v.empty()){
1902 if(world.rank()==0) std::cout << "print_size: " << msg << " is empty" << std::endl;
1903 }else if(v.size()==1){
1904 v.front().print_size(msg);
1905 }else{
1906 for(auto x:v){
1907 // print("impl",x.get_impl().get());
1908 x.print_size(msg);
1909 }
1910 }
1911 }
1912
1913 /// return the size of a vector of functions for each rank
1914 template <typename T, std::size_t NDIM>
1915 double get_size_local(World& world, const std::vector< Function<T,NDIM> >& v){
1916 double size=0.0;
1917 for(auto x:v){
1918 if (x.is_initialized()) size+=x.size_local();
1919 }
1920 const double d=sizeof(T);
1921 const double fac=1024*1024*1024;
1922 return size/fac*d;
1923 }
1924
1925 /// return the size of a function for each rank
1926 template <typename T, std::size_t NDIM>
1928 return get_size_local(f.world(),std::vector<Function<T,NDIM> >(1,f));
1929 }
1930
1931
1932 // gives back the size in GB
1933 template <typename T, std::size_t NDIM>
1934 double get_size(World& world, const std::vector< Function<T,NDIM> >& v){
1935
1936 if (v.empty()) return 0.0;
1937
1938 const double d=sizeof(T);
1939 const double fac=1024*1024*1024;
1940
1941 double size=0.0;
1942 for(unsigned int i=0;i<v.size();i++){
1943 if (v[i].is_initialized()) size+=v[i].size();
1944 }
1945
1946 return size/fac*d;
1947
1948 }
1949
1950 // gives back the size in GB
1951 template <typename T, std::size_t NDIM>
1952 double get_size(const Function<T,NDIM> & f){
1953 const double d=sizeof(T);
1954 const double fac=1024*1024*1024;
1955 double size=f.size();
1956 return size/fac*d;
1957 }
1958
1959 /// apply op on the input vector yielding an output vector of functions
1960
1961 /// @param[in] op the operator working on vin
1962 /// @param[in] vin vector of input Functions; needs to be refined to common level!
1963 /// @return vector of output Functions vout = op(vin)
1964 template <typename T, typename opT, std::size_t NDIM>
1965 std::vector<Function<T,NDIM> > multi_to_multi_op_values(const opT& op,
1966 const std::vector< Function<T,NDIM> >& vin,
1967 const bool fence=true) {
1968 MADNESS_ASSERT(vin.size()>0);
1969 MADNESS_ASSERT(vin[0].is_initialized()); // might be changed
1970 World& world=vin[0].world();
1972 dummy.set_impl(vin[0], false);
1973 std::vector<Function<T,NDIM> > vout=zero_functions<T,NDIM>(world, op.get_result_size());
1974 for (auto& out : vout) out.set_impl(vin[0],false);
1975 dummy.multi_to_multi_op_values(op, vin, vout, fence);
1976 return vout;
1977 }
1978
1979
1980
1981
1982 // convenience operators
1983
1984 /// result[i] = a[i] + b[i]
1985 template <typename T, std::size_t NDIM>
1986 std::vector<Function<T,NDIM> > operator+(const std::vector<Function<T,NDIM> >& lhs,
1987 const std::vector<Function<T,NDIM>>& rhs) {
1988 MADNESS_CHECK(lhs.size() == rhs.size());
1989 return gaxpy_oop(1.0,lhs,1.0,rhs);
1990 }
1991
1992 /// result[i] = a[i] - b[i]
1993 template <typename T, std::size_t NDIM>
1994 std::vector<Function<T,NDIM> > operator-(const std::vector<Function<T,NDIM> >& lhs,
1995 const std::vector<Function<T,NDIM> >& rhs) {
1996 MADNESS_CHECK(lhs.size() == rhs.size());
1997 return gaxpy_oop(1.0,lhs,-1.0,rhs);
1998 }
1999
2000 /// result[i] = a[i] + b
2001 template <typename T, std::size_t NDIM>
2002 std::vector<Function<T,NDIM> > operator+(const std::vector<Function<T,NDIM> >& lhs,
2003 const Function<T,NDIM>& rhs) {
2004 // MADNESS_CHECK(lhs.size() == rhs.size()); // no!!
2005 return gaxpy_oop(1.0,lhs,1.0,rhs);
2006 }
2007
2008 /// result[i] = a[i] - b
2009 template <typename T, std::size_t NDIM>
2010 std::vector<Function<T,NDIM> > operator-(const std::vector<Function<T,NDIM> >& lhs,
2011 const Function<T,NDIM>& rhs) {
2012 // MADNESS_CHECK(lhs.size() == rhs.size()); // no
2013 return gaxpy_oop(1.0,lhs,-1.0,rhs);
2014 }
2015
2016 /// result[i] = a + b[i]
2017 template <typename T, std::size_t NDIM>
2018 std::vector<Function<T,NDIM> > operator+(const Function<T,NDIM>& lhs,
2019 const std::vector<Function<T,NDIM> >& rhs) {
2020 // MADNESS_CHECK(lhs.size() == rhs.size()); // no
2021 return gaxpy_oop(1.0,rhs,1.0,lhs);
2022 }
2023
2024 /// result[i] = a - b[i]
2025 template <typename T, std::size_t NDIM>
2026 std::vector<Function<T,NDIM> > operator-(const Function<T,NDIM>& lhs,
2027 const std::vector<Function<T,NDIM> >& rhs) {
2028// MADNESS_CHECK(lhs.size() == rhs.size()); // no
2029 return gaxpy_oop(-1.0,rhs,1.0,lhs);
2030 }
2031
2032
2033 template <typename T, typename R, std::size_t NDIM>
2034 std::vector<Function<TENSOR_RESULT_TYPE(T,R),NDIM> > operator*(const R fac,
2035 const std::vector<Function<T,NDIM> >& rhs) {
2036 if (rhs.size()>0) {
2037 std::vector<Function<T,NDIM> > tmp=copy(rhs[0].world(),rhs);
2038 scale(tmp[0].world(),tmp,TENSOR_RESULT_TYPE(T,R)(fac));
2039 return tmp;
2040 }
2041 return std::vector<Function<TENSOR_RESULT_TYPE(T,R),NDIM> >();
2042 }
2043
2044 template <typename T, typename R, std::size_t NDIM>
2045 std::vector<Function<T,NDIM> > operator*(const std::vector<Function<T,NDIM> >& rhs,
2046 const R fac) {
2047 if (rhs.size()>0) {
2048 std::vector<Function<TENSOR_RESULT_TYPE(T,R),NDIM> > tmp=copy(rhs[0].world(),rhs);
2049 scale(tmp[0].world(),tmp,TENSOR_RESULT_TYPE(T,R)(fac));
2050 return tmp;
2051 }
2052 return std::vector<Function<TENSOR_RESULT_TYPE(T,R),NDIM> >();
2053 }
2054
2055 /// multiply a vector of functions with a function: r[i] = v[i] * a
2056 template <typename T, typename R, std::size_t NDIM>
2058 const std::vector<Function<R,NDIM> >& v) {
2059 if (v.size()>0) return mul(v[0].world(),a,v,true);
2060 return std::vector<Function<TENSOR_RESULT_TYPE(T,R),NDIM> >();
2061 }
2062
2063
2064 /// multiply a vector of functions with a function: r[i] = a * v[i]
2065 template <typename T, typename R, std::size_t NDIM>
2066 std::vector<Function<TENSOR_RESULT_TYPE(T,R),NDIM> > operator*(const std::vector<Function<T,NDIM> >& v,
2067 const Function<R,NDIM>& a) {
2068 if (v.size()>0) return mul(v[0].world(),a,v,true);
2069 return std::vector<Function<TENSOR_RESULT_TYPE(T,R),NDIM> >();
2070 }
2071
2072
2073 template <typename T, std::size_t NDIM>
2074 std::vector<Function<T,NDIM> > operator+=(std::vector<Function<T,NDIM> >& lhs, const std::vector<Function<T,NDIM> >& rhs) {
2075 MADNESS_CHECK(lhs.size() == rhs.size());
2076 if (lhs.size() > 0) gaxpy(lhs.front().world(), 1.0, lhs, 1.0, rhs);
2077 return lhs;
2078 }
2079
2080 template <typename T, std::size_t NDIM>
2081 std::vector<Function<T,NDIM> > operator-=(std::vector<Function<T,NDIM> >& lhs,
2082 const std::vector<Function<T,NDIM> >& rhs) {
2083 MADNESS_CHECK(lhs.size() == rhs.size());
2084 if (lhs.size() > 0) gaxpy(lhs.front().world(), 1.0, lhs, -1.0, rhs);
2085 return lhs;
2086 }
2087
2088 /// return the real parts of the vector's function (if complex)
2089 template <typename T, std::size_t NDIM>
2090 std::vector<Function<typename Tensor<T>::scalar_type,NDIM> >
2091 real(const std::vector<Function<T,NDIM> >& v, bool fence=true) {
2092 std::vector<Function<typename Tensor<T>::scalar_type,NDIM> > result(v.size());
2093 for (std::size_t i=0; i<v.size(); ++i) result[i]=real(v[i],false);
2094 if (fence and result.size()>0) result[0].world().gop.fence();
2095 return result;
2096 }
2097
2098 /// return the imaginary parts of the vector's function (if complex)
2099 template <typename T, std::size_t NDIM>
2100 std::vector<Function<typename Tensor<T>::scalar_type,NDIM> >
2101 imag(const std::vector<Function<T,NDIM> >& v, bool fence=true) {
2102 std::vector<Function<typename Tensor<T>::scalar_type,NDIM> > result(v.size());
2103 for (std::size_t i=0; i<v.size(); ++i) result[i]=imag(v[i],false);
2104 if (fence and result.size()>0) result[0].world().gop.fence();
2105 return result;
2106 }
2107
2108 /// shorthand gradient operator
2109
2110 /// returns the differentiated function f in all NDIM directions
2111 /// @param[in] f the function on which the grad operator works on
2112 /// @param[in] refine refinement before diff'ing makes the result more accurate
2113 /// @param[in] fence fence after completion; if reconstruction is needed always fence
2114 /// @return the vector \frac{\partial}{\partial x_i} f
2115 template <typename T, std::size_t NDIM>
2116 std::vector<Function<T,NDIM> > grad(const Function<T,NDIM>& f,
2117 bool refine=false, bool fence=true) {
2118
2119 World& world=f.world();
2120 f.reconstruct();
2121 if (refine) f.refine(); // refine to make result more precise
2122
2123 std::vector< std::shared_ptr< Derivative<T,NDIM> > > grad=
2125
2126 std::vector<Function<T,NDIM> > result(NDIM);
2127 for (size_t i=0; i<NDIM; ++i) result[i]=apply(*(grad[i]),f,false);
2128 if (fence) world.gop.fence();
2129 return result;
2130 }
2131
2132 // BLM first derivative
2133 template <typename T, std::size_t NDIM>
2134 std::vector<Function<T,NDIM> > grad_ble_one(const Function<T,NDIM>& f,
2135 bool refine=false, bool fence=true) {
2136
2137 World& world=f.world();
2138 f.reconstruct();
2139 if (refine) f.refine(); // refine to make result more precise
2140
2141 std::vector< std::shared_ptr< Derivative<T,NDIM> > > grad=
2143
2144 // Read in new coeff for each operator
2145 for (unsigned int i=0; i<NDIM; ++i) (*grad[i]).set_ble1();
2146
2147 std::vector<Function<T,NDIM> > result(NDIM);
2148 for (unsigned int i=0; i<NDIM; ++i) result[i]=apply(*(grad[i]),f,false);
2149 if (fence) world.gop.fence();
2150 return result;
2151 }
2152
2153 // BLM second derivative
2154 template <typename T, std::size_t NDIM>
2155 std::vector<Function<T,NDIM> > grad_ble_two(const Function<T,NDIM>& f,
2156 bool refine=false, bool fence=true) {
2157
2158 World& world=f.world();
2159 f.reconstruct();
2160 if (refine) f.refine(); // refine to make result more precise
2161
2162 std::vector< std::shared_ptr< Derivative<T,NDIM> > > grad=
2164
2165 // Read in new coeff for each operator
2166 for (unsigned int i=0; i<NDIM; ++i) (*grad[i]).set_ble2();
2167
2168 std::vector<Function<T,NDIM> > result(NDIM);
2169 for (unsigned int i=0; i<NDIM; ++i) result[i]=apply(*(grad[i]),f,false);
2170 if (fence) world.gop.fence();
2171 return result;
2172 }
2173
2174 // Bspline first derivative
2175 template <typename T, std::size_t NDIM>
2176 std::vector<Function<T,NDIM> > grad_bspline_one(const Function<T,NDIM>& f,
2177 bool refine=false, bool fence=true) {
2178
2179 World& world=f.world();
2180 f.reconstruct();
2181 if (refine) f.refine(); // refine to make result more precise
2182
2183 std::vector< std::shared_ptr< Derivative<T,NDIM> > > grad=
2185
2186 // Read in new coeff for each operator
2187 for (unsigned int i=0; i<NDIM; ++i) (*grad[i]).set_bspline1();
2188
2189 std::vector<Function<T,NDIM> > result(NDIM);
2190 for (unsigned int i=0; i<NDIM; ++i) result[i]=apply(*(grad[i]),f,false);
2191 if (fence) world.gop.fence();
2192 return result;
2193 }
2194
2195 // Bpsline second derivative
2196 template <typename T, std::size_t NDIM>
2197 std::vector<Function<T,NDIM> > grad_bpsline_two(const Function<T,NDIM>& f,
2198 bool refine=false, bool fence=true) {
2199
2200 World& world=f.world();
2201 f.reconstruct();
2202 if (refine) f.refine(); // refine to make result more precise
2203
2204 std::vector< std::shared_ptr< Derivative<T,NDIM> > > grad=
2206
2207 // Read in new coeff for each operator
2208 for (unsigned int i=0; i<NDIM; ++i) (*grad[i]).set_bspline2();
2209
2210 std::vector<Function<T,NDIM> > result(NDIM);
2211 for (unsigned int i=0; i<NDIM; ++i) result[i]=apply(*(grad[i]),f,false);
2212 if (fence) world.gop.fence();
2213 return result;
2214 }
2215
2216 // Bspline third derivative
2217 template <typename T, std::size_t NDIM>
2218 std::vector<Function<T,NDIM> > grad_bspline_three(const Function<T,NDIM>& f,
2219 bool refine=false, bool fence=true) {
2220
2221 World& world=f.world();
2222 f.reconstruct();
2223 if (refine) f.refine(); // refine to make result more precise
2224
2225 std::vector< std::shared_ptr< Derivative<T,NDIM> > > grad=
2227
2228 // Read in new coeff for each operator
2229 for (unsigned int i=0; i<NDIM; ++i) (*grad[i]).set_bspline3();
2230
2231 std::vector<Function<T,NDIM> > result(NDIM);
2232 for (unsigned int i=0; i<NDIM; ++i) result[i]=apply(*(grad[i]),f,false);
2233 if (fence) world.gop.fence();
2234 return result;
2235 }
2236
2237
2238
2239 /// shorthand div operator
2240
2241 /// returns the dot product of nabla with a vector f
2242 /// @param[in] f the vector of functions on which the div operator works on
2243 /// @param[in] refine refinement before diff'ing makes the result more accurate
2244 /// @param[in] fence fence after completion; currently always fences
2245 /// @return the vector \frac{\partial}{\partial x_i} f
2246 /// TODO: add this to operator fusion
2247 template <typename T, std::size_t NDIM>
2249 bool do_refine=false, bool fence=true) {
2250
2251 MADNESS_ASSERT(v.size()>0);
2252 World& world=v[0].world();
2253 reconstruct(world,v);
2254 if (do_refine) refine(world,v); // refine to make result more precise
2255
2256 std::vector< std::shared_ptr< Derivative<T,NDIM> > > grad=
2258
2259 std::vector<Function<T,NDIM> > result(NDIM);
2260 for (size_t i=0; i<NDIM; ++i) result[i]=apply(*(grad[i]),v[i],false);
2261 world.gop.fence();
2262 return sum(world,result,fence);
2263 }
2264
2265 /// shorthand rot operator
2266
2267 /// returns the cross product of nabla with a vector f
2268 /// @param[in] f the vector of functions on which the rot operator works on
2269 /// @param[in] refine refinement before diff'ing makes the result more accurate
2270 /// @param[in] fence fence after completion; currently always fences
2271 /// @return the vector \frac{\partial}{\partial x_i} f
2272 /// TODO: add this to operator fusion
2273 template <typename T, std::size_t NDIM>
2274 std::vector<Function<T,NDIM> > rot(const std::vector<Function<T,NDIM> >& v,
2275 bool do_refine=false, bool fence=true) {
2276
2277 MADNESS_ASSERT(v.size()==3);
2278 World& world=v[0].world();
2279 reconstruct(world,v);
2280 if (do_refine) refine(world,v); // refine to make result more precise
2281
2282 std::vector< std::shared_ptr< Derivative<T,NDIM> > > grad=
2284
2285 std::vector<Function<T,NDIM> > d(NDIM),dd(NDIM);
2286 d[0]=apply(*(grad[1]),v[2],false); // Dy z
2287 d[1]=apply(*(grad[2]),v[0],false); // Dz x
2288 d[2]=apply(*(grad[0]),v[1],false); // Dx y
2289 dd[0]=apply(*(grad[2]),v[1],false); // Dz y
2290 dd[1]=apply(*(grad[0]),v[2],false); // Dx z
2291 dd[2]=apply(*(grad[1]),v[0],false); // Dy x
2292 world.gop.fence();
2293
2294 compress(world,d,false);
2295 compress(world,dd,false);
2296 world.gop.fence();
2297 d[0].gaxpy(1.0,dd[0],-1.0,false);
2298 d[1].gaxpy(1.0,dd[1],-1.0,false);
2299 d[2].gaxpy(1.0,dd[2],-1.0,false);
2300
2301 world.gop.fence();
2302 reconstruct(d);
2303 return d;
2304 }
2305
2306 /// shorthand cross operator
2307
2308 /// returns the cross product of vectors f and g
2309 /// @param[in] f the vector of functions on which the rot operator works on
2310 /// @param[in] g the vector of functions on which the rot operator works on
2311 /// @param[in] fence fence after completion; currently always fences
2312 /// @return the vector \frac{\partial}{\partial x_i} f
2313 /// TODO: add this to operator fusion
2314 template <typename T, typename R, std::size_t NDIM>
2315 std::vector<Function<TENSOR_RESULT_TYPE(T,R),NDIM> > cross(const std::vector<Function<T,NDIM> >& f,
2316 const std::vector<Function<R,NDIM> >& g,
2317 bool do_refine=false, bool fence=true) {
2318
2319 MADNESS_ASSERT(f.size()==3);
2320 MADNESS_ASSERT(g.size()==3);
2321 World& world=f[0].world();
2322 reconstruct(world,f,false);
2323 reconstruct(world,g);
2324
2325 std::vector<Function<TENSOR_RESULT_TYPE(T,R),NDIM> > d(f.size()),dd(f.size());
2326
2327 d[0]=mul(f[1],g[2],false);
2328 d[1]=mul(f[2],g[0],false);
2329 d[2]=mul(f[0],g[1],false);
2330
2331 dd[0]=mul(f[2],g[1],false);
2332 dd[1]=mul(f[0],g[2],false);
2333 dd[2]=mul(f[1],g[0],false);
2334 world.gop.fence();
2335
2336 compress(world,d,false);
2337 compress(world,dd);
2338
2339 d[0].gaxpy(1.0,dd[0],-1.0,false);
2340 d[1].gaxpy(1.0,dd[1],-1.0,false);
2341 d[2].gaxpy(1.0,dd[2],-1.0,false);
2342
2343
2344 world.gop.fence();
2345 return d;
2346 }
2347
2348 template<typename T, std::size_t NDIM>
2349 void load_balance(World& world, std::vector<Function<T,NDIM> >& vf) {
2350
2351 struct LBCost {
2352 LBCost() = default;
2353 double operator()(const Key<NDIM>& key, const FunctionNode<T,NDIM>& node) const {
2354 return node.coeff().size();
2355 }
2356 };
2357
2358 LoadBalanceDeux<6> lb(world);
2359 for (const auto& f : vf) lb.add_tree(f, LBCost());
2361
2362 }
2363
2364 /// load a vector of functions
2365 template<typename T, size_t NDIM>
2366 void load_function(World& world, std::vector<Function<T,NDIM> >& f,
2367 const std::string name) {
2368 if (world.rank()==0) print("loading vector of functions",name);
2370 std::size_t fsize=0;
2371 ar & fsize;
2372 f.resize(fsize);
2373 for (std::size_t i=0; i<fsize; ++i) ar & f[i];
2374 }
2375
2376 /// save a vector of functions
2377 template<typename T, size_t NDIM>
2378 void save_function(const std::vector<Function<T,NDIM> >& f, const std::string name) {
2379 if (f.size()>0) {
2380 World& world=f.front().world();
2381 if (world.rank()==0) print("saving vector of functions",name);
2383 std::size_t fsize=f.size();
2384 ar & fsize;
2385 for (std::size_t i=0; i<fsize; ++i) ar & f[i];
2386 }
2387 }
2388
2389
2390}
2391#endif // MADNESS_MRA_VMRA_H__INCLUDED
double q(double t)
Definition DKops.h:18
Definition test_ar.cc:118
long size() const
Returns the number of elements in the tensor.
Definition basetensor.h:138
Implements derivatives operators with variety of boundary conditions on simulation domain.
Definition derivative.h:329
Definition distributed_matrix.h:68
Manages data associated with a row/column/block distributed array.
Definition distributed_matrix.h:388
static void redistribute(World &world, const std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > &newpmap)
Sets the default process map and redistributes all functions using the old map.
Definition funcdefaults.h:442
static TensorType get_tensor_type()
Returns the default tensor type.
Definition funcdefaults.h:323
FunctionFactory implements the named-parameter idiom for Function.
Definition function_factory.h:86
FunctionImpl holds all Function state to facilitate shallow copy semantics.
Definition funcimpl.h:968
static Tensor< TENSOR_RESULT_TYPE(T, R) > inner_local(const std::vector< const FunctionImpl< T, NDIM > * > &left, const std::vector< const FunctionImpl< R, NDIM > * > &right, bool sym)
Definition funcimpl.h:6214
void undo_redundant(const bool fence)
convert this from redundant to standard reconstructed form
Definition mraimpl.h:1559
void multiply(const implT *f, const FunctionImpl< T, LDIM > *g, const int particle)
multiply f (a pair function of NDIM) with an orbital g (LDIM=NDIM/2)
Definition funcimpl.h:3786
void change_tree_state(const TreeState finalstate, bool fence=true)
change the tree state of this function, might or might not respect fence!
Definition mraimpl.h:1421
static Tensor< TENSOR_RESULT_TYPE(T, R)> dot_local(const std::vector< const FunctionImpl< T, NDIM > * > &left, const std::vector< const FunctionImpl< R, NDIM > * > &right, bool sym)
Definition funcimpl.h:6266
FunctionNode holds the coefficients, etc., at each node of the 2^NDIM-tree.
Definition funcimpl.h:136
coeffT & coeff()
Returns a non-const reference to the tensor containing the coeffs.
Definition funcimpl.h:237
A multiresolution adaptive numerical function.
Definition mra.h:144
bool compressed
Definition mra.h:1267
Function< T, NDIM > & gaxpy(const T &alpha, const Function< Q, NDIM > &other, const R &beta, bool fence=true)
Inplace, general bi-linear operation in wavelet basis. No communication except for optional fence.
Definition mra.h:1124
void set_impl(const std::shared_ptr< FunctionImpl< T, NDIM > > &impl)
Replace current FunctionImpl with provided new one.
Definition mra.h:731
long size() const
Definition lowranktensor.h:488
Key is the index for a node of the 2^NDIM-tree.
Definition key.h:70
Definition lbdeux.h:233
std::shared_ptr< WorldDCPmapInterface< keyT > > load_balance(double fac=1.0, bool printstuff=false)
Actually does the partitioning of the tree.
Definition lbdeux.h:390
void add_tree(const Function< T, NDIM > &f, const costT &costfn, bool fence=false)
Accumulates cost from a function.
Definition lbdeux.h:294
Convolutions in separated form (including Gaussian)
Definition operator.h:139
A slice defines a sub-range or patch of a dimension.
Definition slice.h:103
A tensor is a multidimensional array.
Definition tensor.h:318
TensorTypeData< T >::scalar_type scalar_type
C++ typename of the real type associated with a complex type.
Definition tensor.h:410
T * ptr()
Returns a pointer to the internal data.
Definition tensor.h:1841
A simple, fixed dimension vector.
Definition vector.h:64
Interface to be provided by any process map.
Definition worlddc.h:122
void fence(bool debug=false)
Synchronizes all processes in communicator AND globally ensures no pending AM or tasks.
Definition worldgop.cc:176
void sum(T *buf, size_t nelem)
Inplace global sum while still processing AM & tasks.
Definition worldgop.h:890
void fence()
Returns after all local tasks have completed.
Definition world_task_queue.h:1384
A parallel world class.
Definition world.h:134
WorldTaskQueue & taskq
Task queue.
Definition world.h:215
ProcessID rank() const
Returns the process rank in this World (same as MPI_Comm_rank()).
Definition world.h:344
ProcessID size() const
Returns the number of processes in this World (same as MPI_Comm_size()).
Definition world.h:354
WorldGopInterface & gop
Global operations.
Definition world.h:216
An archive for storing local or parallel data, wrapping a BinaryFstreamInputArchive.
Definition parallel_archive.h:366
An archive for storing local or parallel data wrapping a BinaryFstreamOutputArchive.
Definition parallel_archive.h:321
int integer
Definition crayio.c:25
static const double R
Definition csqrt.cc:46
Declaration and initialization of tree traversal functions and generic derivative.
Tensor< T > conj_transpose(const Tensor< T > &t)
Returns a new deep copy of the complex conjugate transpose of the input tensor.
Definition tensor.h:2044
Tensor< T > transpose(const Tensor< T > &t)
Returns a new deep copy of the transpose of the input tensor.
Definition tensor.h:2035
const double beta
Definition gygi_soltion.cc:62
static const double v
Definition hatom_sf_dirac.cc:20
Tensor< double > op(const Tensor< double > &x)
Definition kain.cc:508
#define rot(x, k)
Definition lookup3.c:72
#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
#define MADNESS_ASSERT(condition)
Assert a condition that should be free of side-effects since in release builds this might be a no-op.
Definition madness_exception.h:134
#define MADNESS_CHECK_THROW(condition, msg)
Check a condition — even in a release build the condition is always evaluated so it can have side eff...
Definition madness_exception.h:207
Main include file for MADNESS and defines Function interface.
static const bool VERIFY_TREE
Definition mra.h:57
Namespace for all elements and tools of MADNESS.
Definition DFParameters.h:10
void save_function(const std::vector< Function< T, NDIM > > &f, const std::string name)
save a vector of functions
Definition vmra.h:2378
bool ensure_tree_state_respecting_fence(const std::vector< Function< T, NDIM > > &v, const TreeState state, bool fence)
ensure v has the requested tree state, change the tree state of v if necessary and no fence is given
Definition vmra.h:316
void rr_cholesky(Tensor< T > &A, typename Tensor< T >::scalar_type tol, Tensor< integer > &piv, int &rank)
Compute the rank-revealing Cholesky factorization.
Definition lapack.cc:1203
void make_redundant(World &world, const std::vector< Function< T, NDIM > > &v, bool fence=true)
change tree_state of a vector of functions to redundant
Definition vmra.h:186
std::vector< Function< T, NDIM > > orthonormalize_rrcd(const std::vector< Function< T, NDIM > > &v, Tensor< T > &ovlp, const double tol, Tensor< integer > &piv, int &rank)
Definition vmra.h:662
Function< double, NDIM > abssq(const Function< double_complex, NDIM > &z, bool fence=true)
Returns a new function that is the square of the absolute value of the input.
Definition mra.h:2919
Function< TENSOR_RESULT_TYPE(L, R), NDIM > gaxpy_oop(TENSOR_RESULT_TYPE(L, R) alpha, const Function< L, NDIM > &left, TENSOR_RESULT_TYPE(L, R) beta, const Function< R, NDIM > &right, bool fence=true)
Returns new function alpha*left + beta*right optional fence and no automatic compression.
Definition mra.h:2101
Function< typename TensorTypeData< Q >::scalar_type, NDIM > abs_square(const Function< Q, NDIM > &func)
Definition complexfun.h:121
Function< T, NDIM > square(const Function< T, NDIM > &f, bool fence=true)
Create a new function that is the square of f - global comm only if not reconstructed.
Definition mra.h:2887
Function< TENSOR_RESULT_TYPE(L, R), NDIM > sub(const Function< L, NDIM > &left, const Function< R, NDIM > &right, bool fence=true)
Same as operator- but with optional fence and no automatic compression.
Definition mra.h:2156
std::vector< Function< T, NDIM > > reduce_rank(std::vector< Function< T, NDIM > > v, double thresh=0.0, bool fence=true)
reduces the tensor rank of the coefficient tensor (if applicable)
Definition vmra.h:366
Tensor< double > norm2s_T(World &world, const std::vector< Function< T, NDIM > > &v)
Computes the 2-norms of a vector of functions.
Definition vmra.h:908
std::vector< double > norm2s(World &world, const std::vector< Function< T, NDIM > > &v)
Computes the 2-norms of a vector of functions.
Definition vmra.h:895
std::vector< Function< T, NDIM > > grad_bspline_one(const Function< T, NDIM > &f, bool refine=false, bool fence=true)
Definition vmra.h:2176
void set_impl(std::vector< Function< T, NDIM > > &v, const std::vector< std::shared_ptr< FunctionImpl< T, NDIM > > > vimpl)
Definition vmra.h:738
Function< Q, NDIM > convert(const Function< T, NDIM > &f, bool fence=true)
Type conversion implies a deep copy. No communication except for optional fence.
Definition mra.h:2234
Function< TENSOR_RESULT_TYPE(Q, T), NDIM > mul(const Q alpha, const Function< T, NDIM > &f, bool fence=true)
Returns new function equal to alpha*f(x) with optional fence.
Definition mra.h:1884
std::vector< Function< T, NDIM > > orthonormalize_symmetric(const std::vector< Function< T, NDIM > > &v, const Tensor< T > &ovlp, double lindep=1e-12)
symmetric orthonormalization (see e.g. Szabo/Ostlund)
Definition vmra.h:500
std::vector< std::shared_ptr< FunctionImpl< T, NDIM > > > get_impl(const std::vector< Function< T, NDIM > > &v)
Definition vmra.h:731
Function< T, NDIM > div(const std::vector< Function< T, NDIM > > &v, bool do_refine=false, bool fence=true)
shorthand div operator
Definition vmra.h:2248
std::vector< Function< T, NDIM > > orthonormalize_cd(const std::vector< Function< T, NDIM > > &v, Tensor< T > &ovlp)
Definition vmra.h:625
std::vector< Function< T, NDIM > > copy_n(World &world, const Function< T, NDIM > &v, const unsigned int n, bool fence=true)
Returns a vector of n deep copies of a function.
Definition vmra.h:1428
void norm_tree(World &world, const std::vector< Function< T, NDIM > > &v, bool fence=true)
Makes the norm tree for all functions in a vector.
Definition vmra.h:1252
tensorT Q2(const tensorT &s)
Given overlap matrix, return rotation with 2nd order error to orthonormalize the vectors.
Definition SCF.cc:138
std::vector< Function< TENSOR_RESULT_TYPE(T, R), NDIM > > transform(World &world, const std::vector< Function< T, NDIM > > &v, const Tensor< R > &c, bool fence=true)
Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i].
Definition vmra.h:757
std::vector< Function< TENSOR_RESULT_TYPE(T, R), NDIM > > cross(const std::vector< Function< T, NDIM > > &f, const std::vector< Function< R, NDIM > > &g, bool do_refine=false, bool fence=true)
shorthand cross operator
Definition vmra.h:2315
TreeState
Definition funcdefaults.h:59
@ nonstandard_after_apply
s and d coeffs, state after operator application
Definition funcdefaults.h:64
@ redundant_after_merge
s coeffs everywhere, must be summed up to yield the result
Definition funcdefaults.h:66
@ reconstructed
s coeffs at the leaves only
Definition funcdefaults.h:60
@ nonstandard
s and d coeffs in internal nodes
Definition funcdefaults.h:62
@ unknown
Definition funcdefaults.h:68
@ compressed
d coeffs in internal nodes, s and d coeffs at the root, empty leaves may be present
Definition funcdefaults.h:61
@ redundant
s coeffs everywhere
Definition funcdefaults.h:65
@ nonstandard_with_leaves
like nonstandard, with s coeffs at the leaves
Definition funcdefaults.h:63
Function< T, NDIM > conj(const Function< T, NDIM > &f, bool fence=true)
Return the complex conjugate of the input function with the same distribution and optional fence.
Definition mra.h:2248
void cholesky(Tensor< T > &A)
Compute the Cholesky factorization.
Definition lapack.cc:1174
std::vector< std::vector< Function< TENSOR_RESULT_TYPE(T, R), NDIM > > > matrix_mul_sparse(World &world, const std::vector< Function< R, NDIM > > &f, const std::vector< Function< R, NDIM > > &g, double tol, bool fence=true, bool symm=false)
Outer product of a vector of functions with a vector of functions using sparsity.
Definition vmra.h:1223
void standard(World &world, std::vector< Function< T, NDIM > > &v, bool fence=true)
Generates standard form of a vector of functions.
Definition vmra.h:243
void truncate(World &world, std::vector< Function< T, NDIM > > &v, double tol=0.0, bool fence=true)
Truncates a vector of functions.
Definition vmra.h:335
void compress(World &world, const std::vector< Function< T, NDIM > > &v, bool fence=true)
Compress a vector of functions.
Definition vmra.h:149
Function< TENSOR_RESULT_TYPE(T, R), NDIM > dot(World &world, const std::vector< Function< T, NDIM > > &a, const std::vector< Function< R, NDIM > > &b, bool fence=true, bool do_make_redundant=true, double tol=0.0)
Multiplies and sums two vectors of functions r = \sum_i a[i] * b[i].
Definition vmra.h:1645
const std::vector< Function< T, NDIM > > & reconstruct(const std::vector< Function< T, NDIM > > &v)
reconstruct a vector of functions
Definition vmra.h:162
std::vector< Function< T, NDIM > > impl2function(const std::vector< std::shared_ptr< FunctionImpl< T, NDIM > > > vimpl)
Definition vmra.h:744
std::vector< Function< T, NDIM > > grad_bpsline_two(const Function< T, NDIM > &f, bool refine=false, bool fence=true)
Definition vmra.h:2197
void set_thresh(World &world, std::vector< Function< T, NDIM > > &v, double thresh, bool fence=true)
Sets the threshold in a vector of functions.
Definition vmra.h:1363
double norm2(World &world, const std::vector< Function< T, NDIM > > &v)
Computes the 2-norm of a vector of functions.
Definition vmra.h:921
std::vector< Function< T, NDIM > > flatten(const std::vector< std::vector< Function< T, NDIM > > > &vv)
Definition vmra.h:724
std::vector< CCPairFunction< T, NDIM > > operator*(const double fac, const std::vector< CCPairFunction< T, NDIM > > &arg)
Definition ccpairfunction.h:1089
static void verify_tree(World &world, const std::vector< Function< T, NDIM > > &v)
Definition SCF.cc:75
std::vector< Function< T, NDIM > > multi_to_multi_op_values(const opT &op, const std::vector< Function< T, NDIM > > &vin, const bool fence=true)
apply op on the input vector yielding an output vector of functions
Definition vmra.h:1965
static const Slice _(0,-1, 1)
Tensor< T > inverse(const Tensor< T > &a_in)
invert general square matrix A
Definition lapack.cc:832
void load_balance(const real_function_6d &f, const bool leaf)
do some load-balancing
Definition madness/chem/mp2.cc:70
TreeState get_tree_state(const Function< T, NDIM > &f)
get tree state of a function
Definition mra.h:2935
std::vector< CCPairFunction< T, NDIM > > operator-(const std::vector< CCPairFunction< T, NDIM > > c1, const std::vector< CCPairFunction< T, NDIM > > &c2)
Definition ccpairfunction.h:1060
std::vector< Function< T, NDIM > > partial_mul(const Function< T, NDIM > f, const std::vector< Function< T, LDIM > > g, const int particle)
multiply a high-dimensional function with a low-dimensional function
Definition vmra.h:1298
Function< T, NDIM > gaxpy_oop_reconstructed(const double alpha, const Function< T, NDIM > &left, const double beta, const Function< T, NDIM > &right, const bool fence=true)
Returns new function alpha*left + beta*right optional fence, having both addends reconstructed.
Definition mra.h:2119
std::vector< Function< TENSOR_RESULT_TYPE(T, R), NDIM > > transform_reconstructed(World &world, const std::vector< Function< T, NDIM > > &v, const Tensor< R > &c, bool fence=true)
Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i].
Definition vmra.h:786
void print(const T &t, const Ts &... ts)
Print items to std::cout (items separated by spaces) and terminate with a new line.
Definition print.h:227
std::vector< Function< T, NDIM > > append(const std::vector< Function< T, NDIM > > &lhs, const std::vector< Function< T, NDIM > > &rhs)
combine two vectors
Definition vmra.h:717
@ TT_2D
Definition gentensor.h:120
@ TT_FULL
Definition gentensor.h:120
void refine(World &world, const std::vector< Function< T, NDIM > > &vf, bool fence=true)
refine the functions according to the autorefine criteria
Definition vmra.h:196
void print_size(World &world, const std::vector< Function< T, NDIM > > &v, const std::string &msg="vectorfunction")
Definition vmra.h:1900
NDIM & f
Definition mra.h:2622
Function< TENSOR_RESULT_TYPE(L, R), NDIM > add(const Function< L, NDIM > &left, const Function< R, NDIM > &right, bool fence=true)
Same as operator+ but with optional fence and no automatic compression.
Definition mra.h:2111
const Function< T, NDIM > & change_tree_state(const Function< T, NDIM > &f, const TreeState finalstate, bool fence=true)
change tree state of a function
Definition mra.h:2948
std::vector< CCPairFunction< T, NDIM > > & operator-=(std::vector< CCPairFunction< T, NDIM > > &rhs, const std::vector< CCPairFunction< T, NDIM > > &lhs)
Definition ccpairfunction.h:1082
std::vector< Function< T, NDIM > > orthonormalize(const std::vector< Function< T, NDIM > > &vf_in)
orthonormalize the vectors
Definition vmra.h:465
NDIM const Function< R, NDIM > & g
Definition mra.h:2622
double wall_time()
Returns the wall time in seconds relative to an arbitrary origin.
Definition timers.cc:48
std::vector< Function< T, NDIM > > grad_ble_one(const Function< T, NDIM > &f, bool refine=false, bool fence=true)
Definition vmra.h:2134
Function< TENSOR_RESULT_TYPE(typename opT::opT, R), NDIM > apply_only(const opT &op, const Function< R, NDIM > &f, bool fence=true)
Apply operator ONLY in non-standard form - required other steps missing !!
Definition mra.h:2322
std::vector< Function< T, NDIM > > grad_bspline_three(const Function< T, NDIM > &f, bool refine=false, bool fence=true)
Definition vmra.h:2218
std::vector< Function< T, NDIM > > zero_functions_compressed(World &world, int n, bool fence=true)
Generates a vector of zero functions (compressed)
Definition vmra.h:449
double imag(double x)
Definition complexfun.h:56
void load_function(World &world, std::vector< Function< T, NDIM > > &f, const std::string name)
load a vector of functions
Definition vmra.h:2366
std::vector< Function< TENSOR_RESULT_TYPE(L, R), D > > vmulXX(const Function< L, D > &left, const std::vector< Function< R, D > > &vright, double tol, bool fence=true)
Use the vmra/mul(...) interface instead.
Definition mra.h:1991
void refine_to_common_level(World &world, std::vector< Function< T, NDIM > > &vf, bool fence=true)
refine all functions to a common (finest) level
Definition vmra.h:206
std::vector< Function< T, NDIM > > grad_ble_two(const Function< T, NDIM > &f, bool refine=false, bool fence=true)
Definition vmra.h:2155
static bool print_timings
Definition SCF.cc:107
CCPairFunction< T, NDIM > apply(const SeparatedConvolution< T, NDIM/2 > &op, const CCPairFunction< T, NDIM > &arg)
apply the operator to the argument
Definition ccpairfunction.h:896
void normalize(World &world, std::vector< Function< T, NDIM > > &v, bool fence=true)
Normalizes a vector of functions — v[i] = v[i].scale(1.0/v[i].norm2())
Definition vmra.h:1892
void stage_halo(World &world, const std::vector< std::shared_ptr< Derivative< T, NDIM > > > &grad, const std::vector< Function< T, NDIM > > &v, bool fence=true)
Pre-stages the neighbor coefficients that differentiating v with each of grad will need.
Definition vmra.h:381
std::vector< Function< T, NDIM > > zero_functions(World &world, int n, bool fence=true)
Generates a vector of zero functions (reconstructed)
Definition vmra.h:442
std::vector< CCPairFunction< T, NDIM > > operator+(const std::vector< CCPairFunction< T, NDIM > > c1, const std::vector< CCPairFunction< T, NDIM > > &c2)
Definition ccpairfunction.h:1052
Function< TENSOR_RESULT_TYPE(L, R), NDIM > mul_sparse(const Function< L, NDIM > &left, const Function< R, NDIM > &right, double tol, bool fence=true, bool do_make_redundant=true)
Sparse multiplication; the scalar interface redirects to the vector one in vmra.h.
Definition mra.h:1929
std::vector< Function< T, NDIM > > grad(const Function< T, NDIM > &f, bool refine=false, bool fence=true)
shorthand gradient operator
Definition vmra.h:2116
Function< T, CCPairFunction< T, NDIM >::LDIM > inner(const CCPairFunction< T, NDIM > &c, const Function< T, CCPairFunction< T, NDIM >::LDIM > &f, const std::tuple< int, int, int > v1, const std::tuple< int, int, int > v2)
Definition ccpairfunction.h:993
Function< T, NDIM > multiply(const Function< T, NDIM > f, const Function< T, LDIM > g, const int particle, const bool fence=true)
multiply a high-dimensional function with a low-dimensional function
Definition mra.h:2575
void scale(World &world, std::vector< Function< T, NDIM > > &v, const std::vector< Q > &factors, bool fence=true)
Scales inplace a vector of functions by distinct values.
Definition vmra.h:873
std::vector< Function< T, NDIM > > zero_functions_auto_tree_state(World &world, int n, bool fence=true)
Generates a vector of zero functions, either compressed or reconstructed, depending on tensor type.
Definition vmra.h:456
DistributedMatrix< T > matrix_dot(const DistributedMatrixDistribution &d, const std::vector< Function< T, NDIM > > &f, const std::vector< Function< T, NDIM > > &g, bool sym=false)
Definition vmra.h:1545
std::vector< Function< T, NDIM > > zero_functions_tree_state(World &world, int n, const TreeState state, bool fence=true)
Generates a vector of zero functions with a given tree state.
Definition vmra.h:421
double real(double x)
Definition complexfun.h:52
std::vector< CCPairFunction< T, NDIM > > & operator+=(std::vector< CCPairFunction< T, NDIM > > &lhs, const CCPairFunction< T, NDIM > &rhs)
Definition ccpairfunction.h:1068
@ same
same atoms at the same places
std::vector< Function< T, NDIM > > orthonormalize_canonical(const std::vector< Function< T, NDIM > > &v, const Tensor< T > &ovlp, double lindep=1e-12)
Definition vmra.h:562
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
Tensor< TENSOR_RESULT_TYPE(T, R) > matrix_dot_old(World &world, const std::vector< Function< T, NDIM > > &f, const std::vector< Function< R, NDIM > > &g, bool sym=false)
Computes the matrix dot product of two function vectors - q(i,j) = dot(f[i],g[j])
Definition vmra.h:1608
std::string name(const FuncType &type, const int ex=-1)
Definition ccpairfunction.h:28
void clear_halo(const std::vector< Function< T, NDIM > > &v)
Discards the neighbor halos staged on v.
Definition vmra.h:396
void matrix_inner(DistributedMatrix< T > &A, const std::vector< Function< T, NDIM > > &f, const std::vector< Function< T, NDIM > > &g, bool sym=false)
Definition distpm.cc:46
double get_size(World &world, const std::vector< Function< T, NDIM > > &v)
Definition vmra.h:1934
double get_size_local(World &world, const std::vector< Function< T, NDIM > > &v)
return the size of a vector of functions for each rank
Definition vmra.h:1915
Function< T, NDIM > copy(const Function< T, NDIM > &f, const std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > &pmap, bool fence=true)
Create a new copy of the function with different distribution and optional fence.
Definition mra.h:2187
void syev(const Tensor< T > &A, Tensor< T > &V, Tensor< typename Tensor< T >::scalar_type > &e)
Real-symmetric or complex-Hermitian eigenproblem.
Definition lapack.cc:969
Tensor< TENSOR_RESULT_TYPE(T, R) > matrix_inner_old(World &world, const std::vector< Function< T, NDIM > > &f, const std::vector< Function< R, NDIM > > &g, bool sym=false)
Computes the matrix inner product of two function vectors - q(i,j) = inner(f[i],g[j])
Definition vmra.h:1043
void make_nonstandard(World &world, std::vector< Function< T, NDIM > > &v, bool fence=true)
Generates non-standard form of a vector of functions.
Definition vmra.h:233
void gaxpy(const double a, ScalarResult< T > &left, const double b, const T &right, const bool fence=true)
the result type of a macrotask must implement gaxpy
Definition macrotaskq.h:244
int distance(const madness::Hash_private::HashIterator< hashT > &it, const madness::Hash_private::HashIterator< hashT > &jt)
Definition worldhashmap.h:616
static long abs(long a)
Definition tensor.h:219
static const double b
Definition nonlinschro.cc:119
static const double d
Definition nonlinschro.cc:121
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 double m
Definition relops.cc:9
static const double L
Definition rk.cc:46
static const double thresh
Definition rk.cc:45
Definition test_ar.cc:204
Definition mp2.h:63
double operator()(const Key< 6 > &key, const FunctionNode< double, 6 > &node) const
Definition mp2.h:70
Definition lowrankfunction.h:336
Definition dirac-hatom.cc:112
std::string ok(const bool b)
Definition test6.cc:43
AtomicInt sum
Definition test_atomicint.cc:46
int P
Definition test_binsorter.cc:9
void e()
Definition test_sig.cc:75
static const double alpha
Definition testcosine.cc:10
constexpr std::size_t NDIM
Definition testgconv.cc:54
#define TENSOR_RESULT_TYPE(L, R)
This macro simplifies access to TensorResultType.
Definition type_data.h:205
#define PROFILE_FUNC
Definition worldprofile.h:209
#define PROFILE_BLOCK(name)
Definition worldprofile.h:208