LIBINT 2.9.0
integral.h
1/*
2 * Copyright (C) 2004-2024 Edward F. Valeev
3 *
4 * This file is part of Libint compiler.
5 *
6 * Libint compiler 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 compiler 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 compiler. 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 <class_registry.h>
25#include <dgvertex.h>
26#include <equiv.h>
27#include <global_macros.h>
28#include <iter.h>
29#include <oper.h>
30#include <policy_spec.h>
31#include <quanta.h>
32#include <singl_stack.h>
33#include <smart_ptr.h>
34
35#include <cassert>
36
37#if USE_BRAKET_H
38#include <braket.h>
39#endif
40
41extern long living_count;
42
43namespace libint2 {
44
49template <class BasisFunctionSet>
51 public:
52 virtual ~IntegralSet(){};
53
54#if USE_BRAKET_H
56 virtual unsigned int num_part() const = 0;
58 virtual unsigned int num_func_bra(unsigned int p) const = 0;
60 virtual unsigned int num_func_ket(unsigned int p) const = 0;
62 virtual const BasisFunctionSet& bra(unsigned int p, unsigned int i) const = 0;
64 virtual const BasisFunctionSet& ket(unsigned int p, unsigned int i) const = 0;
66 virtual BasisFunctionSet& bra(unsigned int p, unsigned int i) = 0;
68 virtual BasisFunctionSet& ket(unsigned int p, unsigned int i) = 0;
69#else
71 virtual unsigned int np() const = 0;
73 virtual const std::shared_ptr<BasisFunctionSet> bra(unsigned int p,
74 unsigned int i) const = 0;
76 virtual const std::shared_ptr<BasisFunctionSet> ket(unsigned int p,
77 unsigned int i) const = 0;
78#endif
79};
80
93template <class Oper, class BFS, class BraSetType, class KetSetType,
94 class AuxQuanta = EmptySet>
96 : public IntegralSet<BFS>,
97 public DGVertex,
98 public std::enable_shared_from_this<
99 GenIntegralSet<Oper, BFS, BraSetType, KetSetType, AuxQuanta> > {
100 public:
103 typedef GenIntegralSet<
104 typename Oper::iter_type, BFS, typename BraSetType::iter_type,
105 typename KetSetType::iter_type, typename AuxQuanta::iter_type>
111#if USE_INT_KEY_TO_HASH
112 typedef mpz_class key_type;
113#else
114 typedef std::string key_type;
115#endif
119 typedef Oper OperType;
121 typedef typename BraSetType::bfs_type BasisFunctionType;
123 static constexpr auto num_particles = BraSetType::num_particles;
124 static_assert(BraSetType::num_particles == KetSetType::num_particles,
125 "number of particles in bra and ket must be same");
127 static constexpr auto num_bf = BraSetType::num_bf + KetSetType::num_bf;
128
139
141 static const std::shared_ptr<GenIntegralSet> Instance(
142 const BraSetType& bra, const KetSetType& ket, const AuxQuanta& aux,
143 const Oper& oper = Oper());
144
146 virtual bool operator==(const GenIntegralSet&) const;
148 bool equiv(const std::shared_ptr<DGVertex>& v) const override {
149 return PtrComp::equiv(this, v);
150 }
152 unsigned int size() const override;
154 const std::string& label() const override;
156 const std::string& id() const override;
158 std::string description() const override;
159
161 unsigned int num_part() const override { return OperType::Properties::np; }
163 unsigned int num_func_bra(unsigned int p) const override {
164 return bra_.num_members(p);
165 }
167 unsigned int num_func_ket(unsigned int p) const override {
168 return ket_.num_members(p);
169 }
171 typename BraSetType::bfs_cref bra(unsigned int p,
172 unsigned int i) const override;
174 typename KetSetType::bfs_cref ket(unsigned int p,
175 unsigned int i) const override;
177 typename BraSetType::bfs_ref bra(unsigned int p, unsigned int i) override;
179 typename KetSetType::bfs_ref ket(unsigned int p, unsigned int i) override;
180
181 typedef BraSetType BraType;
182 typedef KetSetType KetType;
183 typedef Oper OperatorType;
184 typedef AuxQuanta AuxQuantaType;
185
187 const std::shared_ptr<Oper> oper() const;
189 const BraType& bra() const;
191 const KetType& ket() const;
193 const std::shared_ptr<AuxQuanta> aux() const;
194
196 DGVertex::KeyReturnType key() const override {
197 if (key_ == 0) compute_key();
198 return key_;
199 }
200
202 void unregister() const override;
203
205 virtual bool auto_unroll() const { return false; }
206
207 protected:
208 // Basic Integral constructor. It is protected so that derived classes don't
209 // have to behave like singletons
210 GenIntegralSet(const Oper& oper, const BraSetType& bra, const KetSetType& ket,
211 const AuxQuanta& aux);
214 static key_type compute_key(const Oper& O, const BraType& bra,
215 const KetType& ket, const AuxQuanta& aux) {
216#define TEST_KEYTYPE_SAFETY 0
217#if TEST_KEYTYPE_SAFETY
218 key_type remainder = UINT64_MAX;
219 remainder /= (key_type)aux.max_key();
220 assert(remainder != 0);
221 remainder /= (key_type)ket.max_key();
222 assert(remainder != 0);
223 remainder /= (key_type)bra.max_key();
224 assert(remainder != 0);
225 remainder /= (key_type)O.max_key;
226 assert(remainder != 0);
227#endif
228
229 key_type key;
230
231 key = ((key_type(O.key()) * KeyTypes::cast(bra.max_key()) +
232 KeyTypes::cast(bra.key())) *
233 KeyTypes::cast(ket.max_key()) +
234 KeyTypes::cast(ket.key())) *
235 KeyTypes::cast(aux.max_key()) +
236 KeyTypes::cast(aux.key());
237
238 return key;
239 }
240
241 BraSetType bra_;
242 KetSetType ket_;
243
245 void set_size(unsigned int sz);
247 bool this_precomputed() const override { return false; }
249 void reset_cache() {
250 key_ = 0;
251 size_ = 0;
252 }
253
254 private:
255 //
256 // All integrals are Singletons by nature, therefore they must be treated as
257 // such 1) No public constructors are provided 2) protected members are
258 // provided to implement Singleton-type functionality
259 //
262 // Copy is not permitted
263 GenIntegralSet& operator=(const GenIntegralSet& source);
264
265 // This is used to manage GenIntegralSet objects as singletons
266 static SingletonManagerType singl_manager_;
267
268 // The operator needs to be a real object rather than real type to be able to
269 // construct a SubIterator, etc.
270 std::shared_ptr<Oper> O_;
271 // Same for AuxQuanta
272 std::shared_ptr<AuxQuanta> aux_;
273
274 // size of the integral set
275 mutable unsigned int size_;
276
277 // unique label -- no 2 GenIntegralSet instances can have the same label!
278 mutable std::string label_;
279 // generates label_
280 std::string generate_label() const /*override*/;
281 // key
282 mutable key_type key_;
283
285 void compute_key() const {
286 key_ = compute_key(*(O_.get()), bra_, ket_, *(aux_.get()));
287 }
288};
289
290#if USE_INT_KEY_TO_HASH
291// I use key() to hash GenIntegralSet. Therefore compute_key() must return
292// unique keys!
293template <class Op, class BFS, class BraSetType, class KetSetType,
294 class AuxQuanta>
295typename GenIntegralSet<Op, BFS, BraSetType, KetSetType,
296 AuxQuanta>::SingletonManagerType
297 GenIntegralSet<Op, BFS, BraSetType, KetSetType, AuxQuanta>::singl_manager_(
299#else
300// I use label() to hash GenIntegralSet. Therefore labels must be unique!
301template <class Op, class BFS, class BraSetType, class KetSetType,
302 class AuxQuanta>
303typename GenIntegralSet<Op, BFS, BraSetType, KetSetType,
304 AuxQuanta>::SingletonManagerType
305 GenIntegralSet<Op, BFS, BraSetType, KetSetType, AuxQuanta>::singl_manager_(
307#endif
308
309template <class Op, class BFS, class BraSetType, class KetSetType,
310 class AuxQuanta>
311GenIntegralSet<Op, BFS, BraSetType, KetSetType, AuxQuanta>::GenIntegralSet(
312 const Op& oper, const BraSetType& bra, const KetSetType& ket,
313 const AuxQuanta& aux)
314 : DGVertex(ClassInfo<GenIntegralSet>::Instance().id()),
315 bra_(bra),
316 ket_(ket),
317 O_(std::shared_ptr<Op>(new Op(oper))),
318 aux_(std::shared_ptr<AuxQuanta>(new AuxQuanta(aux))),
319 size_(0),
320 label_() {
321 if (Op::Properties::np != bra.num_part())
322 throw std::runtime_error(
323 "GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::"
324 "GenIntegralSet(bra,ket) -- number of particles in bra doesn't match "
325 "that in the operator");
326 if (Op::Properties::np != ket.num_part())
327 throw std::runtime_error(
328 "GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::"
329 "GenIntegralSet(bra,ket) -- number of particles in ket doesn't match "
330 "that in the operator");
331 compute_key();
332#if DEBUG
333 std::cout << "GenIntegralSet: constructed " << label() << std::endl;
334 std::cout << "GenIntegralSet: living_count = " << ++living_count << std::endl;
335#endif
336}
337
338template <class Op, class BFS, class BraSetType, class KetSetType,
339 class AuxQuanta>
341#if DEBUG
342 std::cout << "GenIntegralSet: destructed " << label() << std::endl;
343 std::cout << "GenIntegralSet: living_count = " << --living_count << std::endl;
344#endif
345}
346
347template <class Op, class BFS, class BraSetType, class KetSetType,
348 class AuxQuanta>
349const std::shared_ptr<
352 const BraSetType& bra, const KetSetType& ket, const AuxQuanta& aux,
353 const Op& oper) {
354 typedef typename SingletonManagerType::value_type map_value_type;
355 key_type key = compute_key(oper, bra, ket, aux);
356 const map_value_type& val = singl_manager_.find(key);
357 if (!val.second) {
358 std::shared_ptr<this_type> this_int(new this_type(oper, bra, ket, aux));
359 // Use singl_manager_ to make sure this is a new object of this type
360 const map_value_type& val = singl_manager_.find(this_int);
361 val.second->instid_ = val.first;
362 this_int.reset();
363 return val.second;
364 }
365 return val.second;
366}
367
368template <class Op, class BFS, class BraSetType, class KetSetType,
369 class AuxQuanta>
370typename BraSetType::bfs_cref
372 unsigned int p, unsigned int i) const {
373 return bra_.member(p, i);
374}
375
376template <class Op, class BFS, class BraSetType, class KetSetType,
377 class AuxQuanta>
378typename KetSetType::bfs_cref
380 unsigned int p, unsigned int i) const {
381 return ket_.member(p, i);
382}
383
384template <class Op, class BFS, class BraSetType, class KetSetType,
385 class AuxQuanta>
386typename BraSetType::bfs_ref GenIntegralSet<Op, BFS, BraSetType, KetSetType,
387 AuxQuanta>::bra(unsigned int p,
388 unsigned int i) {
389 reset_cache();
390 return bra_.member(p, i);
391}
392
393template <class Op, class BFS, class BraSetType, class KetSetType,
394 class AuxQuanta>
395typename KetSetType::bfs_ref GenIntegralSet<Op, BFS, BraSetType, KetSetType,
396 AuxQuanta>::ket(unsigned int p,
397 unsigned int i) {
398 reset_cache();
399 return ket_.member(p, i);
400}
401
402template <class Op, class BFS, class BraSetType, class KetSetType,
403 class AuxQuanta>
404const typename GenIntegralSet<Op, BFS, BraSetType, KetSetType,
405 AuxQuanta>::BraType&
409
410template <class Op, class BFS, class BraSetType, class KetSetType,
411 class AuxQuanta>
412const typename GenIntegralSet<Op, BFS, BraSetType, KetSetType,
413 AuxQuanta>::KetType&
417
418template <class Op, class BFS, class BraSetType, class KetSetType,
419 class AuxQuanta>
420const std::shared_ptr<Op>
424
425template <class Op, class BFS, class BraSetType, class KetSetType,
426 class AuxQuanta>
427const std::shared_ptr<AuxQuanta>
431
432template <class Op, class BFS, class BraSetType, class KetSetType,
433 class AuxQuanta>
435 const this_type& a) const {
436#if USE_INT_KEY_TO_COMPARE
437 return key() == a.key();
438#else
439 bool aux_equiv = PtrEquiv<AuxQuanta>::equiv(aux_, a.aux_);
440 if (!aux_equiv) return false;
441 bool oper_equiv = PtrEquiv<Op>::equiv(O_, a.O_);
442 bool bra_equiv = PtrEquiv<BraSetType>::equiv(bra_, a.bra_);
443 if (!bra_equiv) return false;
444 bool ket_equiv = PtrEquiv<KetSetType>::equiv(ket_, a.ket_);
445 if (!ket_equiv) return false;
446 return true;
447#endif
448}
449
450template <class Op, class BFS, class BraSetType, class KetSetType,
451 class AuxQuanta>
453 const {
454 singl_manager_.remove(std::const_pointer_cast<this_type, const this_type>(
455 std::enable_shared_from_this<this_type>::shared_from_this()));
456}
457
458template <class Op, class BFS, class BraSetType, class KetSetType,
459 class AuxQuanta>
461 const {
462 if (size_ > 0) return size_;
463
464#if COMPUTE_SIZE_DIRECTLY
465 // WARNING: will not work if aux_ includes "sets" of numbers, i.e. when a
466 // quantum number can be a set of numbers but I don't at the moment see why
467 // this would be needed
468 size_ = bra_.size() * ket_.size() * O_->num_oper();
469#else
470 // compute size
471 std::shared_ptr<this_type> this_ptr =
472 std::const_pointer_cast<this_type, const this_type>(
473 std::enable_shared_from_this<GenIntegralSet>::shared_from_this());
474 std::shared_ptr<SubIteratorBase<this_type> > siter(
475 new SubIteratorBase<this_type>(this_ptr));
476 size_ = siter->num_iter();
477 if (size_ == 0)
478 throw std::runtime_error(
479 "GenIntegralSet<Op,BFS,BraSetType,KetSetType,AuxQuanta>::size() -- "
480 "size is 0");
481#endif
482
483 return size_;
484}
485
486template <class Op, class BFS, class BraSetType, class KetSetType,
487 class AuxQuanta>
489 unsigned int sz) {
490 size_ = sz;
491}
492
493template <class BraSetType, class KetSetType, class AuxQuanta, class Op>
494std::string genintegralset_label(const BraSetType& bra, const KetSetType& ket,
495 const std::shared_ptr<AuxQuanta>& aux,
496 const std::shared_ptr<Op>& O) {
497 std::ostringstream os;
498 os << "< ";
499 for (unsigned int p = 0; p < Op::Properties::np; p++) {
500 unsigned int nbra = bra.num_members(p);
501 for (unsigned int i = 0; i < nbra; i++)
502#if USE_BRAKET_H
503 os << bra.member(p, i).label() << "(" << p << ") ";
504#else
505 os << bra.member(p, i)->label() << "(" << p << ") ";
506#endif
507 }
508 os << "| " << O->label() << " | ";
509 for (unsigned int p = 0; p < Op::Properties::np; p++) {
510 unsigned int nket = ket.num_members(p);
511 for (unsigned int i = 0; i < nket; i++)
512#if USE_BRAKET_H
513 os << ket.member(p, i).label() << "(" << p << ") ";
514#else
515 os << ket.member(p, i)->label() << "(" << p << ") ";
516#endif
517 }
518 os << "> ^ { " << aux->label() << " }";
519 return os.str();
520}
521
522template <class Op, class BFS, class BraSetType, class KetSetType,
523 class AuxQuanta>
524const std::string&
526 if (label_.empty()) label_ = generate_label();
527 return label_;
528}
529
530template <class Op, class BFS, class BraSetType, class KetSetType,
531 class AuxQuanta>
532std::string GenIntegralSet<Op, BFS, BraSetType, KetSetType,
533 AuxQuanta>::generate_label() const {
534 return genintegralset_label(bra_, ket_, aux_, O_);
535}
536
537template <class Op, class BFS, class BraSetType, class KetSetType,
538 class AuxQuanta>
539const std::string&
543
544template <class Op, class BFS, class BraSetType, class KetSetType,
545 class AuxQuanta>
546std::string GenIntegralSet<Op, BFS, BraSetType, KetSetType,
547 AuxQuanta>::description() const {
548 std::ostringstream os;
549 os << " GenIntegralSet: " << label();
550 const std::string descr = os.str();
551 return descr;
552}
553
554}; // namespace libint2
555
556#endif
ArrayBraket is a lightweight implementation of Braket concept.
Definition src/bin/libint/braket.h:39
This is a vertex of a Directed Graph (DG)
Definition dgvertex.h:44
GenIntegralSet is a set of integrals over functions derived from BFS.
Definition integral.h:99
const std::string & label() const override
Specialization of DGVertex::label()
Definition integral.h:525
virtual bool operator==(const GenIntegralSet &) const
Comparison operator.
Definition integral.h:434
SingletonStack< GenIntegralSet, key_type > SingletonManagerType
This the type of the object that manages GenIntegralSet's as Singletons.
Definition integral.h:117
BraSetType::bfs_cref bra(unsigned int p, unsigned int i) const override
Implementation of IntegralSet::bra() const.
Definition integral.h:371
const BraType & bra() const
Obtain const ref to bra.
Definition integral.h:406
unsigned int num_func_bra(unsigned int p) const override
Implementation of IntegralSet::num_func_bra.
Definition integral.h:163
virtual ~GenIntegralSet()
No constructors are public since this is a singleton-like quantity.
Definition integral.h:340
virtual bool auto_unroll() const
If consists of precomputed elements, override this to return true.
Definition integral.h:205
std::string description() const override
Specialization of DGVertex::description()
Definition integral.h:547
static constexpr auto num_particles
The number of particles.
Definition integral.h:123
IntegralSet< BFS > parent_type
GenIntegralSet is derived from IntegralSet.
Definition integral.h:108
Oper OperType
This is the type of the operator.
Definition integral.h:119
DGVertex::KeyReturnType key() const override
Implements Hashable::key()
Definition integral.h:196
BraSetType::bfs_ref bra(unsigned int p, unsigned int i) override
Implementation of IntegralSet::bra()
Definition integral.h:387
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:106
bool this_precomputed() const override
Specialization of DGVertex::this_precomputed()
Definition integral.h:247
const KetType & ket() const
Obtain const ref to bra.
Definition integral.h:414
BraSetType::bfs_type BasisFunctionType
This is the real type of basis functions.
Definition integral.h:121
bool equiv(const std::shared_ptr< DGVertex > &v) const override
Specialization of DGVertex::equiv()
Definition integral.h:148
static key_type compute_key(const Oper &O, const BraType &bra, const KetType &ket, const AuxQuanta &aux)
computes a key.
Definition integral.h:214
static const std::shared_ptr< 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:351
unsigned int num_func_ket(unsigned int p) const override
Implementation of IntegralSet::num_func_ket.
Definition integral.h:167
KetSetType::bfs_cref ket(unsigned int p, unsigned int i) const override
Implementation of IntegralSet::ket() const.
Definition integral.h:379
unsigned int num_part() const override
Implementation of IntegralSet::num_part.
Definition integral.h:161
void unregister() const override
Reimplements DGVertex::unregister()
Definition integral.h:452
const std::shared_ptr< Oper > oper() const
Obtain the operator.
Definition integral.h:421
const std::string & id() const override
Specialization of DGVertex::id()
Definition integral.h:540
static constexpr auto num_bf
The total number of basis functions.
Definition integral.h:127
const std::shared_ptr< AuxQuanta > aux() const
Obtain the auxiliary quanta.
Definition integral.h:428
void set_size(unsigned int sz)
set size to sz
Definition integral.h:488
PtrEquiv< GenIntegralSet > PtrComp
This type provides comparison operations on pointers to GenIntegralSet.
Definition integral.h:110
unsigned int size() const override
Specialization of DGVertex::size()
Definition integral.h:460
KetSetType::bfs_ref ket(unsigned int p, unsigned int i) override
Implementation of IntegralSet::ket()
Definition integral.h:396
void reset_cache()
Resets all cached values.
Definition integral.h:249
This is an abstract base for sets of all types of integrals.
Definition integral.h:50
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 const std::shared_ptr< BasisFunctionSet > bra(unsigned int p, unsigned int i) const =0
Obtain pointers to ith BasisFunctionSet for particle p in bra.
virtual unsigned int num_func_bra(unsigned int p) const =0
Return the number of functions for particle p.
virtual const std::shared_ptr< BasisFunctionSet > ket(unsigned int p, unsigned int i) const =0
Obtain pointers to ith BasisFunctionSet for particle p in ket.
virtual BasisFunctionSet & bra(unsigned int p, unsigned int i)=0
Obtain pointers to ith BasisFunctionSet for particle p in bra.
virtual unsigned int num_oper() const =0
Number of operators in the set.
Oper is OperSet characterized by properties Props.
Definition oper.h:91
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:193
SingletonStack<T,KeyType> helps to implement Singleton-like objects of type T.
Definition singl_stack.h:45
SubIteratorBase<T> provides a base class for a sub-iterator class for T.
Definition iter.h:73
Defaults definitions for various parameters assumed by Libint.
Definition algebra.cc:24