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