MADNESS 0.10.1
srconf.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
34/// \file SRConf.h
35/// \brief handles the low-level details of a separated representation tensor
36
37#ifndef SRCONF_H_
38#define SRCONF_H_
39
40//#define BENCH 0
41
42#include <madness/world/print.h>
46#include <list>
47#include <random>
48#include<array>
49
50namespace madness {
51#ifdef BENCH
52 static double time_[30];
53#endif
54
55
56 template <class T>
57 class GenTensor;
58 template <class T>
59 class GenTensor;
60 template <class T>
62
63 /**
64 * A SRConf handles all the configurations in a Separated Representation.
65 */
66
67 template <typename T>
68 class SRConf : public BaseTensor {
69 friend class GenTensor<T>;
70 friend class SliceLowRankTensor<T>;
71
72 /// the scalar type of T
75
76 public:
77#ifdef BENCH
78 static double& time(int i) { return time_[i]; }
79#endif
80
82
83 /// check orthonormality at low rank additions at every xth addition
84 static const long check_orthonormality_frequency = 100000;
85
86 /// for each configuration the weight; length should be r
88
89 /// for each (physical) dimension one Tensor of (logical) dimension (r,k)
90 /// for vectors or (r,kprime,k) for operators
91 std::array<Tensor<T>, 2> vector_;
92
93 /// separation dimensions: A(n,m) -> A(r,n) B(r,m), with n={k1,k2},m={k3,k4,k5..) multi-indices
94 long nci_left = -1;
95
96 /// Slice containing the actual data in each vector, ignoring "empty" configurations;
97 /// will maintain contiguity of the data.
98 std::vector<Slice> s0, s1;
99
100 public:
101 /// return the index of the last singular vector/value to meet the threshold
102 /// (returns -1 if all meet threshold, i.e. || A ||_2 < threshold)
103 /// given a matrix A in SVD form, truncate the singular values such that the
104 /// accuracy threshold is still met.
105 /// @param[in] thresh the threshold eps: || A - A(truncated) || < eps
106 /// @param[in] rank the number of singular values in w
107 /// @param[in] w the weights/singular values of A
108 /// @return i the index of s_max to contribute: w(Slice(0,i)); i.e. inclusive!
109 static int max_sigma(const double& thresh, const long& rank, const Tensor<double>& w) {
110 if (thresh < 0.0) return rank - 1;
111 // find the maximal singular value that's supposed to contribute
112 // singular values are ordered (largest first)
113 double residual = 0.0;
114 long i;
115 for (i = rank - 1; i >= 0; i--) {
116 residual += w(i) * w(i);
117 if (residual > thresh * thresh) break;
118 }
119 return i;
120 }
121
122 /// default ctor
123 SRConf() : nci_left(-1) {};
124
125 SRConf(const long& ndim, const long* dimensions,
126 const long nci) : nci_left(nci) {
128 if (nci_left < 0) nci_left = ndim / 2; // integer division
130 }
131
132 SRConf(const long& ndim, const std::array<long,TENSOR_MAXDIM>& dimensions,
133 const long nci) : SRConf(ndim, dimensions.data(), nci) {}
134
135 /// copy ctor (tested); shallow copy
136 SRConf(const SRConf& rhs) = default;
137
138 /// ctor with provided weights and effective vectors; shallow copy
139 SRConf(const Tensor<double>& weights, const std::vector<Tensor<T>>& vectors,
140 const long& ndim, const long& dims, const long nci)
141 : SRConf(ndim, dims, nci) {
142 MADNESS_ASSERT(vectors.size()==2);
143 set_vectors_and_weights(weights, vectors[0], vectors[1]);
147 }
148
149 /// explicit ctor with two vectors (aka SVD), shallow
150 SRConf(const Tensor<double>& weights, const tensorT& vector1, const tensorT& vector2,
151 const long& ndim, const long* dims, const long nci)
152 : SRConf(ndim, dims, nci) {
153 set_vectors_and_weights(weights, vector1, vector2);
156 }
157
158 /// assignment operator (tested), shallow copy of vectors
159 SRConf& operator=(const SRConf& rhs) {
160 // check for self-assignment
161 if (&rhs == this) return *this;
162 if (rhs.has_no_data()) {
163 clear();
164 return *this;
165 }
166
167 // these always hold
168 nci_left = rhs.nci_left;
170 s0 = rhs.s0;
171 s1 = rhs.s1;
172
173 if (rhs.rank() == 0) {
174 // construct empty vector
177 }
178 else {
179 // assign vectors; shallow copy
180 for (unsigned int i = 0; i < rhs.vector_.size(); i++) {
181 vector_[i] = rhs.vector_[i];
182 }
183
184 // shallow copy
185 weights_ = (rhs.weights_);
186 }
188 return *this;
189 }
190
191 /// assign a number to this;
192 SRConf& operator=(const T& number) {
193 // rank will be one
195 vector_[0] = number;
196 vector_[1] = 1.0;
197 weights_(0l) = 1.0;
199 normalize();
200 return *this;
201 }
202
203
204 void set_size_and_dim(long ndim, long k) {
205 std::array<long,TENSOR_MAXDIM> dims;
206 dims.fill(k);
208 }
209
210 /// deduce the dimensions of the left and right singular vectors from the tensor dimensions
211 std::array<std::array<long,TENSOR_MAXDIM>, 2> make_vector_dimensions(const long rank) const {
212 std::array<std::array<long,TENSOR_MAXDIM>, 2> dimensions;
213 for (int i = 0; i < nci_left; ++i) dimensions[0][i + 1] = this->dim(i);
214 for (int i = nci_left; i < ndim(); ++i) dimensions[1][i + 1 - nci_left] = this->dim(i);
215
216 dimensions[0][0] = rank;
217 dimensions[1][0] = rank;
218 return dimensions;
219 }
220
222 auto dimensions = make_vector_dimensions(rank);
224 vector_[0] = Tensor<T>(nci_left + 1, dimensions[0].data());
225 vector_[1] = Tensor<T>(ndim() - nci_left + 1, dimensions[1].data());
227 }
228
230 const Tensor<T>& vector1, const Tensor<T>& vector2) {
232 vector_ = {vector1, vector2};
234 }
235
236 void clear() {
237 weights_.clear();
238 vector_[0].clear();
239 vector_[1].clear();
240 _size = 0;
241 _ndim = -1;
242 }
243
244 /// return some of the terms of the SRConf (start,..,end), inclusively
245 /// shallow copy
246 const SRConf get_configs(const int& start, const int& end) const {
247 MADNESS_ASSERT((start>=0) and (end<=rank()));
248
249 Slice s(start, end);
250 tensorT v0, v1;
251
252 // slice vectors
253 v0 = flat_vector(0)(s, _);
254 v1 = flat_vector(1)(s, _);
255
256 SRConf<T> result(ndim(), dims(), nci_left);
257 result.set_vectors_and_weights(weights_(s), v0, v1);
259 return result;
260 }
261
262 /// dtor
264
265 template <typename Archive>
266 void serialize(Archive& ar) {
267 ar & weights_ & vector_[0] & vector_[1] & nci_left & _ndim & _size
269 // make_slices();
271 }
272
273 /// does this have any data?
274 bool has_data() const {
275 return (size() != 0);
276 }
277
278 /// does this have any data?
279 bool has_no_data() const { return !has_data(); }
280
281 /// return a Slice that corresponds the that part of vector_ that holds coefficients
282 const std::vector<Slice>& c0(const int idim) const {
283 if (idim == 0) return s0;
284 else if (idim == 1) return s1;
285 else {
286 MADNESS_EXCEPTION("invalid idim in SRConf::idim", 1);
287 }
288 }
289
290 /// append configurations of rhs to this
291
292 /// simplified version of inplace_add for flattened configurations
293 /// *this += fac*rhs
294 void append(const SRConf<T>& rhs, const double fac = 1.0) {
295 // fast return if possible
296 if (rhs.has_no_data() or rhs.rank() == 0) return;
297 if (this->has_no_data() or rank() == 0) {
298 *this = copy(rhs);
299 this->scale(fac);
300 return;
301 }
302
303 auto dimensions = make_vector_dimensions(rank() + rhs.rank());
305 Tensor<T> vector0(nci_left + 1, dimensions[0].data());
306 Tensor<T> vector1(ndim() - nci_left + 1, dimensions[1].data());
307
308 // assign weights
309 weights(Slice(0, rank() - 1)) = weights_(Slice(0, rank() - 1));
310 weights(Slice(rank(), rank() + rhs.rank() - 1)) = rhs.weights_(Slice(0, rhs.rank() - 1)) * fac;
311
312 vector0(c0(0)) = vector_[0](c0(0));
313 vector1(c0(1)) = vector_[1](c0(1));
314
315 auto s00 = s0;
316 auto s10 = s1;
317 s00[0] = Slice(rank(), rank() + rhs.rank() - 1);
318 s10[0] = Slice(rank(), rank() + rhs.rank() - 1);
319
320 vector0(s00) = rhs.vector_[0](rhs.c0(0));
321 vector1(s10) = rhs.vector_[1](rhs.c0(1));
322
323 std::swap(weights, weights_);
324 std::swap(vector0, vector_[0]);
325 std::swap(vector1, vector_[1]);
326
327 make_slices();
329 }
330
331 void append(const SRConf<T>& rhs, const double_complex fac = 1.0) {
332 MADNESS_EXCEPTION("no complex in SRConf", 1);
333 }
334
335 public:
336 /// add two orthonormal configurations, yielding an optimal SVD decomposition
337 void add_SVD(const SRConf<T>& rhs, const double& thresh) {
338#ifdef BENCH
339 double cpu0 = wall_time();
340#endif
341 if (rhs.has_no_data() or rhs.rank() == 0) return;
342 if (has_no_data() or rank() == 0) {
343 *this = rhs;
344 return;
345 }
346
348 // get random number
349 std::random_device rd;
350
351 // 2. Initialize the Mersenne Twister engine with the seed
352 std::mt19937 gen(rd());
353
354 // 3. Define the distribution range [inclusive lower bound, inclusive upper bound]
355 std::uniform_int_distribution<int> distrib(1, check_orthonormality_frequency);
356
357 // 4. Generate random numbers
358 long iran = distrib(gen);
359 if (iran==1) { // any number will do here..
360 print("checking orthonormality in add_SVD");
361 int isuccess=0;
362 if (not check_vector_orthonormality(0)) isuccess++;
363 if (not check_vector_orthonormality(1)) isuccess++;
364 if (not rhs.check_vector_orthonormality(0)) isuccess++;
365 if (not rhs.check_vector_orthonormality(1)) isuccess++;
366 if (isuccess>0) {
367 print("vector in add_svd not orthogonal");
368 }
369 }
370 }
371
372 // Tensor<T> x1=flat_vector(0);
373 // Tensor<T> x2=flat_vector(1);
374 Tensor<T> x1 = vector_[0].reshape(rank(), kVec(0));
375 Tensor<T> x2 = vector_[1].reshape(rank(), kVec(1));
376 ortho5(x1, x2, weights_,
377 rhs.flat_vector(0), rhs.flat_vector(1), rhs.weights_, thresh);
378 std::swap(x1, vector_[0]);
379 std::swap(x2, vector_[1]);
380
382 make_slices();
384#ifdef BENCH
385 double cpu1 = wall_time();
386 time(25) += cpu1 - cpu0;
387#endif
388 }
389
390 protected:
391 /// alpha * this(lhs_s) + beta * rhs(rhs_s)
392
393 /// bounds checking should have been performed by caller
394 /// s denotes where in lhs the new contribution from rhs will be inserted
395 void inplace_add(const SRConf<T>& rhs, std::array<Slice,TENSOR_MAXDIM> lhs_s,
396 std::array<Slice,TENSOR_MAXDIM> rhs_s, const double alpha, const double beta) {
397 // cannot scale a slice only...
398 MADNESS_ASSERT(alpha==1.0);
399
400 // fast return if possible; no fast return for this.rank()==0
401 // since we might work with slices!
402 if (rhs.has_no_data() or rhs.rank() == 0) return;
403
404 // prepare the vectors
405 SRConf<T> result(ndim(), dims(), nci_left);
406 result.make_empty_vectors_and_weights(rank() + rhs.rank());
407
408 // insert lhs into result
409 if (rank() > 0) {
410 result.vector_[0](s0) = vector_[0];
411 result.vector_[1](s1) = vector_[1];
412 result.weights_(Slice(0, rank() - 1)) = weights_;
413 }
414 // insert rhs into result
415 {
416 auto [sr0,sr1] = rhs.make_slices(rhs_s);
417 auto [sl0,sl1] = make_slices(lhs_s);
418 sl0[0] = Slice(rank(), result.rank() - 1);
419 sl1[0] = Slice(rank(), result.rank() - 1);
420 result.vector_[0](sl0) = rhs.vector_[0](sr0);
421 result.vector_[1](sl1) = rhs.vector_[1](sr1);
422 result.weights_(Slice(rank(), result.rank() - 1)) = rhs.weights_ * beta;
423 }
424 std::swap(*this, result);
426 }
427
428 /// deep copy of rhs, shrink
429 friend SRConf<T> copy(const SRConf<T>& rhs) {
430 if (rhs.has_no_data()) return SRConf<T>();
431
432 SRConf<T> result(rhs.ndim(), rhs.dims(), rhs.nci_left);
433
434 // if rhs is non-existent simply construct a new SRConf
435 if (rhs.has_data() and rhs.rank() > 0) {
436 result.set_vectors_and_weights(copy(rhs.weights_(Slice(0, rhs.rank() - 1))),
437 copy(rhs.vector_[0](rhs.c0(0))), copy(rhs.vector_[1](rhs.c0(1))));
438 }
439
440 return result;
441 }
442
443 public:
444 /// return a slice of this (deep copy)
445 SRConf<T> copy_slice(const std::array<Slice,TENSOR_MAXDIM>& s) const {
446 std::array<long,TENSOR_MAXDIM> k;
447 for (int i = 0; i < s.size(); ++i) {
448 if (s[i].end == -1) k[i] = dim(i);
449 else k[i] = s[i].end - s[i].start + 1;
450 }
451 SRConf<T> result(ndim(), k, nci_left);
452
453 // fast return if possible
454 if (this->has_no_data() or rank() == 0) return result;
455
456 auto [s00,s11] = make_slices(s);
457 Tensor<T> vector0 = copy(vector_[0](s00));
458 Tensor<T> vector1 = copy(vector_[1](s11));
459
460 Tensor<double> weights = copy(this->weights_(Slice(0, rank() - 1)));
461 result.set_vectors_and_weights(weights, vector0, vector1);
462
463 return result;
464 }
465
466 /// perform elementwise Hadamard product
467 SRConf<T>& emul(const SRConf<T>& other) {
468 // consistency check
469 MADNESS_ASSERT(compatible(*this,other));
470
471 long finalrank = this->rank() * other.rank();
472
473 SRConf<T> result(ndim(), dims(), nci_left); // empty tensor
474
475 if ((this->rank() == 0) or (other.rank() == 0)) {
476 ; // pass
477 }
478 else {
479 result.make_empty_vectors_and_weights(finalrank);
480 result.weights_ = outer(weights_, other.weights_).flat();
481
482 // left vector
483 for (int i = 0; i < 2; ++i) {
485 Tensor<T> b1 = other.flat_vector(i);
486 Tensor<T> r1 = result.vector_[i].reshape(finalrank, kVec(i));
487 Tensor<T> tmp(finalrank, 1);
488 for (int k = 0; k < a1.dim(1); ++k) {
489 // r1(_,Slice(k,k))=outer(a1(_,k),b1(_,k)).reshape(finalrank,1);
490 outer_result(a1(_, k), b1(_, k), tmp);
491 r1(_, Slice(k, k)) = tmp;
492 }
493 }
494 }
495 result.make_structure();
496 result.normalize();
497
498 *this = result;
499 return *this;
500 }
501
502 protected:
503 /// redo the Slices for getting direct access to the configurations
504 void make_slices() {
505 s0 = std::vector<Slice>(nci_left + 1, _); // first dim is the rank
506 s1 = std::vector<Slice>(ndim() - nci_left + 1, _); // first dim is the rank
507
508 s0[0] = Slice(0, rank() - 1);
509 s1[0] = Slice(0, rank() - 1);
510 }
511
512 std::array<std::vector<Slice>, 2> make_slices(const std::array<Slice,TENSOR_MAXDIM>& s) const {
513 std::vector<Slice> s00(nci_left + 1, _); // first dim is the rank
514 std::vector<Slice> s10(ndim() - nci_left + 1, _); // first dim is the rank
515
516 s00[0] = Slice(0, rank() - 1);
517 s10[0] = Slice(0, rank() - 1);
518
519 for (int idim = 0; idim < ndim(); ++idim) {
520 if (idim < nci_left) s00[idim + 1] = s[idim];
521 if (idim >= nci_left) s10[idim - nci_left + 1] = s[idim];
522 }
523
524 std::array<std::vector<Slice>, 2> result = {s00, s10};
525 return result;
526 }
527
528 void make_structure(bool force = false) {
529 auto dimensions = make_vector_dimensions(rank());
530 vector_[0] = vector_[0].reshape(nci_left + 1, &dimensions[0][0]);
531 vector_[1] = vector_[1].reshape(ndim() - nci_left + 1, &dimensions[1][0]);
532
533 this->make_slices();
534 }
535
536 public:
537 /// return reference to one of the vectors F
538 Tensor<T>& ref_vector(const unsigned int& idim) {
539 return vector_[idim];
540 }
541
542 /// return reference to one of the vectors F
543 const Tensor<T>& ref_vector(const unsigned int& idim) const {
544 return vector_[idim];
545 }
546
547
548 long kVec(const int idim) const {
549 return vector_[idim].size() / vector_[idim].dim(0);
550 }
551
552 /// return shallow copy of a slice of one of the vectors, flattened to (r,kVec)
553 const Tensor<T> flat_vector(const unsigned int& idim) const {
554 MADNESS_ASSERT(rank()>0);
555 // const Tensor<T> result=vector_[idim](c0(idim)).reshape(rank(),kVec(idim));
556 const Tensor<T> result = vector_[idim].reshape(rank(), kVec(idim));
557 return result;
558 }
559
560 /// return shallow copy of a slice of one of the vectors, flattened to (r,kVec)
561 Tensor<T> flat_vector(const unsigned int& idim) {
562 MADNESS_ASSERT(rank()>0);
563 // Tensor<T> result=vector_[idim](c0(idim)).reshape(rank(),kVec(idim));
564 Tensor<T> result = vector_[idim].reshape(rank(), kVec(idim));
565 return result;
566 }
567
568 protected:
569 // /// fill this SRConf with 1 flattened random configurations (tested)
570 // void fillWithRandom(const long& rank=1) {
571 //
572 //
573 // // assign; note that Slice(0,_) is inclusive
574 // weights_=Tensor<double>(rank);
575 // weights_=1.0;
576 //
577 // for (unsigned int idim=0; idim<this->dim_eff(); idim++) {
578 // vector_[idim]=Tensor<T>(rank,this->kVec());
579 // vector_[idim].fillrandom();
580 // }
581 //
582 // this->normalize();
583 // for (unsigned int idim=0; idim<this->dim_eff(); idim++) {
584 // vector_[idim].scale(madness::RandomValue<T>()*scalar_type(10.0));
585 // }
586 // weights_(Slice(0,this->rank()-1)).fillrandom().scale(10.0);
587 // make_slices();
588 // MADNESS_ASSERT(has_structure());
589 // }
590
591 /// normalize the vectors (tested)
592 void normalize() {
593 if (rank() == 0) return;
595
596 // for convenience
597 const unsigned int rank = this->rank();
598 // std::vector<Slice> s(2,_);
599
600 // we calculate the norm sum_i < F^r_i | F^r_i > for each dimension for each r
601
602 // loop over all configurations
603 for (unsigned int r = 0; r < rank; r++) {
604 // loop over all dimensions
605 for (unsigned int idim = 0; idim < 2; idim++) {
606 std::vector<Slice> s(dim_per_vector(idim) + 1, _);
607 s[0] = Slice(r, r);
608
609 // const double norm=this->ref_vector(idim)(s).normf();
610 const double norm = this->vector_[idim](s).normf();
611 const double fac = norm;
612 double oofac = 1.0 / fac;
613 if (fac < 1.e-13) oofac = 0.0;
614 weights_(r) *= fac;
615 vector_[idim](s).scale(oofac);
616 }
617 }
619 }
620
621 bool check_dimensions() const {
622 bool correct = true;
623 if (vector_[0].dim(0) != rank()) return false;
624 if (vector_[0].ndim() + vector_[1].ndim() != ndim() + 2) return false;
625 if (vector_[0].ndim() != nci_left + 1) return false;
626 if (vector_[1].ndim() != ndim() - nci_left + 1) return false;
627
628 return correct;
629 }
630
631 /// check if the terms are orthogonal
632
633 /// @param[in] ivec which vector (0 or 1) to check
634 bool check_vector_orthonormality(const int ivec) const {
635 // fast return if possible
636 if (rank() == 0) return true;
637
638 const tensorT t1 = ref_vector(ivec)(c0(ivec)).reshape(rank(), kVec(ivec));
639 tensorT S = inner(t1, t1, 1, 1);
640 for (int i = 0; i < S.dim(0); i++) S(i, i) -= 1.0;
641
642 // error per matrix element
643 double norm = S.normf();
644 double small = sqrt(norm * norm / S.size());
645 return (small < 1.e-10);
646 }
647
648 /// return if this has only one additional dimension (apart from rank)
649 bool is_flat() const {
650 return (vector_[0].ndim() == 2);
651 }
652
653 public:
654 /// return if this has a tensor structure (has not been flattened)
655 bool has_structure() const {
656 if (vector_.size() == 2) {
657 auto vector_dimensions = make_vector_dimensions(vector_[0].dim(0));
658 for (int i = 0; i < vector_[0].ndim(); ++i) {
659 if (vector_dimensions[0][i] != vector_[0].dim(i)) return false;
660 }
661 for (int i = 0; i < vector_[1].ndim(); ++i) {
662 if (vector_dimensions[1][i] != vector_[1].dim(i)) return false;
663 }
664 }
665 return true;
666 }
667
668 /// return the logicalrank
669 long rank() const { return weights_.size(); };
670
671 public:
672 /// return the number of physical dimensions
673 int dim_per_vector(int idim) const {
674 MADNESS_ASSERT(vector_.size()>size_t(idim));
675 return vector_[idim].ndim() - 1; // remove dimension for the rank
676 }
677
678 /// return the weight
679 double weights(const unsigned int& i) const { return weights_(i); };
680
681 /// reconstruct this to return a full tensor
683 // fast return if possible
684 if (rank() == 0) return Tensor<T>(ndim(), dims(), true);
685
686 // include weights in left vector
688
689 Tensor<T> result = inner(conj(scr), flat_vector(1), 0, 0);
690 return result.reshape(ndim(), dims());
691 }
692
693 protected:
697
698 public:
700 Tensor<T> v = copy(vector_[dim].reshape(rank(), vector_[dim].size() / rank()));
701 for (unsigned int r = 0; r < rank(); r++) v(r, _) *= weights(r);
702 v = v.reshape(vector_[dim].ndim(), vector_[dim].dims());
703 return v;
704 }
705
706 /// return flat (r,i) view of the tensor with the weights multiplied in
707
708 /// return a(r,i) = vec(dim)(r,i) * w(r)
710 return make_vector_with_weights(dim).reshape(rank(), vector_[dim].size() / rank());
711 }
712
713 protected:
714 /// return the number of coefficients
715 unsigned int nCoeff() const {
716 return vector_[0].size() + vector_[1].size() + weights_.size();
717 };
718
719 /// return the real size of this
720 size_t real_size() const {
721 size_t n = 0;
722 for (size_t i = 0; i < vector_.size(); ++i) {
723 n += vector_[i].size() * sizeof(T) + sizeof(tensorT);
724 }
725 n += weights_.size() * sizeof(double) + sizeof(Tensor<double>);
726 n += sizeof(*this);
727 n += 2 * s1.size() * sizeof(Slice);
728 return n;
729 }
730
731
732 template <typename Q>
735 friend trace(const SRConf<T>& rhs, const SRConf<Q>& lhs) {
736 MADNESS_EXCEPTION("no complex trace in srconf.h", 1);
737 return T(0.0);
738 }
739
740 /// calculate the Frobenius inner product (tested)
741 template <typename Q>
744 friend trace(const SRConf<T>& rhs, const SRConf<Q>& lhs) {
745 // fast return if either rank is 0
746 if ((lhs.has_no_data()) or (rhs.has_no_data())) return 0.0;
747 if ((lhs.rank() == 0) or (rhs.rank() == 0)) return 0.0;
748
749 /*
750 * the structure of an SRConf is (r,k) or (r,k',k), with
751 * r the slowest index; the overlap is therefore simply calculated
752 * as the matrix multiplication rhs*lhs^T
753 */
754
755 // some checks
756 MADNESS_ASSERT(rhs.ndim()==lhs.ndim());
757 MADNESS_ASSERT(rhs.ndim()>0);
758
759 typedef TENSOR_RESULT_TYPE(T, Q) resultT;
760
761 const unsigned int dim_eff = 2;
762
763 // get the weight matrix
764 Tensor<resultT> weightMatrix = outer(lhs.weights_(Slice(0, lhs.rank() - 1)),
765 rhs.weights_(Slice(0, rhs.rank() - 1)));
766
767 // calculate the overlap matrices for each dimension at a time
768 for (unsigned int idim = 0; idim < dim_eff; idim++) {
769 const Tensor<T> lhs2 = lhs.flat_vector(idim);
770 const Tensor<Q> rhs2 = rhs.flat_vector(idim);
771 Tensor<resultT> ovlp(lhs.rank(), rhs.rank());
772 inner_result(lhs2, rhs2, -1, -1, ovlp);
773
774 // multiply all overlap matrices with the weight matrix
775 weightMatrix.emul(ovlp);
776 }
777
778 // return weightMatrix;
779 const TENSOR_RESULT_TYPE(T, Q) overlap = weightMatrix.sum();
780 return overlap;
781 }
782
783 /// calculate the Frobenius norm, if this is in SVD form
785 if (has_no_data() or rank() == 0) return 0.0;
786 return weights_(Slice(0, rank() - 1)).normf();
787 }
788
789 /// calculate the Frobenius norm
791 // fast return if possible
792 if (has_no_data() or rank() == 0) return 0.0;
793
794 // some checks
795 MADNESS_ASSERT(ndim()>0);
797
798 // get the weight matrix
799 Tensor<T> weightMatrix = outer(weights_(Slice(0, rank() - 1)), weights_(Slice(0, rank() - 1)));
800
801 // calculate the overlap matrices for each dimension at a time
802 for (unsigned int idim = 0; idim < 2; idim++) {
803 const Tensor<T> vec = flat_vector(idim);
804 Tensor<T> ovlp(rank(), rank());
805 inner_result(vec, vec, -1, -1, ovlp);
806
807 // multiply all overlap matrices with the weight matrix
808 weightMatrix.emul(ovlp);
809 }
810
811 typedef typename TensorTypeData<T>::float_scalar_type resultT;
812 const resultT overlap = std::abs(weightMatrix.sum());
813 return sqrt(overlap);
814 }
815
816 protected:
817 /// scale this by a number
818 void scale(const double& fac) { weights_.scale(fac); };
819
820 void scale(const double_complex& fac) {
821 MADNESS_EXCEPTION("no complex scaling in SRConf", 1);
822 }
823
824 /// check compatibility
825 friend bool compatible(const SRConf& lhs, const SRConf& rhs) {
826 return (lhs.conforms(&rhs) and (lhs.dim_per_vector(0) == rhs.dim_per_vector(0)));
827 }
828
829 /// \code
830 /// result(i,j,k,...) <-- sum(i',j', k',...) t(i',j',k',...) c(i',i) c(j',j) c(k',k) ...
831 /// \endcode
832 ///
833 /// The input dimensions of \c t must all be the same .
835 // fast return if possible
836 if (this->has_no_data() or rank() == 0) return SRConf<T>(ndim(), dims(), nci_left);
837
838 // transpose both singular vectors from U(r,i,j,k) to U(i,j,k,r)
839 // and run the contraction as in tensor: U(i,j,k,r) t(i,i') = U(j,k,r,i')
840 // and so on, yielding U(r,i',j',k')
841 Tensor<T> left = copy(vector_[0].cycledim(-1, 0, -1));
842 Tensor<T> right = copy(vector_[1].cycledim(-1, 0, -1));
843
844 for (long i = 0; i < nci_left; ++i) left = inner(left, c, 0, 0);
845 for (long i = nci_left; i < ndim(); ++i) right = inner(right, c, 0, 0);
846
847 SRConf<T> result(ndim(), dims(), this->nci_left);
848 result.set_vectors_and_weights(copy(weights_), left, right);
849
851 return result;
852 }
853
854 public:
855 /// \code
856 /// result(i,j,k,...) <-- sum(i',j', k',...) t(i',j',k',...) c(i',i) c(j',j) c(k',k) ...
857 /// \endcode
858 ///
859 /// The input dimensions of \c t must all be the same .
860 template <typename Q>
862 // fast return if possible
863 if (this->has_no_data() or rank() == 0) return SRConf<T>(ndim(), dims(), nci_left);
864
865 // copying shrinks the vectors to (r,k,k,..)
867
868 // transpose both singular vectors from U(r,i,j,k) to U(i,j,k,r)
869 // and run the contraction as in tensor: U(i,j,k,r) t(i,i') = U(j,k,r,i')
870 // and so on, yielding U(r,i',j',k')
871 Tensor<T> left = copy(vector_[0].cycledim(-1, 0, -1));
872 Tensor<T> right = copy(vector_[1].cycledim(-1, 0, -1));
873
874 for (long i = 0; i < nci_left; ++i) left = inner(left, c[i], 0, 0);
875 for (long i = nci_left; i < ndim(); ++i) right = inner(right, c[i], 0, 0);
876
877 SRConf<T> result(ndim(), dims(), this->nci_left);
878 result.set_vectors_and_weights(copy(weights_), left, right);
879
881 return result;
882 }
883
884 SRConf<T> transform_dir(const Tensor<T>& c, const int& axis) const {
885 if (this->has_no_data() or rank() == 0) return SRConf<T>(ndim(), dims(), nci_left);
886
887 // copying shrinks the vectors to (r,k,k,..)
888 SRConf<T> result = copy(*this);
889
890 // only a matrix is allowed for c
891 MADNESS_ASSERT(c.ndim()==2);
892
893 // make sure this is not flattened
895
896 // compute idim for accessing the vector_, and the dimension inside vector_
897 // the +1 on jdim for the rank
898 const long idim = axis / this->dim_per_vector(0);
899 const long jdim = axis % this->dim_per_vector(0) + 1;
900
901 // note: no slicing necessary, since we've copied this to result (incl shrinking)
902 result.ref_vector(idim) = madness::transform_dir(this->ref_vector(idim), c, jdim);
904
905 return result;
906 }
907 };
908
909 /// sophisticated version of ortho2
910
911 /// after calling this we will have an optimally rank-reduced representation
912 /// with the left and right subspaces being bi-orthogonal and normalized;
913 /// outline of the algorithm:
914 /// - canonical orthogonalization of the subspaces (screen for small eigenvalues)
915 /// - SVD of the modified overlap (incorporates the roots of eigenvalues)
916 /// operation count is O(kr^2 + r^3)
917 ///
918 /// @param[in,out] x normalized left subspace
919 /// @param[in,out] y normalize right subspace
920 /// @param[in,out] weights weights
921 /// @param[in] thresh truncation threshold
922 template <typename T>
923 void ortho3(Tensor<T>& x, Tensor<T>& y, Tensor<typename Tensor<T>::scalar_type>& weights, const double& thresh) {
924#ifdef BENCH
925 double cpu0 = wall_time();
926#endif
927 typedef Tensor<T> tensorT;
928 typedef typename Tensor<T>::scalar_type scalar_type;
929
930 const long rank = x.dim(0);
931 const double w_max = weights.absmax() * rank; // max Frobenius norm
932
933
934 // overlap of 1 and 2
935 tensorT S1 = inner(x, x, 1, 1);
936 tensorT S2 = inner(y, y, 1, 1); // 0.5 / 2.1
937#ifdef BENCH
938 double cpu1 = wall_time();
939 SRConf<T>::time(1) += (cpu1 - cpu0);
940#endif
941
942 // print("norm(S1)",S1.normf());
943 // print("norm(S2)",S2.normf());
944
945 // diagonalize
946 tensorT U1, U2;
948 syev(S1, U1, e1);
949 syev(S2, U2, e2); // 2.3 / 4.0
950#ifdef BENCH
951 double cpu3 = wall_time();
952 SRConf<T>::time(3) += cpu3 - cpu1;
953#endif
954
955 const scalar_type e1_max = e1.absmax();
956 const scalar_type e2_max = e2.absmax();
957
958 // fast return if possible
959 if ((e1_max * w_max < thresh) or (e2_max * w_max < thresh)) {
960 x.clear();
961 y.clear();
962 weights.clear();
963 return;
964 }
965
966 // remove small negative eigenvalues
967 e1.screen(1.e-13);
968 e2.screen(1.e-13);
969 Tensor<scalar_type> sqrt_e1(rank), sqrt_e2(rank);
970
971
972 // shrink U1, U2
973 int lo1 = 0;
974 int lo2 = 0;
975 for (unsigned int r = 0; r < rank; r++) {
976 if (e1(r) * w_max < thresh) lo1 = r + 1;
977 if (e2(r) * w_max < thresh) lo2 = r + 1;
978 sqrt_e1(r) = sqrt(std::abs(e1(r)));
979 sqrt_e2(r) = sqrt(std::abs(e2(r)));
980 }
981
982 U1 = U1(Slice(_), Slice(lo1, -1));
983 U2 = U2(Slice(_), Slice(lo2, -1));
984 sqrt_e1 = sqrt_e1(Slice(lo1, -1));
985 sqrt_e2 = sqrt_e2(Slice(lo2, -1));
986 unsigned int rank1 = rank - lo1;
987 unsigned int rank2 = rank - lo2; // 0.0 / 0.0
988
989
990 MADNESS_ASSERT(sqrt_e1.size()==rank1);
991 MADNESS_ASSERT(sqrt_e2.size()==rank2);
992#ifdef BENCH
993 double cpu4 = wall_time();
994 SRConf<T>::time(4) += cpu4 - cpu3;
995#endif
996
997
998 // set up overlap M; include X+
999 tensorT M(rank1, rank2);
1000 for (unsigned int i = 0; i < rank1; i++) {
1001 for (unsigned int j = 0; j < rank2; j++) {
1002 for (unsigned int r = 0; r < rank; r++) {
1003 M(i, j) += U1(r, i) * sqrt_e1(i) * weights(r) * U2(r, j) * sqrt_e2(j);
1004 // M(i,j)+=U1(r,i)*weights(r)*U2(r,j);
1005 }
1006 }
1007 }
1008
1009
1010 // include X-
1011 for (unsigned int r = 0; r < rank1; r++) {
1012 scalar_type fac = 1.0 / sqrt_e1(r);
1013 for (unsigned int t = 0; t < rank; t++) {
1014 U1(t, r) *= fac;
1015 // if (sqrt_e1(r)<thresh) throw;
1016 }
1017 }
1018
1019 for (unsigned int r = 0; r < rank2; r++) {
1020 scalar_type fac = 1.0 / sqrt_e2(r);
1021 for (unsigned int t = 0; t < rank; t++) {
1022 U2(t, r) *= fac;
1023 // if (sqrt_e2(r)<thresh) throw;
1024 }
1025 } // 0.2 / 0.6
1026#ifdef BENCH
1027 double cpu5 = wall_time();
1028 SRConf<T>::time(5) += cpu5 - cpu4;
1029#endif
1030
1031 // decompose M
1032 tensorT Up, VTp;
1034 svd(M, Up, Sp, VTp); // 1.5 / 3.0
1035#ifdef BENCH
1036 double cpu6 = wall_time();
1037 SRConf<T>::time(6) += cpu6 - cpu5;
1038#endif
1039
1040 // make transformation matrices
1041 Up = inner(Up, U1, 0, 1);
1042 VTp = inner(VTp, U2, 1, 1);
1043
1044
1045 // // find the maximal singular value that's supposed to contribute
1046 // // singular values are ordered (largest first)
1047 // double residual=0.0;
1048 // long i;
1049 // for (i=Sp.dim(0)-1; i>=0; i--) {
1050 // residual+=Sp(i)*Sp(i);
1051 // if (residual>thresh*thresh) break;
1052 // }
1053 long i = SRConf<T>::max_sigma(thresh, Sp.dim(0), Sp);
1054
1055#ifdef BENCH
1056 double cpu7 = wall_time();
1057 SRConf<T>::time(7) += cpu7 - cpu6;
1058#endif
1059
1060 // i=std::min(i,long(0));
1061
1062 Up = Up(Slice(0, i), Slice(_));
1063 VTp = VTp(Slice(0, i), Slice(_));
1064
1065
1066 // convert SVD output to our convention
1067 if (i >= 0) {
1068 // transform 1 and 2
1069 x = inner(Up, x, 1, 0);
1070 y = inner(VTp, y, 1, 0); // 0.5 / 2.5
1071 weights = Sp(Slice(0, i));
1072 }
1073 else {
1074 x.clear();
1075 y.clear();
1076 weights.clear();
1077 }
1078#ifdef BENCH
1079 double cpu8 = wall_time();
1080 SRConf<T>::time(8) += cpu8 - cpu7;
1081 SRConf<T>::time(0) += cpu8 - cpu0;
1082#endif
1083 return;
1084 }
1085
1086 /// specialized version of ortho3
1087
1088 /// does the same as ortho3, but takes two bi-orthonormal configs as input
1089 /// and saves on the inner product. Result will be written onto the first config
1090 ///
1091 /// @param[in,out] x1 left subspace, will hold the result on exit
1092 /// @param[in,out] y1 right subspace, will hold the result on exit
1093 /// @param[in] x2 left subspace, will be accumulated onto x1
1094 /// @param[in] y2 right subspace, will be accumulated onto y1
1095 template <typename T>
1097 const Tensor<T>& x2, const Tensor<T>& y2, const Tensor<typename Tensor<T>::scalar_type>& w2,
1098 const double& thresh) {
1099#ifdef BENCH
1100 double cpu0 = wall_time();
1101#endif
1102 typedef Tensor<T> tensorT;
1103
1104 const long rank1 = x1.dim(0);
1105 const long rank2 = x2.dim(0);
1106 const long rank = rank1 + rank2;
1107
1108 // for convenience: blocks of the matrices
1109 const Slice s0(0, rank1 - 1), s1(rank1, rank - 1);
1110
1111 const double w_max = std::max(w1.absmax(), w2.absmax());
1112 const double norm_max = w_max * rank; // max Frobenius norm
1113
1114 // the overlap between 1 and 2;
1115 // the overlap of 1 and 1, and 2 and 2 is assumed to be the identity matrix
1116 tensorT Sx12 = inner(x1, x2, 1, 1);
1117 tensorT Sy12 = inner(y1, y2, 1, 1);
1118#ifdef BENCH
1119 double cpu1 = wall_time();
1120 SRConf<T>::time(11) += cpu1 - cpu0;
1121#endif
1122
1123 tensorT Sx(rank, rank);
1124 tensorT Sy(rank, rank);
1125
1126 // the identity matrix (half of it)
1127 for (long i = 0; i < rank; i++) {
1128 Sx(i, i) = 0.5;
1129 Sy(i, i) = 0.5;
1130 }
1131 Sx(s0, s1) = Sx12;
1132 Sy(s0, s1) = Sy12;
1133 Sx += transpose(Sx);
1134 Sy += transpose(Sy);
1135
1136 // overlap of 1 and 2
1137 // tensorT S1=inner(x,x,1,1);
1138 // tensorT S2=inner(y,y,1,1); // 0.5 / 2.1
1139#ifdef BENCH
1140 double cpu2 = wall_time();
1141 SRConf<T>::time(12) += cpu2 - cpu1;
1142#endif
1143
1144 // diagonalize
1145 tensorT U1, U2;
1147 syev(Sx, U1, e1);
1148 syev(Sy, U2, e2); // 2.3 / 4.0
1149#ifdef BENCH
1150 double cpu3 = wall_time();
1151 SRConf<T>::time(13) += cpu3 - cpu2;
1152#endif
1153
1154 // print("norm(Sx)",Sx.normf());
1155 // print("norm(Sy)",Sy.normf());
1156
1157 const double e1_max = e1.absmax();
1158 const double e2_max = e2.absmax();
1159
1160 // fast return if possible
1161 if ((e1_max * norm_max < thresh) or (e2_max * norm_max < thresh)) {
1162 x1.clear();
1163 y1.clear();
1164 w1.clear();
1165 return;
1166 }
1167
1168 // remove small negative eigenvalues
1169 e1.screen(1.e-13);
1170 e2.screen(1.e-13);
1171 Tensor<double> sqrt_e1(rank), sqrt_e2(rank);
1172
1173
1174 // shrink U1, U2
1175 int lo1 = 0;
1176 int lo2 = 0;
1177 for (unsigned int r = 0; r < rank; r++) {
1178 if (e1(r) < thresh / norm_max) lo1 = r + 1;
1179 else sqrt_e1(r) = sqrt(std::abs(e1(r)));
1180 if (e2(r) < thresh / norm_max) lo2 = r + 1;
1181 else sqrt_e2(r) = sqrt(std::abs(e2(r)));
1182 }
1183
1184 U1 = U1(Slice(_), Slice(lo1, -1));
1185 U2 = U2(Slice(_), Slice(lo2, -1));
1186 sqrt_e1 = sqrt_e1(Slice(lo1, -1));
1187 sqrt_e2 = sqrt_e2(Slice(lo2, -1));
1188 unsigned int rank_x = rank - lo1;
1189 unsigned int rank_y = rank - lo2; // 0.0 / 0.0
1190
1191
1192 // MADNESS_ASSERT(sqrt_e1.size()==rank_x);
1193 // MADNESS_ASSERT(sqrt_e2.size()==rank_y);
1194
1195 // set up overlap M; include X+
1196
1197 // for (unsigned int i=0; i<rank_x; ++i) U(i,_)*=sqrt_e1(i);
1198 // for (unsigned int i=0; i<rank_y; ++i) U(i,_)*=sqrt_e2(i);
1199
1200 tensorT UU1 = copy(U1);
1201 for (unsigned int i = 0; i < rank1; ++i) UU1(i, _) *= w1(i);
1202 for (unsigned int i = rank1; i < rank; ++i) UU1(i, _) *= w2(i - rank1);
1203
1204 tensorT M = inner(UU1, U2, 0, 0);
1205 tensorT ee = outer(sqrt_e1, sqrt_e2);
1206 M.emul(ee);
1207
1208 // include X-
1209 for (unsigned int r = 0; r < rank_x; r++) {
1210 double fac = 1.0 / sqrt_e1(r);
1211 U1(_, r) *= fac;
1212 }
1213
1214 for (unsigned int r = 0; r < rank_y; r++) {
1215 double fac = 1.0 / sqrt_e2(r);
1216 U2(_, r) *= fac;
1217 } // 0.2 / 0.6
1218#ifdef BENCH
1219 double cpu4 = wall_time();
1220 SRConf<T>::time(14) += cpu4 - cpu3;
1221#endif
1222
1223
1224 // decompose M
1225 tensorT Up, VTp;
1227 svd(M, Up, Sp, VTp); // 1.5 / 3.0
1228#ifdef BENCH
1229 double cpu5 = wall_time();
1230 SRConf<T>::time(15) += cpu5 - cpu4;
1231#endif
1232
1233 // make transformation matrices
1234 Up = inner(Up, U1, 0, 1);
1235 VTp = inner(VTp, U2, 1, 1);
1236#ifdef BENCH
1237 double cpu6 = wall_time();
1238 SRConf<T>::time(16) += cpu6 - cpu5;
1239#endif
1240
1241 // find the maximal singular value that's supposed to contribute
1242 // singular values are ordered (largest first)
1243 double residual = 0.0;
1244 long i;
1245 for (i = Sp.dim(0) - 1; i >= 0; i--) {
1246 residual += Sp(i) * Sp(i);
1247 if (residual > thresh * thresh) break;
1248 }
1249
1250 // convert SVD output to our convention
1251 if (i >= 0) {
1252 // make it contiguous
1253 tensorT Up1 = transpose(Up(Slice(0, i), s0));
1254 tensorT Up2 = transpose(Up(Slice(0, i), s1));
1255 tensorT VTp1 = transpose(VTp(Slice(0, i), s0));
1256 tensorT VTp2 = transpose(VTp(Slice(0, i), s1));
1257
1258 // transform 1 and 2
1259 x1 = inner(Up1, x1, 0, 0);
1260 inner_result(Up2, x2, 0, 0, x1);
1261 y1 = inner(VTp1, y1, 0, 0);
1262 inner_result(VTp2, y2, 0, 0, y1);
1263 w1 = Sp(Slice(0, i));
1264 }
1265 else {
1266 x1.clear();
1267 y1.clear();
1268 w1.clear();
1269 }
1270#ifdef BENCH
1271 double cpu7 = wall_time();
1272 SRConf<T>::time(17) += cpu7 - cpu6;
1273 SRConf<T>::time(10) += cpu7 - cpu0;
1274#endif
1275 return;
1276 }
1277
1278 template <typename T>
1279 static inline
1280 std::ostream& operator<<(std::ostream& s, const SRConf<T>& sr) {
1281 s << "dim_ " << sr.ndim() << "\n";;
1282 s << "rank_ " << sr.rank_ << "\n";;
1283 s << "vector_.size()" << sr.vector_.size() << "\n";
1284 s << "has_data() " << sr.has_data() << "\n";
1285 s << "TensorType " << sr.type() << "\n\n";
1286 return s;
1287 }
1288}
1289
1290#endif /* SRCONF_H_ */
double w(double t, double eps)
Definition DKops.h:22
static const double small
Definition binaryop.cc:117
std::complex< double > double_complex
Definition cfft.h:14
C++ interface to LAPACK, either directly via Fortran API (see clapack_fortran.h) or via LAPACKE (see ...
bool conforms(const BaseTensor *t) const
Returns true if this and *t are the same shape and size.
Definition basetensor.h:159
long dim(int i) const
Returns the size of dimension i.
Definition basetensor.h:147
const long * dims() const
Returns the array of tensor dimensions.
Definition basetensor.h:153
long _size
Number of elements in the tensor.
Definition basetensor.h:93
void set_dims_and_size(long nd, const long d[])
Definition basetensor.h:99
long _id
Id from TensorTypeData<T> in type_data.h.
Definition basetensor.h:95
BaseTensor()
Definition basetensor.h:116
long _dim[TENSOR_MAXDIM]
Size of each dimension.
Definition basetensor.h:96
long ndim() const
Returns the number of dimensions in the tensor.
Definition basetensor.h:144
long size() const
Returns the number of elements in the tensor.
Definition basetensor.h:138
long _ndim
Number of dimensions (-1=invalid; 0=no supported; >0=tensor).
Definition basetensor.h:94
Definition lowranktensor.h:59
Definition srconf.h:68
long nci_left
separation dimensions: A(n,m) -> A(r,n) B(r,m), with n={k1,k2},m={k3,k4,k5..) multi-indices
Definition srconf.h:94
TensorTypeData< T >::float_scalar_type float_scalar_type
Definition srconf.h:74
SRConf(const long &ndim, const std::array< long, TENSOR_MAXDIM > &dimensions, const long nci)
Definition srconf.h:132
Tensor< T > & ref_vector(const unsigned int &idim)
return reference to one of the vectors F
Definition srconf.h:538
SRConf< T > transform_dir(const Tensor< T > &c, const int &axis) const
Definition srconf.h:884
size_t real_size() const
return the real size of this
Definition srconf.h:720
SRConf< TENSOR_RESULT_TYPE(T, Q)> general_transform(const Tensor< Q > c[]) const
Definition srconf.h:861
const SRConf get_configs(const int &start, const int &end) const
Definition srconf.h:246
unsigned int nCoeff() const
return the number of coefficients
Definition srconf.h:715
std::array< Tensor< T >, 2 > vector_
Definition srconf.h:91
Tensor< T > make_left_vector_with_weights() const
Definition srconf.h:694
void clear()
Definition srconf.h:236
SRConf()
default ctor
Definition srconf.h:123
SRConf< T > transform(const Tensor< T > &c) const
Definition srconf.h:834
bool check_vector_orthonormality(const int ivec) const
check if the terms are orthogonal
Definition srconf.h:634
SRConf & operator=(const T &number)
assign a number to this;
Definition srconf.h:192
bool has_structure() const
return if this has a tensor structure (has not been flattened)
Definition srconf.h:655
bool has_no_data() const
does this have any data?
Definition srconf.h:279
void make_slices()
redo the Slices for getting direct access to the configurations
Definition srconf.h:504
void add_SVD(const SRConf< T > &rhs, const double &thresh)
add two orthonormal configurations, yielding an optimal SVD decomposition
Definition srconf.h:337
void serialize(Archive &ar)
Definition srconf.h:266
Tensor< T >::scalar_type scalar_type
the scalar type of T
Definition srconf.h:73
bool check_dimensions() const
Definition srconf.h:621
void append(const SRConf< T > &rhs, const double_complex fac=1.0)
Definition srconf.h:331
SRConf(const SRConf &rhs)=default
copy ctor (tested); shallow copy
std::vector< Slice > s0
Definition srconf.h:98
void normalize()
normalize the vectors (tested)
Definition srconf.h:592
Tensor< T > tensorT
Definition srconf.h:81
SRConf(const long &ndim, const long *dimensions, const long nci)
Definition srconf.h:125
Tensor< T > flat_vector(const unsigned int &idim)
return shallow copy of a slice of one of the vectors, flattened to (r,kVec)
Definition srconf.h:561
TensorTypeData< T >::float_scalar_type svd_normf() const
calculate the Frobenius norm, if this is in SVD form
Definition srconf.h:784
double weights(const unsigned int &i) const
return the weight
Definition srconf.h:679
void set_size_and_dim(long ndim, long k)
Definition srconf.h:204
SRConf< T > copy_slice(const std::array< Slice, TENSOR_MAXDIM > &s) const
return a slice of this (deep copy)
Definition srconf.h:445
std::array< std::vector< Slice >, 2 > make_slices(const std::array< Slice, TENSOR_MAXDIM > &s) const
Definition srconf.h:512
std::vector< Slice > s1
Definition srconf.h:98
Tensor< T > reconstruct() const
reconstruct this to return a full tensor
Definition srconf.h:682
SRConf(const Tensor< double > &weights, const tensorT &vector1, const tensorT &vector2, const long &ndim, const long *dims, const long nci)
explicit ctor with two vectors (aka SVD), shallow
Definition srconf.h:150
Tensor< typename Tensor< T >::scalar_type > weights_
for each configuration the weight; length should be r
Definition srconf.h:87
SRConf(const Tensor< double > &weights, const std::vector< Tensor< T > > &vectors, const long &ndim, const long &dims, const long nci)
ctor with provided weights and effective vectors; shallow copy
Definition srconf.h:139
Tensor< T > flat_vector_with_weights(const int dim) const
return flat (r,i) view of the tensor with the weights multiplied in
Definition srconf.h:709
long kVec(const int idim) const
Definition srconf.h:548
const Tensor< T > & ref_vector(const unsigned int &idim) const
return reference to one of the vectors F
Definition srconf.h:543
int dim_per_vector(int idim) const
return the number of physical dimensions
Definition srconf.h:673
void set_vectors_and_weights(const Tensor< typename Tensor< T >::scalar_type > &weights, const Tensor< T > &vector1, const Tensor< T > &vector2)
Definition srconf.h:229
long rank() const
return the logicalrank
Definition srconf.h:669
SRConf & operator=(const SRConf &rhs)
assignment operator (tested), shallow copy of vectors
Definition srconf.h:159
static int max_sigma(const double &thresh, const long &rank, const Tensor< double > &w)
Definition srconf.h:109
friend SRConf< T > copy(const SRConf< T > &rhs)
deep copy of rhs, shrink
Definition srconf.h:429
SRConf< T > & emul(const SRConf< T > &other)
perform elementwise Hadamard product
Definition srconf.h:467
~SRConf()
dtor
Definition srconf.h:263
bool has_data() const
does this have any data?
Definition srconf.h:274
friend bool compatible(const SRConf &lhs, const SRConf &rhs)
check compatibility
Definition srconf.h:825
std::enable_if<(TensorTypeData< T >::iscomplexorTensorTypeData< Q >::iscomplex), TENSOR_RESULT_TYPE(T, Q)>::type friend trace(const SRConf< T > &rhs, const SRConf< Q > &lhs)
Definition srconf.h:735
void append(const SRConf< T > &rhs, const double fac=1.0)
append configurations of rhs to this
Definition srconf.h:294
void scale(const double &fac)
scale this by a number
Definition srconf.h:818
TensorTypeData< T >::float_scalar_type normf() const
calculate the Frobenius norm
Definition srconf.h:790
Tensor< T > make_vector_with_weights(const int dim) const
Definition srconf.h:699
bool is_flat() const
return if this has only one additional dimension (apart from rank)
Definition srconf.h:649
const Tensor< T > flat_vector(const unsigned int &idim) const
return shallow copy of a slice of one of the vectors, flattened to (r,kVec)
Definition srconf.h:553
void scale(const double_complex &fac)
Definition srconf.h:820
void make_empty_vectors_and_weights(const long rank)
Definition srconf.h:221
void inplace_add(const SRConf< T > &rhs, std::array< Slice, TENSOR_MAXDIM > lhs_s, std::array< Slice, TENSOR_MAXDIM > rhs_s, const double alpha, const double beta)
alpha * this(lhs_s) + beta * rhs(rhs_s)
Definition srconf.h:395
std::array< std::array< long, TENSOR_MAXDIM >, 2 > make_vector_dimensions(const long rank) const
deduce the dimensions of the left and right singular vectors from the tensor dimensions
Definition srconf.h:211
void make_structure(bool force=false)
Definition srconf.h:528
std::enable_if<!(TensorTypeData< T >::iscomplexorTensorTypeData< Q >::iscomplex), TENSOR_RESULT_TYPE(T, Q)>::type friend trace(const SRConf< T > &rhs, const SRConf< Q > &lhs)
calculate the Frobenius inner product (tested)
Definition srconf.h:744
const std::vector< Slice > & c0(const int idim) const
return a Slice that corresponds the that part of vector_ that holds coefficients
Definition srconf.h:282
static const long check_orthonormality_frequency
check orthonormality at low rank additions at every xth addition
Definition srconf.h:84
implements a temporary(!) slice of a LowRankTensor
Definition lowranktensor.h:957
A slice defines a sub-range or patch of a dimension.
Definition slice.h:103
Traits class to specify support of numeric types.
Definition type_data.h:56
A tensor is a multidimensional array.
Definition tensor.h:313
scalar_type absmax(long *ind=0) const
Return the absolute maximum value (and if ind is non-null, its index) in the Tensor.
Definition tensor.h:1759
float_scalar_type normf() const
Returns the Frobenius norm of the tensor.
Definition tensor.h:1731
T sum() const
Returns the sum of all elements of the tensor.
Definition tensor.h:1667
Tensor< T > reshape(int ndimnew, const long *d)
Returns new view/tensor reshaping size/number of dimensions to conforming tensor.
Definition tensor.h:1389
TensorTypeData< T >::scalar_type scalar_type
C++ typename of the real type associated with a complex type.
Definition tensor.h:405
Tensor< T > & emul(const Tensor< T > &t)
Inplace multiply by corresponding elements of argument Tensor.
Definition tensor.h:1804
Tensor< T > & screen(double x)
Inplace set elements of *this less than x in absolute magnitude to zero.
Definition tensor.h:763
void clear()
Frees all memory and resests to state of default constructor.
Definition tensor.h:1905
archive_array< T > wrap(const T *, unsigned int)
Factory function to wrap a dynamically allocated pointer as a typed archive_array.
Definition archive.h:914
void inner_result(const Tensor< T > &left, const Tensor< Q > &right, long k0, long k1, Tensor< TENSOR_RESULT_TYPE(T, Q) > &result)
Accumulate inner product into user provided, contiguous, correctly sized result tensor.
Definition tensor.h:2327
Tensor< T > transpose(const Tensor< T > &t)
Returns a new deep copy of the transpose of the input tensor.
Definition tensor.h:2039
const double beta
Definition gygi_soltion.cc:62
static const double v
Definition hatom_sf_dirac.cc:20
#define MADNESS_EXCEPTION(msg, value)
Macro for throwing a MADNESS exception.
Definition madness_exception.h:119
#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
Namespace for all elements and tools of MADNESS.
Definition DFConvergence.h:9
void ortho5(Tensor< T > &x1, Tensor< T > &y1, Tensor< typename Tensor< T >::scalar_type > &w1, const Tensor< T > &x2, const Tensor< T > &y2, const Tensor< typename Tensor< T >::scalar_type > &w2, const double &thresh)
specialized version of ortho3
Definition srconf.h:1096
std::ostream & operator<<(std::ostream &os, const particle< PDIM > &p)
Definition lowrankfunction.h:452
double FunctionDefaults< NDIM >::thresh
Definition mraimpl.h:3879
void outer_result(const Tensor< T > &left, const Tensor< T > &right, Tensor< T > &result)
Outer product ... result(i,j,...,p,q,...) = left(i,k,...)*right(p,q,...).
Definition tensor.h:2254
int FunctionDefaults< NDIM >::k
Definition mraimpl.h:3878
void ortho3(Tensor< T > &x, Tensor< T > &y, Tensor< typename Tensor< T >::scalar_type > &weights, const double &thresh)
sophisticated version of ortho2
Definition srconf.h:923
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:2300
Tensor< double > tensorT
Definition distpm.cc:21
static Tensor< double > weights[max_npt+1]
Definition legendre.cc:99
static const Slice _(0,-1, 1)
std::enable_if< std::is_base_of< ProjectorBase, projT >::value, OuterProjector< projT, projQ > >::type outer(const projT &p0, const projQ &p1)
Definition projector.h:476
void svd(const Tensor< T > &a, Tensor< T > &U, Tensor< typename Tensor< T >::scalar_type > &s, Tensor< T > &VT)
Compute the singluar value decomposition of an n-by-m matrix using *gesvd.
Definition lapack.cc:739
double wall_time()
Returns the wall time in seconds relative to an arbitrary origin.
Definition timers.cc:48
void print(const T &t, Ts &&... ts)
Print items to std::cout (items separated by spaces) and terminate with a new line.
Definition print.h:232
GenTensor< TENSOR_RESULT_TYPE(R, Q)> transform_dir(const GenTensor< R > &t, const Tensor< Q > &c, const int axis)
Definition lowranktensor.h:1108
constexpr Vector< T, sizeof...(Ts)+1 > vec(T t, Ts... ts)
Factory function for creating a madness::Vector.
Definition vector.h:750
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:1007
const FunctionCommonData< T, NDIM > * FunctionCommonData< T, NDIM >::data[MAXK]
Definition mraimpl.h:3875
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:2239
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:979
static long abs(long a)
Definition tensor.h:214
Defines simple templates for printing to std::cout "a la Python".
double Q(double a)
Definition relops.cc:20
static const double c
Definition relops.cc:10
static const double s0
Definition tdse4.cc:83
Defines and implements most of Tensor.
Prototypes for a partial interface from Tensor to LAPACK.
#define TENSOR_MAXDIM
Definition tensor_macros.h:194
double norm(const T i1)
Definition test_cloud.cc:85
F residual(const F &f)
Definition testcomplexfunctionsolver.cc:69
static const double alpha
Definition testcosine.cc:10
std::size_t axis
Definition testpdiff.cc:59
#define TENSOR_RESULT_TYPE(L, R)
This macro simplifies access to TensorResultType.
Definition type_data.h:205
const double a1
Definition vnucso.cc:85
FLOAT e1(FLOAT z)
Definition y1.cc:144