LIBINT 2.7.2
integral.h
1/*
2 * Copyright (C) 2004-2021 Edward F. Valeev
3 *
4 * This file is part of Libint.
5 *
6 * Libint 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 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Libint 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 Libint. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#ifndef _libint2_src_bin_libint_integral_h_
22#define _libint2_src_bin_libint_integral_h_
23
24#include <cassert>
25#include <smart_ptr.h>
26#include <dgvertex.h>
27#include <oper.h>
28#include <iter.h>
29#include <policy_spec.h>
30#include <quanta.h>
31#include <equiv.h>
32#include <singl_stack.h>
33#include <class_registry.h>
34#include <global_macros.h>
35
36#if USE_BRAKET_H
37# include <braket.h>
38#endif
39
40extern long living_count;
41
42namespace libint2 {
43
48 template <class BasisFunctionSet> class IntegralSet {
49
50 public:
51 virtual ~IntegralSet() {};
52
53#if USE_BRAKET_H
55 virtual unsigned int num_part() const =0;
57 virtual unsigned int num_func_bra(unsigned int p) const =0;
59 virtual unsigned int num_func_ket(unsigned int p) const =0;
61 virtual const BasisFunctionSet& bra(unsigned int p, unsigned int i) const =0;
63 virtual const BasisFunctionSet& ket(unsigned int p, unsigned int i) const =0;
65 virtual BasisFunctionSet& bra(unsigned int p, unsigned int i) =0;
67 virtual BasisFunctionSet& ket(unsigned int p, unsigned int i) =0;
68#else
70 virtual unsigned int np() const =0;
72 virtual const SafePtr<BasisFunctionSet> bra(unsigned int p, unsigned int i) const =0;
74 virtual const SafePtr<BasisFunctionSet> ket(unsigned int p, unsigned int i) const =0;
75#endif
76 };
77
88 template <class Oper, class BFS, class BraSetType, class KetSetType, class AuxQuanta = EmptySet>
90 public IntegralSet<BFS>, public DGVertex,
91 public EnableSafePtrFromThis< GenIntegralSet<Oper,BFS,BraSetType,KetSetType,AuxQuanta> >
92 {
93 public:
101#if USE_INT_KEY_TO_HASH
102 typedef mpz_class key_type;
103#else
104 typedef std::string key_type;
105#endif
109 typedef Oper OperType;
111 typedef typename BraSetType::bfs_type BasisFunctionType;
113 static constexpr auto num_particles = BraSetType::num_particles;
114 static_assert(BraSetType::num_particles == KetSetType::num_particles,
115 "number of particles in bra and ket must be same");
117 static constexpr auto num_bf = BraSetType::num_bf + KetSetType::num_bf;
118
127
129 static const SafePtr<GenIntegralSet> Instance(const BraSetType& bra, const KetSetType& ket, const AuxQuanta& aux, const Oper& oper=Oper());
130
132 virtual bool operator==(const GenIntegralSet&) const;
134 bool equiv(const SafePtr<DGVertex>& v) const override
135 {
136 return PtrComp::equiv(this,v);
137 }
139 unsigned int size() const override;
141 const std::string& label() const override;
143 const std::string& id() const override;
145 std::string description() const override;
146
148 unsigned int num_part() const override { return OperType::Properties::np; }
150 unsigned int num_func_bra(unsigned int p) const override { return bra_.num_members(p); }
152 unsigned int num_func_ket(unsigned int p) const override { return ket_.num_members(p); }
154 typename BraSetType::bfs_cref bra(unsigned int p, unsigned int i) const override;
156 typename KetSetType::bfs_cref ket(unsigned int p, unsigned int i) const override;
158 typename BraSetType::bfs_ref bra(unsigned int p, unsigned int i) override;
160 typename KetSetType::bfs_ref ket(unsigned int p, unsigned int i) override;
161
162 typedef BraSetType BraType;
163 typedef KetSetType KetType;
164 typedef Oper OperatorType;
165 typedef AuxQuanta AuxQuantaType;
166
168 const SafePtr<Oper> oper() const;
170 const BraType& bra() const;
172 const KetType& ket() const;
174 const SafePtr<AuxQuanta> aux() const;
175
177 DGVertex::KeyReturnType key() const override {
178 if (key_ == 0) compute_key();
179 return key_;
180 }
181
183 void unregister() const override;
184
186 virtual bool auto_unroll() const { return false; }
187
188 protected:
189 // Basic Integral constructor. It is protected so that derived classes don't have to behave like singletons
190 GenIntegralSet(const Oper& oper, const BraSetType& bra, const KetSetType& ket, const AuxQuanta& aux);
192 static key_type compute_key(const Oper& O, const BraType& bra, const KetType& ket, const AuxQuanta& aux) {
193#define TEST_KEYTYPE_SAFETY 0
194#if TEST_KEYTYPE_SAFETY
195 key_type remainder = UINT64_MAX;
196 remainder /= (key_type)aux.max_key(); assert(remainder != 0);
197 remainder /= (key_type)ket.max_key(); assert(remainder != 0);
198 remainder /= (key_type)bra.max_key(); assert(remainder != 0);
199 remainder /= (key_type)O.max_key; assert(remainder != 0);
200#endif
201
202 key_type key;
203
204 key = ( (key_type(O.key()) * KeyTypes::cast(bra.max_key()) + KeyTypes::cast(bra.key()) ) * KeyTypes::cast(ket.max_key()) +
205 KeyTypes::cast(ket.key()) ) * KeyTypes::cast(aux.max_key()) + KeyTypes::cast(aux.key());
206
207 return key;
208
209 }
210
211 BraSetType bra_;
212 KetSetType ket_;
213
215 void set_size(unsigned int sz);
217 bool this_precomputed() const override { return false; }
219 void reset_cache() { key_ = 0; size_ = 0; }
220
221 private:
222 //
223 // All integrals are Singletons by nature, therefore they must be treated as such
224 // 1) No public constructors are provided
225 // 2) protected members are provided to implement Singleton-type functionality
226 //
229 // Copy is not permitted
230 GenIntegralSet& operator=(const GenIntegralSet& source);
231
232 // This is used to manage GenIntegralSet objects as singletons
233 static SingletonManagerType singl_manager_;
234
235 // The operator needs to be a real object rather than real type to be able to construct a SubIterator, etc.
236 SafePtr<Oper> O_;
237 // Same for AuxQuanta
238 SafePtr<AuxQuanta> aux_;
239
240 // size of the integral set
241 mutable unsigned int size_;
242
243 // unique label -- no 2 GenIntegralSet instances can have the same label!
244 mutable std::string label_;
245 // generates label_
246 std::string generate_label() const /*override*/;
247 // key
248 mutable key_type key_;
249
251 void compute_key() const {
252 key_ = compute_key(*(O_.get()),bra_,ket_,*(aux_.get()));
253 }
254
255 };
256
257#if USE_INT_KEY_TO_HASH
258 // I use key() to hash GenIntegralSet. Therefore compute_key() must return unique keys!
259 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
261 GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::singl_manager_(&GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::key);
262#else
263 // I use label() to hash GenIntegralSet. Therefore labels must be unique!
264 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
266 GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::singl_manager_(&GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::label);
267#endif
268
269 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
270 GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::GenIntegralSet(const Op& oper, const BraSetType& bra, const KetSetType& ket, const AuxQuanta& aux) :
271 DGVertex(ClassInfo<GenIntegralSet>::Instance().id()), bra_(bra), ket_(ket), O_(SafePtr<Op>(new Op(oper))), aux_(SafePtr<AuxQuanta>(new AuxQuanta(aux))),
272 size_(0), label_()
273 {
274 if (Op::Properties::np != bra.num_part())
275 throw std::runtime_error("GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::GenIntegralSet(bra,ket) -- number of particles in bra doesn't match that in the operator");
276 if (Op::Properties::np != ket.num_part())
277 throw std::runtime_error("GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::GenIntegralSet(bra,ket) -- number of particles in ket doesn't match that in the operator");
278 compute_key();
279#if DEBUG
280 std::cout << "GenIntegralSet: constructed " << label() << std::endl;
281 std::cout << "GenIntegralSet: living_count = " << ++living_count << std::endl;
282#endif
283 }
284
285 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
287 {
288#if DEBUG
289 std::cout << "GenIntegralSet: destructed " << label() << std::endl;
290 std::cout << "GenIntegralSet: living_count = " << --living_count << std::endl;
291#endif
292 }
293
294 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
295 const SafePtr< GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta> >
296 GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::Instance(const BraSetType& bra, const KetSetType& ket, const AuxQuanta& aux, const Op& oper)
297 {
298 typedef typename SingletonManagerType::value_type map_value_type;
299 key_type key = compute_key(oper,bra,ket,aux);
300 const map_value_type& val = singl_manager_.find(key);
301 if (!val.second) {
302 SafePtr<this_type> this_int(new this_type(oper,bra,ket,aux));
303 // Use singl_manager_ to make sure this is a new object of this type
304 const map_value_type& val = singl_manager_.find(this_int);
305 val.second->instid_ = val.first;
306 this_int.reset();
307 return val.second;
308 }
309 return val.second;
310 }
311
312 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
313 typename BraSetType::bfs_cref
315 {
316 return bra_.member(p,i);
317 }
318
319 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
320 typename KetSetType::bfs_cref
322 {
323 return ket_.member(p,i);
324 }
325
326 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
327 typename BraSetType::bfs_ref
329 {
330 reset_cache();
331 return bra_.member(p,i);
332 }
333
334 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
335 typename KetSetType::bfs_ref
337 {
338 reset_cache();
339 return ket_.member(p,i);
340 }
341
342 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
343 const typename GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::BraType&
345 {
346 return bra_;
347 }
348
349 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
350 const typename GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::KetType&
352 {
353 return ket_;
354 }
355
356 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
357 const SafePtr<Op>
359 {
360 return O_;
361 }
362
363 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
364 const SafePtr<AuxQuanta>
366 {
367 return aux_;
368 }
369
370 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
371 bool
373 {
374#if USE_INT_KEY_TO_COMPARE
375 return key() == a.key();
376#else
377 bool aux_equiv = PtrEquiv<AuxQuanta>::equiv(aux_,a.aux_);
378 if (!aux_equiv) return false;
379 bool oper_equiv = PtrEquiv<Op>::equiv(O_,a.O_);
380 bool bra_equiv = PtrEquiv<BraSetType>::equiv(bra_,a.bra_);
381 if (!bra_equiv) return false;
382 bool ket_equiv = PtrEquiv<KetSetType>::equiv(ket_,a.ket_);
383 if (!ket_equiv) return false;
384 return true;
385#endif
386 }
387
388 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
389 void
391 {
392 singl_manager_.remove(const_pointer_cast<this_type,const this_type>(EnableSafePtrFromThis<this_type>::SafePtr_from_this()));
393 }
394
395 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
396 unsigned int
398 {
399 if (size_ > 0)
400 return size_;
401
402#if COMPUTE_SIZE_DIRECTLY
403 // WARNING: will not work if aux_ includes "sets" of numbers, i.e. when a quantum number can be a set of numbers
404 // but I don't at the moment see why this would be needed
405 size_ = bra_.size() * ket_.size() * O_->num_oper();
406#else
407 // compute size
408 SafePtr<this_type> this_ptr = const_pointer_cast<this_type,const this_type>(EnableSafePtrFromThis<GenIntegralSet>::SafePtr_from_this());
409 SafePtr< SubIteratorBase<this_type> > siter(new SubIteratorBase<this_type>(this_ptr));
410 size_ = siter->num_iter();
411 if (size_ == 0)
412 throw std::runtime_error("GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::size() -- size is 0");
413#endif
414
415 return size_;
416 }
417
418 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
419 void
421 {
422 size_ = sz;
423 }
424
425 template <class BraSetType, class KetSetType, class AuxQuanta, class Op>
426 std::string
427 genintegralset_label(const BraSetType& bra, const KetSetType& ket, const SafePtr<AuxQuanta>& aux, const SafePtr<Op>& O)
428 {
429 std::ostringstream os;
430 os << "< ";
431 for(unsigned int p=0; p<Op::Properties::np; p++) {
432 unsigned int nbra = bra.num_members(p);
433 for(unsigned int i=0; i<nbra; i++)
434#if USE_BRAKET_H
435 os << bra.member(p,i).label() << "(" << p << ") ";
436#else
437 os << bra.member(p,i)->label() << "(" << p << ") ";
438#endif
439 }
440 os << "| " << O->label() << " | ";
441 for(unsigned int p=0; p<Op::Properties::np; p++) {
442 unsigned int nket = ket.num_members(p);
443 for(unsigned int i=0; i<nket; i++)
444#if USE_BRAKET_H
445 os << ket.member(p,i).label() << "(" << p << ") ";
446#else
447 os << ket.member(p,i)->label() << "(" << p << ") ";
448#endif
449 }
450 os << "> ^ { " << aux->label() << " }";
451 return os.str();
452 }
453
454 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
455 const std::string&
457 {
458 if (label_.empty())
459 label_ = generate_label();
460 return label_;
461 }
462
463 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
464 std::string
466 {
467 return genintegralset_label(bra_,ket_,aux_,O_);
468 }
469
470 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
471 const std::string&
473 {
474 return label();
475 }
476
477 template <class Op, class BFS, class BraSetType, class KetSetType, class AuxQuanta>
478 std::string
480 {
481 std::ostringstream os;
482 os << " GenIntegralSet: " << label();
483 const std::string descr = os.str();
484 return descr;
485 }
486
487};
488
489#endif
ArrayBraket is a lightweight implementation of Braket concept.
Definition: src/bin/libint/braket.h:38
This is a vertex of a Directed Graph (DG)
Definition: dgvertex.h:43
GenIntegralSet is a set of integrals over functions derived from BFS.
Definition: integral.h:92
const std::string & label() const override
Specialization of DGVertex::label()
Definition: integral.h:456
GenIntegralSet< typename Oper::iter_type, BFS, typename BraSetType::iter_type, typename KetSetType::iter_type, typename AuxQuanta::iter_type > iter_type
GenIntegralSet is a set of these subobjects.
Definition: integral.h:96
virtual bool operator==(const GenIntegralSet &) const
Comparison operator.
Definition: integral.h:372
BraSetType::bfs_cref bra(unsigned int p, unsigned int i) const override
Implementation of IntegralSet::bra() const.
Definition: integral.h:314
const BraType & bra() const
Obtain const ref to bra.
Definition: integral.h:344
unsigned int num_func_bra(unsigned int p) const override
Implementation of IntegralSet::num_func_bra.
Definition: integral.h:150
virtual ~GenIntegralSet()
No constructors are public since this is a singleton-like quantity.
Definition: integral.h:286
virtual bool auto_unroll() const
If consists of precomputed elements, override this to return true.
Definition: integral.h:186
std::string description() const override
Specialization of DGVertex::description()
Definition: integral.h:479
static constexpr auto num_particles
The number of particles.
Definition: integral.h:113
IntegralSet< BFS > parent_type
GenIntegralSet is derived from IntegralSet.
Definition: integral.h:98
Oper OperType
This is the type of the operator.
Definition: integral.h:109
DGVertex::KeyReturnType key() const override
Implements Hashable::key()
Definition: integral.h:177
bool equiv(const SafePtr< DGVertex > &v) const override
Specialization of DGVertex::equiv()
Definition: integral.h:134
BraSetType::bfs_ref bra(unsigned int p, unsigned int i) override
Implementation of IntegralSet::bra()
Definition: integral.h:328
bool this_precomputed() const override
Specialization of DGVertex::this_precomputed()
Definition: integral.h:217
const KetType & ket() const
Obtain const ref to bra.
Definition: integral.h:351
BraSetType::bfs_type BasisFunctionType
This is the real type of basis functions.
Definition: integral.h:111
static key_type compute_key(const Oper &O, const BraType &bra, const KetType &ket, const AuxQuanta &aux)
computes a key. it's protected so that derived classes can use it to implement smart caching in const...
Definition: integral.h:192
const SafePtr< AuxQuanta > aux() const
Obtain the auxiliary quanta.
Definition: integral.h:365
unsigned int num_func_ket(unsigned int p) const override
Implementation of IntegralSet::num_func_ket.
Definition: integral.h:152
KetSetType::bfs_cref ket(unsigned int p, unsigned int i) const override
Implementation of IntegralSet::ket() const.
Definition: integral.h:321
unsigned int num_part() const override
Implementation of IntegralSet::num_part.
Definition: integral.h:148
void unregister() const override
Reimplements DGVertex::unregister()
Definition: integral.h:390
const std::string & id() const override
Specialization of DGVertex::id()
Definition: integral.h:472
static constexpr auto num_bf
The total number of basis functions.
Definition: integral.h:117
void set_size(unsigned int sz)
set size to sz
Definition: integral.h:420
SingletonStack< GenIntegralSet, key_type > SingletonManagerType
This the type of the object that manages GenIntegralSet's as Singletons.
Definition: integral.h:107
PtrEquiv< GenIntegralSet > PtrComp
This type provides comparison operations on pointers to GenIntegralSet.
Definition: integral.h:100
unsigned int size() const override
Specialization of DGVertex::size()
Definition: integral.h:397
KetSetType::bfs_ref ket(unsigned int p, unsigned int i) override
Implementation of IntegralSet::ket()
Definition: integral.h:336
static const SafePtr< GenIntegralSet > Instance(const BraSetType &bra, const KetSetType &ket, const AuxQuanta &aux, const Oper &oper=Oper())
Returns a pointer to a unique instance, a la Singleton.
Definition: integral.h:296
void reset_cache()
Resets all cached values.
Definition: integral.h:219
const SafePtr< Oper > oper() const
Obtain the operator.
Definition: integral.h:358
This is an abstract base for sets of all types of integrals.
Definition: integral.h:48
virtual unsigned int num_func_ket(unsigned int p) const =0
Return the number of functions for particle p.
virtual unsigned int num_part() const =0
Return the number of particles.
virtual BasisFunctionSet & ket(unsigned int p, unsigned int i)=0
Obtain pointers to ith BasisFunctionSet for particle p in ket.
virtual const BasisFunctionSet & bra(unsigned int p, unsigned int i) const =0
Obtain pointers to ith BasisFunctionSet for particle p in bra.
virtual const BasisFunctionSet & ket(unsigned int p, unsigned int i) const =0
Obtain pointers to ith BasisFunctionSet for particle p in ket.
virtual unsigned int np() const =0
Return the number of particles.
virtual unsigned int num_func_bra(unsigned int p) const =0
Return the number of functions for particle p.
virtual const SafePtr< BasisFunctionSet > bra(unsigned int p, unsigned int i) const =0
Obtain pointers to ith BasisFunctionSet for particle p in bra.
virtual BasisFunctionSet & bra(unsigned int p, unsigned int i)=0
Obtain pointers to ith BasisFunctionSet for particle p in bra.
virtual const SafePtr< BasisFunctionSet > ket(unsigned int p, unsigned int i) const =0
Obtain pointers to ith BasisFunctionSet for particle p in ket.
Oper is OperSet characterized by properties Props.
Definition: oper.h:90
PtrEquiv<T> provides a set of comparison functions named 'equiv' which take as arguments a mix of ref...
Definition: equiv.h:36
QuantumNumbersA<T,N> is a set of N quantum numbers of type T implemented in terms of a C-style array.
Definition: quanta.h:197
SingletonStack<T,KeyType> helps to implement Singleton-like objects of type T.
Definition: singl_stack.h:44
SubIteratorBase<T> provides a base class for a sub-iterator class for T.
Definition: iter.h:70
Defaults definitions for various parameters assumed by Libint.
Definition: algebra.cc:24