LIBINT 2.9.0
itr_11_twoprep_11.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_itr11twoprep11_h_
22#define _libint2_src_bin_libint_itr11twoprep11_h_
23
24#include <algebra.h>
25#include <context.h>
26#include <default_params.h>
27#include <dgvertex.h>
28#include <flop.h>
29#include <prefactors.h>
30#include <rr.h>
31#include <twoprep_11_11.h>
32#include <util.h>
33
34#include <cassert>
35#include <iostream>
36#include <sstream>
37#include <stdexcept>
38#include <string>
39#include <vector>
40
41namespace libint2 {
42
48template <template <typename, typename, typename> class ERI, class BFSet,
49 int part, FunctionPosition where>
51 public:
55 typedef ERI<BFSet, TwoPRep, mType> TargetType;
56 typedef TargetType ChildType;
59
68 static std::shared_ptr<ThisType> Instance(const std::shared_ptr<TargetType>&,
69 unsigned int dir = 0);
70 virtual ~ITR_11_TwoPRep_11() { assert(part == 0 || part == 1); }
71
73 int partindex_direction() const {
74 return part == 0 ? +1 // transfer from 0 to 1
75 : -1; // transfer from 1 to 0
76 }
77
79
82 static bool directional() {
83 if (boost::is_same<BasisFunctionType, CGShell>::value) return false;
84 return true;
85 }
86
87#if 1
89 unsigned int num_children() const override { return children_.size(); }
91 std::shared_ptr<DGVertex> rr_target() const override {
92 return std::static_pointer_cast<DGVertex, TargetType>(target_);
93 }
95 std::shared_ptr<DGVertex> rr_child(unsigned int i) const override {
96 return std::static_pointer_cast<DGVertex, ChildType>(children_.at(i));
97 }
99 bool is_simple() const override { return TrivialBFSet<BFSet>::result; }
100#endif
101
102 private:
108 ITR_11_TwoPRep_11(const std::shared_ptr<TargetType>&, unsigned int dir);
109
110 static const unsigned int max_nchildren_ = 4;
111 unsigned int dir_;
112 std::shared_ptr<TargetType> target_;
113 std::vector<std::shared_ptr<ChildType> > children_;
114 const std::shared_ptr<ChildType>& make_child(const BFSet& A, const BFSet& B,
115 const BFSet& C, const BFSet& D,
116 unsigned int m) {
117 const std::shared_ptr<ChildType>& i = ChildType::Instance(A, B, C, D, m);
118 children_.push_back(i);
119 return *(children_.end() - 1);
120 }
121
122 std::string generate_label() const override {
123 typedef typename TargetType::AuxIndexType mType;
124 static std::shared_ptr<mType> aux0(new mType(0u));
125 std::ostringstream os;
126 // ITR recurrence relation code is independent of m (it never appears
127 // anywhere in equations), hence to avoid generating identical code make
128 // sure that the (unique) label does not contain m
129 os << "ITR Part" << part << " " << to_string(where)
130 << genintegralset_label(target_->bra(), target_->ket(), aux0,
131 target_->oper());
132 return os.str();
133 }
134
135#if LIBINT_ENABLE_GENERIC_CODE
137 bool has_generic(
138 const std::shared_ptr<CompilationParameters>& cparams) const override;
140 std::string generic_header() const override;
142 std::string generic_instance(
143 const std::shared_ptr<CodeContext>& context,
144 const std::shared_ptr<CodeSymbols>& args) const override;
145#endif
146};
147
148template <template <typename, typename, typename> class ERI, class F, int part,
149 FunctionPosition where>
150std::shared_ptr<ITR_11_TwoPRep_11<ERI, F, part, where> >
152 const std::shared_ptr<TargetType>& Tint, unsigned int dir) {
153 std::shared_ptr<ThisType> this_ptr(new ThisType(Tint, dir));
154 // Do post-construction duties
155 if (this_ptr->num_children() != 0) {
156 this_ptr->template register_with_rrstack<ThisType>();
157 return this_ptr;
158 }
159 return std::shared_ptr<ThisType>();
160}
161
162template <template <typename, typename, typename> class ERI, class F, int part,
163 FunctionPosition where>
165 const std::shared_ptr<TargetType>& Tint, unsigned int dir)
166 : target_(Tint), dir_(dir) {
167 // only works for primitive integrals
168 {
169 F a(Tint->bra(0, 0));
170 F b(Tint->ket(0, 0));
171 F c(Tint->bra(1, 0));
172 F d(Tint->ket(1, 0));
173 if (a.contracted() || b.contracted() || c.contracted() || d.contracted())
174 return;
175 }
176
177 // not yet implemented for derivative integrals
178 {
179 const OriginDerivative<3u> dA = Tint->bra(0, 0).deriv();
180 const OriginDerivative<3u> dB = Tint->ket(0, 0).deriv();
181 const OriginDerivative<3u> dC = Tint->bra(1, 0).deriv();
182 const OriginDerivative<3u> dD = Tint->ket(1, 0).deriv();
183 const bool deriv = !dA.zero() || !dB.zero() || !dC.zero() || !dD.zero();
184 if (deriv) return;
185 }
186
187 children_.reserve(max_nchildren_);
188 using namespace libint2::algebra;
189 using namespace libint2::prefactor;
190 const unsigned int m = Tint->aux()->elem(0);
191 const F& _1 = unit<F>(dir);
192
193 // Build on A
194 if (part == 0 && where == InBra) {
195 F a(Tint->bra(0, 0) - _1);
196 if (!exists(a)) return;
197 F b(Tint->ket(0, 0));
198 F c(Tint->bra(1, 0));
199 F d(Tint->ket(1, 0));
200
201 // must be (A0|C0)
202 if (not(b.zero() && d.zero())) return;
203
204 const std::shared_ptr<ChildType>& ABCD_m = make_child(a, b, c, d, m);
205 if (is_simple()) {
206 expr_ = Vector("TwoPRepITR_pfac0_0_0")[dir] * ABCD_m;
207 nflops_ += 1;
208 }
209
210 const F& cp1 = c + _1;
211 const std::shared_ptr<ChildType>& ABCp1D_m = make_child(a, b, cp1, d, m);
212 if (is_simple()) {
213 expr_ -= Scalar("eoz") * ABCp1D_m;
214 nflops_ += 2;
215 }
216
217 const F& am1 = a - _1;
218 if (exists(am1)) {
219 const std::shared_ptr<ChildType>& Am1BCD_m = make_child(am1, b, c, d, m);
220 if (is_simple()) {
221 expr_ += Scalar(a[dir]) * Scalar("oo2z") * Am1BCD_m;
222 nflops_ += 3;
223 }
224 }
225 const F& cm1 = c - _1;
226 if (exists(cm1)) {
227 const std::shared_ptr<ChildType>& ABCm1D_m = make_child(a, b, cm1, d, m);
228 if (is_simple()) {
229 expr_ += Scalar(c[dir]) * Scalar("oo2z") * ABCm1D_m;
230 nflops_ += 3;
231 }
232 }
233 return;
234 }
235 // Build on C
236 if (part == 1 && where == InBra) {
237 F a(Tint->bra(0, 0));
238 F b(Tint->ket(0, 0));
239 F c(Tint->bra(1, 0) - _1);
240 if (!exists(c)) return;
241 F d(Tint->ket(1, 0));
242
243 // must be (A0|C0)
244 if (not(b.zero() && d.zero())) return;
245
246 const std::shared_ptr<ChildType>& ABCD_m = make_child(a, b, c, d, m);
247 if (is_simple()) {
248 expr_ = Vector("TwoPRepITR_pfac0_1_0")[dir] * ABCD_m;
249 nflops_ += 1;
250 }
251
252 const F& ap1 = a + _1;
253 const std::shared_ptr<ChildType>& Ap1BCD_m = make_child(ap1, b, c, d, m);
254 if (is_simple()) {
255 expr_ -= Scalar("zoe") * Ap1BCD_m;
256 nflops_ += 2;
257 }
258
259 const F& cm1 = c - _1;
260 if (exists(cm1)) {
261 const std::shared_ptr<ChildType>& ABCm1D_m = make_child(a, b, cm1, d, m);
262 if (is_simple()) {
263 expr_ += Scalar(c[dir]) * Scalar("oo2e") * ABCm1D_m;
264 nflops_ += 3;
265 }
266 }
267 const F& am1 = a - _1;
268 if (exists(am1)) {
269 const std::shared_ptr<ChildType>& Am1BCD_m = make_child(am1, b, c, d, m);
270 if (is_simple()) {
271 expr_ += Scalar(a[dir]) * Scalar("oo2e") * Am1BCD_m;
272 nflops_ += 3;
273 }
274 }
275 return;
276 }
277 // Build on B
278 if (part == 0 && where == InKet) {
279 F a(Tint->bra(0, 0));
280 F b(Tint->ket(0, 0) - _1);
281 if (!exists(b)) return;
282 F c(Tint->bra(1, 0));
283 F d(Tint->ket(1, 0));
284
285 // must be (0B|0D)
286 if (not(a.zero() && c.zero())) return;
287
288 const std::shared_ptr<ChildType>& ABCD_m = make_child(a, b, c, d, m);
289 if (is_simple()) {
290 expr_ = Vector("TwoPRepITR_pfac0_0_1")[dir] * ABCD_m;
291 nflops_ += 1;
292 }
293
294 const F& dp1 = d + _1;
295 const std::shared_ptr<ChildType>& ABCDp1_m = make_child(a, b, c, dp1, m);
296 if (is_simple()) {
297 expr_ -= Scalar("eoz") * ABCDp1_m;
298 nflops_ += 2;
299 }
300
301 const F& bm1 = b - _1;
302 if (exists(bm1)) {
303 const std::shared_ptr<ChildType>& ABm1CD_m = make_child(a, bm1, c, d, m);
304 if (is_simple()) {
305 expr_ += Scalar(b[dir]) * Scalar("oo2z") * ABm1CD_m;
306 nflops_ += 3;
307 }
308 }
309 const F& dm1 = d - _1;
310 if (exists(dm1)) {
311 const std::shared_ptr<ChildType>& ABCDm1_m = make_child(a, b, c, dm1, m);
312 if (is_simple()) {
313 expr_ += Scalar(d[dir]) * Scalar("oo2z") * ABCDm1_m;
314 nflops_ += 3;
315 }
316 }
317 return;
318 }
319 // Build on D
320 if (part == 1 && where == InKet) {
321 F a(Tint->bra(0, 0));
322 F b(Tint->ket(0, 0));
323 F c(Tint->bra(1, 0));
324 F d(Tint->ket(1, 0) - _1);
325 if (!exists(d)) return;
326
327 // must be (0B|0D)
328 if (not(a.zero() && c.zero())) return;
329
330 const std::shared_ptr<ChildType>& ABCD_m = make_child(a, b, c, d, m);
331 if (is_simple()) {
332 expr_ = Vector("TwoPRepITR_pfac0_1_1")[dir] * ABCD_m;
333 nflops_ += 1;
334 }
335
336 const F& bp1 = b + _1;
337 const std::shared_ptr<ChildType>& ABp1CD_m = make_child(a, bp1, c, d, m);
338 if (is_simple()) {
339 expr_ -= Scalar("zoe") * ABp1CD_m;
340 nflops_ += 2;
341 }
342
343 const F& dm1 = d - _1;
344 if (exists(dm1)) {
345 const std::shared_ptr<ChildType>& ABCDm1_m = make_child(a, b, c, dm1, m);
346 if (is_simple()) {
347 expr_ += Scalar(d[dir]) * Scalar("oo2e") * ABCDm1_m;
348 nflops_ += 3;
349 }
350 }
351 const F& bm1 = b - _1;
352 if (exists(bm1)) {
353 const std::shared_ptr<ChildType>& ABm1CD_m = make_child(a, bm1, c, d, m);
354 if (is_simple()) {
355 expr_ += Scalar(b[dir]) * Scalar("oo2e") * ABm1CD_m;
356 nflops_ += 3;
357 }
358 }
359 return;
360 }
361}
362
363#if LIBINT_ENABLE_GENERIC_CODE
364template <template <typename, typename, typename> class ERI, class F, int part,
365 FunctionPosition where>
367 const std::shared_ptr<CompilationParameters>& cparams) const {
368 if (TrivialBFSet<F>::result) return false;
369
370 F sh_a(target_->bra(0, 0));
371 F sh_b(target_->ket(0, 0));
372 F sh_c(target_->bra(1, 0));
373 F sh_d(target_->ket(1, 0));
374 const unsigned int max_opt_am = cparams->max_am_opt();
375 // generic code works for a0c0 of 0a0c classes where am(a) > 1 and am(c) > 1
376 // to generate optimized code for xxxx integral need to generate specialized
377 // code for up to (x+x)0(x+x)0 integrals
378 if (sh_b.zero() && sh_d.zero() &&
379 (sh_a.norm() > std::max(2 * max_opt_am, 1u) ||
380 sh_c.norm() > std::max(2 * max_opt_am, 1u)) &&
381 (sh_a.norm() > 1u && sh_c.norm() > 1u)) {
382 const bool ITR_xs_xs_Part1_implemented =
383 false; // only Part0 is implemented
384 if (part == 1)
385 return ITR_xs_xs_Part1_implemented;
386 else
387 return true;
388 }
389 if (sh_a.zero() && sh_c.zero() &&
390 (sh_b.norm() > std::max(2 * max_opt_am, 1u) ||
391 sh_d.norm() > std::max(2 * max_opt_am, 1u)) &&
392 (sh_b.norm() > 1u && sh_d.norm() > 1u)) {
393 const bool ITR_sx_sx_implemented = false; // only ITR_xs_xs is implemented
394 return ITR_sx_sx_implemented;
395 }
396 return false;
397}
398
399template <template <typename, typename, typename> class ERI, class F, int part,
400 FunctionPosition where>
402 F sh_a(target_->bra(0, 0));
403 F sh_b(target_->ket(0, 0));
404 F sh_c(target_->bra(1, 0));
405 F sh_d(target_->ket(1, 0));
406 const bool xsxs = sh_b.zero() && sh_d.zero();
407 const bool sxsx = sh_a.zero() && sh_c.zero();
408
409 const OriginDerivative<3u> dA = target_->bra(0, 0).deriv();
410 const OriginDerivative<3u> dB = target_->ket(0, 0).deriv();
411 const OriginDerivative<3u> dC = target_->bra(1, 0).deriv();
412 const OriginDerivative<3u> dD = target_->ket(1, 0).deriv();
413 const bool deriv = !dA.zero() || !dB.zero() || !dC.zero() || !dD.zero();
414 assert(!deriv);
415
416 if (!deriv) {
417 return std::string("ITR_xs_xs.h");
418 } else {
419 if (xsxs) return std::string("ITR_xs_xs_deriv.h");
420 if (sxsx) return std::string("ITR_sx_sx_deriv.h");
421 }
422 abort(); // unreachable
423}
424
425template <template <typename, typename, typename> class ERI, class F, int part,
426 FunctionPosition where>
428 const std::shared_ptr<CodeContext>& context,
429 const std::shared_ptr<CodeSymbols>& args) const {
430 std::ostringstream oss;
431 F sh_a(target_->bra(0, 0));
432 F sh_b(target_->ket(0, 0));
433 F sh_c(target_->bra(1, 0));
434 F sh_d(target_->ket(1, 0));
435 const bool xsxs = sh_b.zero() && sh_d.zero();
436 const bool sxsx = sh_a.zero() && sh_c.zero();
437
438 const OriginDerivative<3u> dA = target_->bra(0, 0).deriv();
439 const OriginDerivative<3u> dB = target_->ket(0, 0).deriv();
440 const OriginDerivative<3u> dC = target_->bra(1, 0).deriv();
441 const OriginDerivative<3u> dD = target_->ket(1, 0).deriv();
442 const bool deriv = !dA.zero() || !dB.zero() || !dC.zero() || !dD.zero();
443 assert(!deriv);
444
445 oss << "using namespace libint2;" << std::endl;
446
447 if (!deriv) { // for regular integrals I know exactly how many prerequisites
448 // I need
449 if (xsxs) {
450 oss << "libint2::ITR_xs_xs<" << part << "," << sh_a.norm() << ","
451 << sh_c.norm() << ",true,";
452 }
453 if (sxsx) {
454 oss << "libint2::ITR_xs_xs<" << part << "," << sh_b.norm() << ","
455 << sh_d.norm() << ",false,";
456 }
457 oss << ((context->cparams()->max_vector_length() == 1) ? "false" : "true");
458 oss << ">::compute(inteval";
459
460 const unsigned int nargs = args->n();
461 for (unsigned int a = 0; a < nargs; a++) {
462 oss << "," << args->symbol(a);
463 }
464 oss << ");";
465 }
466
467 return oss.str();
468}
469#endif // #if !LIBINT_ENABLE_GENERIC_CODE
470
471}; // namespace libint2
472
473#endif
AlgebraicOperator is an algebraic operator that acts on objects of type T.
Definition algebra.h:47
Set of basis functions.
Definition bfset.h:43
ITR (Interelectron Transfer Relation) for 2-e ERI.
Definition itr_11_twoprep_11.h:50
std::shared_ptr< DGVertex > rr_target() const override
Implementation of RecurrenceRelation::rr_target()
Definition itr_11_twoprep_11.h:91
bool is_simple() const override
Implementation of RecurrenceRelation::is_simple()
Definition itr_11_twoprep_11.h:99
unsigned int num_children() const override
Implementation of RecurrenceRelation::num_children()
Definition itr_11_twoprep_11.h:89
int partindex_direction() const
overrides RecurrenceRelation::partindex_direction()
Definition itr_11_twoprep_11.h:73
static std::shared_ptr< ThisType > Instance(const std::shared_ptr< TargetType > &, unsigned int dir=0)
Use Instance() to obtain an instance of RR.
Definition itr_11_twoprep_11.h:151
static bool directional()
Default directionality.
Definition itr_11_twoprep_11.h:82
RecurrenceRelation::ExprType ExprType
The type of expressions in which RecurrenceRelations result.
Definition itr_11_twoprep_11.h:58
std::shared_ptr< DGVertex > rr_child(unsigned int i) const override
Implementation of RecurrenceRelation::rr_child()
Definition itr_11_twoprep_11.h:95
Represents cartesian derivatives of atom-centered basis functions.
Definition bfset.h:101
bool zero() const
norm() == 0
Definition bfset.h:158
RecurrenceRelation describes all recurrence relations.
Definition rr.h:97
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