LIBINT 2.9.0
comp_deriv_gauss.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_compderivgauss_h_
22#define _libint2_src_bin_libint_compderivgauss_h_
23
24#include <generic_rr.h>
25
26#include <set>
27
28namespace libint2 {
29
31 static CR_DerivGauss_GenericInstantiator instance_;
32
33 CR_DerivGauss_GenericInstantiator(); // this is a singleton
35
36 // pairs of L,vectorize specify the instances of GenericGaussDeriv template to
37 // be created
38 std::set<std::pair<unsigned int, bool> > template_instances_;
39
40 public:
41 static CR_DerivGauss_GenericInstantiator& instance();
42 void add(unsigned int L, bool vectorize);
43};
44
62template <class IntType, int part, FunctionPosition where,
63 int trans_inv_part = -1, FunctionPosition trans_inv_where = InBra>
66 CR_DerivGauss<IntType, part, where, trans_inv_part, trans_inv_where>,
67 typename IntType::BasisFunctionType, IntType> {
68 private:
69 static constexpr auto trans_inv_oper =
70 not IntType::OperType::Properties::odep;
71 // can use translational invariance iff the operator is
72 // translationally-invariant
73 static constexpr auto using_trans_inv =
74 trans_inv_oper && (part == trans_inv_part) && (where == trans_inv_where);
75
76 public:
77 typedef CR_DerivGauss ThisType;
78 typedef typename IntType::BasisFunctionType BasisFunctionType;
79 typedef IntType TargetType;
82 friend class GenericRecurrenceRelation<ThisType, BasisFunctionType,
83 TargetType>;
84 // # of children varies:
85 // 1. translational invariance makes num_functions - 1 children
86 // 2. direct differentiation always makes at most 2 Gaussians
87 static constexpr auto max_nchildren =
88 using_trans_inv ? (IntType::num_bf - 1) : 2u;
89
91
94 static bool directional() { return true; }
95
96 private:
98 using ParentType::target_;
99 using ParentType::RecurrenceRelation::expr_;
100 using ParentType::RecurrenceRelation::nflops_;
101
104 CR_DerivGauss(const std::shared_ptr<TargetType>&, unsigned int dir);
105
106 static std::string descr() { return "CR_DerivGauss"; }
111 std::string generate_label() const override {
112 typedef typename TargetType::AuxIndexType mType;
113 static std::shared_ptr<mType> aux0(new mType(0u));
114 std::ostringstream os;
115 os << descr() << "P" << part << to_string(where)
116 << genintegralset_label(target_->bra(), target_->ket(), aux0,
117 target_->oper());
118 return os.str();
119 }
120
121#if LIBINT_ENABLE_GENERIC_CODE
123 bool has_generic(
124 const std::shared_ptr<CompilationParameters>& cparams) const override;
126 std::string generic_header() const override;
128 std::string generic_instance(
129 const std::shared_ptr<CodeContext>& context,
130 const std::shared_ptr<CodeSymbols>& args) const override;
131#endif
132};
133
134template <class IntType, int part, FunctionPosition where, int trans_inv_part,
135 FunctionPosition trans_inv_where>
136CR_DerivGauss<IntType, part, where, trans_inv_part, trans_inv_where>::
137 CR_DerivGauss(const std::shared_ptr<TargetType>& Tint, unsigned int dir)
138 : ParentType(Tint, dir) {
139 using namespace libint2::algebra;
140 using namespace libint2::prefactor;
141 using namespace libint2::braket;
142 typedef BasisFunctionType F;
143 const F& _1 = unit<F>(
144 is_simple() ? dir : 0); // for shell sets increment the first index
145
146 const typename IntType::AuxQuantaType& aux = Tint->aux();
147 const typename IntType::OperType& oper = Tint->oper();
148
149 // WARNING assuming one function per position
150
151 // the Gaussian must be differentiated in direction dir
152 {
153 if (where == InBra && Tint->bra(part, 0).deriv().d(dir) == 0) return;
154 if (where == InKet && Tint->ket(part, 0).deriv().d(dir) == 0) return;
155 }
156
157 // if not using translational invariance ...
158 // can expand derivatives of primitive Gaussians only
159 if (not using_trans_inv) {
160 if (where == InBra && Tint->bra(part, 0).contracted()) return;
161 if (where == InKet && Tint->ket(part, 0).contracted()) return;
162 }
163
164 typedef typename IntType::BraType IBraType;
165 typedef typename IntType::KetType IKetType;
166 IBraType* bra = new IBraType(Tint->bra());
167 IKetType* ket = new IKetType(Tint->ket());
168
169 if (not using_trans_inv) { // differentiate
170
171 if (where == InBra) {
172 F a(bra->member(part, 0));
173
174 // add a+1
175 F ap1(bra->member(part, 0) + _1);
176 ap1.deriv().dec(dir);
177 bra->set_member(ap1, part, 0);
178 auto int_ap1 = this->add_child(IntType::Instance(*bra, *ket, aux, oper));
179 bra->set_member(a, part, 0);
180 if (is_simple()) {
181 std::ostringstream oss;
182 oss << "two_alpha" << part << "_bra";
183 expr_ = Scalar(oss.str()) * int_ap1;
184 nflops_ += 1;
185 }
186
187 // See if a-1 exists
188 F am1(bra->member(part, 0) - _1);
189 if (exists(am1)) {
190 am1.deriv().dec(dir);
191 bra->set_member(am1, part, 0);
192 auto int_am1 =
193 this->add_child(IntType::Instance(*bra, *ket, aux, oper));
194 bra->set_member(a, part, 0);
195 if (is_simple()) {
196 expr_ -= Scalar(a[dir]) * int_am1;
197 nflops_ += 2;
198 }
199 }
200 return;
201 }
202
203 if (where == InKet) {
204 F a(ket->member(part, 0));
205
206 // add a+1
207 F ap1(ket->member(part, 0) + _1);
208 ap1.deriv().dec(dir);
209 ket->set_member(ap1, part, 0);
210 auto int_ap1 = this->add_child(IntType::Instance(*bra, *ket, aux, oper));
211 ket->set_member(a, part, 0);
212 if (is_simple()) {
213 std::ostringstream oss;
214 oss << "two_alpha" << part << "_ket";
215 expr_ = Scalar(oss.str()) * int_ap1;
216 nflops_ += 1;
217 }
218
219 // See if a-1 exists
220 F am1(ket->member(part, 0) - _1);
221 if (exists(am1)) {
222 am1.deriv().dec(dir);
223 ket->set_member(am1, part, 0);
224 auto int_am1 =
225 this->add_child(IntType::Instance(*bra, *ket, aux, oper));
226 ket->set_member(a, part, 0);
227 if (is_simple()) {
228 expr_ -= Scalar(a[dir]) * int_am1;
229 nflops_ += 2;
230 }
231 }
232 return;
233 }
234 } else { // use translational invariance
235
236 // remove one deriv quantum from the target function
237 if (where == InBra) bra->member(part, 0).deriv().dec(dir);
238 if (where == InKet) ket->member(part, 0).deriv().dec(dir);
239
240 int term_count = 0;
241 for (int p = 0; p != IntType::num_particles; ++p) {
242 if (p != trans_inv_part || trans_inv_where != InBra) {
243 F a(bra->member(p, 0));
244 if (not a.is_unit()) {
245 F da(a);
246 da.deriv().inc(dir);
247 bra->set_member(da, p, 0);
248 auto int_da =
249 this->add_child(IntType::Instance(*bra, *ket, aux, oper));
250 bra->set_member(a, p, 0);
251 if (is_simple()) {
252 std::ostringstream oss;
253 if (term_count == 0)
254 expr_ = Scalar(-1) * int_da;
255 else
256 expr_ -= int_da;
257 ++term_count;
258 nflops_ += 1;
259 }
260 }
261 }
262 if (p != trans_inv_part || trans_inv_where != InKet) {
263 F a(ket->member(p, 0));
264 if (not a.is_unit()) {
265 F da(a);
266 da.deriv().inc(dir);
267 ket->set_member(da, p, 0);
268 auto int_da =
269 this->add_child(IntType::Instance(*bra, *ket, aux, oper));
270 ket->set_member(a, p, 0);
271 if (is_simple()) {
272 std::ostringstream oss;
273 if (term_count == 0)
274 expr_ = Scalar(-1) * int_da;
275 else
276 expr_ -= int_da;
277 ++term_count;
278 nflops_ += 1;
279 }
280 }
281 }
282 }
283 }
284
285 return;
286}
287
288#if LIBINT_ENABLE_GENERIC_CODE
289template <class IntType, int part, FunctionPosition where, int trans_inv_part,
290 FunctionPosition trans_inv_where>
292 has_generic(const std::shared_ptr<CompilationParameters>& cparams) const {
293 // not implemented generic relation for translational invariance yet
294 if (using_trans_inv) return false;
295
297
298 // generate generic code if the average quantum number > max_l_opt
299 const unsigned int max_opt_am = cparams->max_am_opt();
300 unsigned int am_total = 0;
301 unsigned int nfunctions = 0;
302 const unsigned int np = IntType::OperType::Properties::np;
303 for (unsigned int p = 0; p < np; p++) {
304 unsigned int nbra = target_->bra().num_members(p);
305 for (unsigned int i = 0; i < nbra; i++) {
306 am_total += target_->bra(p, i).norm();
307 ++nfunctions;
308 }
309 unsigned int nket = target_->ket().num_members(p);
310 for (unsigned int i = 0; i < nket; i++) {
311 am_total += target_->ket(p, i).norm();
312 ++nfunctions;
313 }
314 }
315 if (am_total > max_opt_am * nfunctions) return true;
316
317 // else generate explicit code
318 return false;
319}
320
321template <class IntType, int part, FunctionPosition where, int trans_inv_part,
322 FunctionPosition trans_inv_where>
323std::string CR_DerivGauss<IntType, part, where, trans_inv_part,
324 trans_inv_where>::generic_header() const {
325 return std::string("GenericGaussDeriv.h");
326}
327
328template <class IntType, int part, FunctionPosition where, int trans_inv_part,
329 FunctionPosition trans_inv_where>
330std::string
332 generic_instance(const std::shared_ptr<CodeContext>& context,
333 const std::shared_ptr<CodeSymbols>& args) const {
334 std::ostringstream oss;
335
336 oss << "using namespace libint2;" << std::endl;
337
338 BasisFunctionType sh(where == InBra ? target_->bra(part, 0)
339 : target_->ket(part, 0));
340
341 const unsigned int L = sh.norm();
342 const bool vectorize =
343 (context->cparams()->max_vector_length() == 1) ? false : true;
344 oss << "libint2::GenericGaussDeriv<" << L << ","
345 << (vectorize ? "true" : "false") << ">::compute(inteval";
346
347 oss << "," << args->symbol(0); // target
348 const unsigned int nargs = args->n();
349 for (unsigned int a = 1; a < nargs; a++) {
350 oss << "," << args->symbol(a);
351 }
352 // L == 0 => second argument not needed
353 if (nargs == 2) oss << ",0";
354
355 // then dimensions of basis function sets not involved in the transfer
356 unsigned int hsr = 1;
357 unsigned int lsr = 1;
358 const unsigned int np = IntType::OperType::Properties::np;
359 // a cleaner way to count the number of function sets referring
360 // to some particles is to construct a dummy integral and
361 // use subiterator policy
362 // WARNING !!!
363 for (int p = 0; p < static_cast<int>(np); p++) {
364 unsigned int nbra = target_->bra().num_members(p);
365 assert(nbra == 1);
366 for (unsigned int i = 0; i < nbra; i++) {
367 SubIterator* iter = target_->bra().member_subiter(p, i);
368 if (p < part || (p == part && where == InKet)) hsr *= iter->num_iter();
369 // skip p == part && where == InBra
370 if (p > part) lsr *= iter->num_iter();
371 delete iter;
372 }
373 unsigned int nket = target_->ket().num_members(p);
374 assert(nket == 1);
375 for (unsigned int i = 0; i < nket; i++) {
376 SubIterator* iter = target_->ket().member_subiter(p, i);
377 if (p < part) hsr *= iter->num_iter();
378 // skip p == part && where == InKet
379 if (p > part || (p == part && where == InBra)) lsr *= iter->num_iter();
380 delete iter;
381 }
382 }
383 oss << "," << hsr << "," << lsr;
384
385 // direction
386 oss << "," << this->dir();
387
388 // two_alpha prefactor
389 oss << ",inteval->two_alpha" << part << "_"
390 << (where == InBra ? "bra" : "ket");
391
392 oss << ");";
393
394 CR_DerivGauss_GenericInstantiator::instance().add(L, vectorize);
395
396 return oss.str();
397}
398#endif // #if !LIBINT_ENABLE_GENERIC_CODE
399
400}; // namespace libint2
401
402#endif
Definition comp_deriv_gauss.h:30
Compute relation for (geometric) derivative Gaussian ints of generic type IntType .
Definition comp_deriv_gauss.h:67
static bool directional()
always directional! Cartesian derivatives are applied in a particular direction
Definition comp_deriv_gauss.h:94
RRImpl must inherit GenericRecurrenceRelation<RRImpl>
Definition generic_rr.h:47
bool is_simple() const override
Implementation of RecurrenceRelation::is_simple()
Definition generic_rr.h:81
const std::shared_ptr< DGVertex > & add_child(const std::shared_ptr< DGVertex > &child)
add child
Definition generic_rr.h:109
static std::shared_ptr< RRImpl > Instance(const std::shared_ptr< TargetType > &Tint, unsigned int dir)
Return an instance if applicable, or a null pointer otherwise.
Definition generic_rr.h:55
Iterator provides a base class for all object iterator classes.
Definition iter.h:43
virtual unsigned int num_iter() const =0
Returns a number of iterations (number of elements in a set over which to iterate).
these objects help to construct BraketPairs
Definition src/bin/libint/braket.h:275
Defaults definitions for various parameters assumed by Libint.
Definition algebra.cc:24
bool exists(const IncableBFSet &A)
Return true if A is valid.
Definition bfset.h:96
DefaultQuantumNumbers< unsignedint, 1 >::Result mType
mType is the type that describes the auxiliary index of standard 2-body repulsion integrals
Definition quanta.h:395
std::string to_string(const T &x)
Converts x to its string representation.
Definition entity.h:121
TrivialBFSet<T> defines static member result, which is true if T is a basis function set consisting o...
Definition bfset.h:906