LIBINT 2.9.0
vrr_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_vrr11twoprep11_h_
22#define _libint2_src_bin_libint_vrr11twoprep11_h_
23
24#include <generic_rr.h>
25#include <twoprep_11_11.h>
26
27namespace libint2 {
28
33template <class BFSet, int part, FunctionPosition where>
35 VRR_11_TwoPRep_11<BFSet, part, where>, BFSet,
36 GenIntegralSet_11_11<BFSet, TwoPRep, mType> > {
37 public:
43 static const unsigned int max_nchildren = 26;
44
46
48 static bool directional() { return ParentType::default_directional(); }
49
50 private:
52 using ParentType::target_;
53 using ParentType::RecurrenceRelation::expr_;
54 using ParentType::RecurrenceRelation::nflops_;
55
58 VRR_11_TwoPRep_11(const std::shared_ptr<TargetType>&, unsigned int dir);
59
60 static std::string descr() { return "OSVRR"; }
65 std::string generate_label() const override {
66 typedef typename TargetType::AuxIndexType mType;
67 static std::shared_ptr<mType> aux0(new mType(0u));
68 std::ostringstream os;
69 os << descr() << "P" << part << to_string(where)
70 << genintegralset_label(target_->bra(), target_->ket(), aux0,
71 target_->oper());
72 return os.str();
73 }
74
75#if LIBINT_ENABLE_GENERIC_CODE
77 bool has_generic(
78 const std::shared_ptr<CompilationParameters>& cparams) const override;
80 std::string generic_header() const override;
82 std::string generic_instance(
83 const std::shared_ptr<CodeContext>& context,
84 const std::shared_ptr<CodeSymbols>& args) const override;
85#endif
86};
87
88template <class F, int part, FunctionPosition where>
89VRR_11_TwoPRep_11<F, part, where>::VRR_11_TwoPRep_11(
90 const std::shared_ptr<TargetType>& Tint, unsigned int dir)
91 : ParentType(Tint, dir) {
92 using namespace libint2::algebra;
93 using namespace libint2::prefactor;
94 using namespace libint2::braket;
95 const unsigned int m = Tint->aux()->elem(0);
96 const F& _1 = unit<F>(dir);
97
98 { // can't apply to contracted basis functions
99 F a(Tint->bra(0, 0));
100 F b(Tint->ket(0, 0));
101 F c(Tint->bra(1, 0));
102 F d(Tint->ket(1, 0));
103 if (a.contracted() || b.contracted() || c.contracted() || d.contracted())
104 return;
105 }
106
107 // if derivative integrals, there will be extra terms (Eq. (143) in Obara &
108 // Saika JCP 89)
109 const OriginDerivative<3u> dA = Tint->bra(0, 0).deriv();
110 const OriginDerivative<3u> dB = Tint->ket(0, 0).deriv();
111 const OriginDerivative<3u> dC = Tint->bra(1, 0).deriv();
112 const OriginDerivative<3u> dD = Tint->ket(1, 0).deriv();
113 const bool deriv = !dA.zero() || !dB.zero() || !dC.zero() || !dD.zero();
114
115 // This is a hack to avoid creating recurrence relations for which generic
116 // code has not been yet implemented
117#if LIBINT_ENABLE_GENERIC_CODE
118 {
119 F sh_a(target_->bra(0, 0));
120 F sh_b(target_->ket(0, 0));
121 F sh_c(target_->bra(1, 0));
122 F sh_d(target_->ket(1, 0));
123 // generic code works for a0c0 of 0a0c classes where am(a) > 1 and am(c) > 1
124 // to generate optimized code for xxxx integral need to generate specialized
125 // code for up to (x+x)0(x+x)0 integrals
126 if (sh_b.zero() && sh_d.zero() &&
127 (sh_a.norm() > 1u &&
128 sh_c.norm() > 1u)) { // have a generic implemented ...
129 if (part != 0) // ... but only implemented build on A in this case
130 return;
131 }
132 if (sh_a.zero() && sh_c.zero() && (sh_b.norm() > 1u && sh_d.norm() > 1u)) {
133 if (part != 0) // but only implemented build on B in this case
134 return;
135 }
136 }
137#endif
138
139 typedef TargetType ChildType;
141
142 bool part0_has_unit = false, part1_has_unit = false;
143
144 // Build on A
145 if (part == 0 && where == InBra) {
146 F a(Tint->bra(0, 0) - _1);
147 if (!exists(a)) return;
148 F b(Tint->ket(0, 0));
149 const bool unit_b = (b == F::unit());
150 part0_has_unit |= unit_b;
151 F c(Tint->bra(1, 0));
152 F d(Tint->ket(1, 0));
153
154 std::shared_ptr<DGVertex> ABCD_m;
155 if (not unit_b) ABCD_m = factory.make_child(a, b, c, d, m);
156 auto ABCD_mp1 = factory.make_child(a, b, c, d, m + 1);
157 if (is_simple()) {
158 if (not unit_b) {
159 expr_ = Vector("PA")[dir] * ABCD_m + Vector("WP")[dir] * ABCD_mp1;
160 nflops_ += 3;
161 } else {
162 expr_ = Vector("WP")[dir] * ABCD_mp1;
163 nflops_ += 1;
164 }
165 }
166
167 // simplified 3-center VRR due to Ahlrichs (PCCP 6, 5119 (2004))
168 const bool ahlrichs_simplification = a.pure_sh() && unit_b;
169 auto am1 = a - _1;
170 if (exists(am1) && not ahlrichs_simplification) {
171 auto Am1BCD_m = factory.make_child(am1, b, c, d, m);
172 auto Am1BCD_mp1 = factory.make_child(am1, b, c, d, m + 1);
173#if LIBINT_GENERATE_FMA
174 // this form is amenable to generation of fmsub
175 if (is_simple()) {
176 expr_ -= Scalar(a[dir]) * Scalar("oo2z") *
177 (Scalar("roz") * Am1BCD_mp1 - Am1BCD_m);
178 nflops_ += 5;
179 }
180#else
181 if (is_simple()) {
182 expr_ += Scalar(a[dir]) * Scalar("oo2z") *
183 (Am1BCD_m - Scalar("roz") * Am1BCD_mp1);
184 nflops_ += 5;
185 }
186#endif
187 }
188 const F& bm1 = b - _1;
189 if (exists(bm1)) {
190 auto ABm1CD_m = factory.make_child(a, bm1, c, d, m);
191 auto ABm1CD_mp1 = factory.make_child(a, bm1, c, d, m + 1);
192#if LIBINT_GENERATE_FMA
193 // this form is amenable to generation of fmsub
194 if (is_simple()) {
195 expr_ -= Scalar(b[dir]) * Scalar("oo2z") *
196 (Scalar("roz") * ABm1CD_mp1 - ABm1CD_m);
197 nflops_ += 5;
198 }
199#else
200 if (is_simple()) {
201 expr_ += Scalar(b[dir]) * Scalar("oo2z") *
202 (ABm1CD_m - Scalar("roz") * ABm1CD_mp1);
203 nflops_ += 5;
204 }
205#endif
206 }
207 const F& cm1 = c - _1;
208 if (exists(cm1)) {
209 auto ABCm1D_mp1 = factory.make_child(a, b, cm1, d, m + 1);
210 if (is_simple()) {
211 expr_ += Scalar(c[dir]) * Scalar("oo2ze") * ABCm1D_mp1;
212 nflops_ += 3;
213 }
214 }
215 const F& dm1 = d - _1;
216 if (exists(dm1)) {
217 auto ABCDm1_mp1 = factory.make_child(a, b, c, dm1, m + 1);
218 if (is_simple()) {
219 expr_ += Scalar(d[dir]) * Scalar("oo2ze") * ABCDm1_mp1;
220 nflops_ += 3;
221 }
222 }
223 }
224 // Build on B
225 if (part == 0 && where == InKet) {
226 F a(Tint->bra(0, 0));
227 const bool unit_a = (a == F::unit());
228 part0_has_unit |= unit_a;
229 F b(Tint->ket(0, 0) - _1);
230 if (!exists(b)) return;
231 F c(Tint->bra(1, 0));
232 F d(Tint->ket(1, 0));
233
234 std::shared_ptr<DGVertex> ABCD_m;
235 if (not unit_a) ABCD_m = factory.make_child(a, b, c, d, m);
236 auto ABCD_mp1 = factory.make_child(a, b, c, d, m + 1);
237 if (is_simple()) {
238 if (not unit_a) {
239 expr_ = Vector("PB")[dir] * ABCD_m + Vector("WP")[dir] * ABCD_mp1;
240 nflops_ += 3;
241 } else {
242 expr_ = Vector("WP")[dir] * ABCD_mp1;
243 nflops_ += 1;
244 }
245 }
246
247 const F& am1 = a - _1;
248 if (exists(am1)) {
249 auto Am1BCD_m = factory.make_child(am1, b, c, d, m);
250 auto Am1BCD_mp1 = factory.make_child(am1, b, c, d, m + 1);
251#if LIBINT_GENERATE_FMA
252 // this form is amenable to generation of fmsub
253 if (is_simple()) {
254 expr_ -= Scalar(a[dir]) * Scalar("oo2z") *
255 (Scalar("roz") * Am1BCD_mp1 - Am1BCD_m);
256 nflops_ += 5;
257 }
258#else
259 if (is_simple()) {
260 expr_ += Scalar(a[dir]) * Scalar("oo2z") *
261 (Am1BCD_m - Scalar("roz") * Am1BCD_mp1);
262 nflops_ += 5;
263 }
264#endif
265 }
266 // simplified 3-center VRR due to Ahlrichs (PCCP 6, 5119 (2004))
267 const bool ahlrichs_simplification = b.pure_sh() && unit_a;
268 const F& bm1 = b - _1;
269 if (exists(bm1) && not ahlrichs_simplification) {
270 auto ABm1CD_m = factory.make_child(a, bm1, c, d, m);
271 auto ABm1CD_mp1 = factory.make_child(a, bm1, c, d, m + 1);
272#if LIBINT_GENERATE_FMA
273 // this form is amenable to generation of fmsub
274 if (is_simple()) {
275 expr_ -= Scalar(b[dir]) * Scalar("oo2z") *
276 (Scalar("roz") * ABm1CD_mp1 - ABm1CD_m);
277 nflops_ += 5;
278 }
279#else
280 if (is_simple()) {
281 expr_ += Scalar(b[dir]) * Scalar("oo2z") *
282 (ABm1CD_m - Scalar("roz") * ABm1CD_mp1);
283 nflops_ += 5;
284 }
285#endif
286 }
287 const F& cm1 = c - _1;
288 if (exists(cm1)) {
289 auto ABCm1D_mp1 = factory.make_child(a, b, cm1, d, m + 1);
290 if (is_simple()) {
291 expr_ += Scalar(c[dir]) * Scalar("oo2ze") * ABCm1D_mp1;
292 nflops_ += 3;
293 }
294 }
295 const F& dm1 = d - _1;
296 if (exists(dm1)) {
297 auto ABCDm1_mp1 = factory.make_child(a, b, c, dm1, m + 1);
298 if (is_simple()) {
299 expr_ += Scalar(d[dir]) * Scalar("oo2ze") * ABCDm1_mp1;
300 nflops_ += 3;
301 }
302 }
303 }
304 // Build on C
305 if (part == 1 && where == InBra) {
306 F a(Tint->bra(0, 0));
307 F b(Tint->ket(0, 0));
308 F c(Tint->bra(1, 0) - _1);
309 if (!exists(c)) return;
310 F d(Tint->ket(1, 0));
311 const bool unit_d = (d == F::unit());
312 part1_has_unit |= unit_d;
313
314 std::shared_ptr<DGVertex> ABCD_m;
315 if (not unit_d) ABCD_m = factory.make_child(a, b, c, d, m);
316 auto ABCD_mp1 = factory.make_child(a, b, c, d, m + 1);
317 if (is_simple()) {
318 if (not unit_d) {
319 expr_ = Vector("QC")[dir] * ABCD_m + Vector("WQ")[dir] * ABCD_mp1;
320 nflops_ += 3;
321 } else {
322 expr_ = Vector("WQ")[dir] * ABCD_mp1;
323 nflops_ += 1;
324 }
325 }
326
327 // simplified 3-center VRR due to Ahlrichs (PCCP 6, 5119 (2004))
328 const bool ahlrichs_simplification = c.pure_sh() && unit_d;
329 const F& cm1 = c - _1;
330 if (exists(cm1) && not ahlrichs_simplification) {
331 auto ABCm1D_m = factory.make_child(a, b, cm1, d, m);
332 auto ABCm1D_mp1 = factory.make_child(a, b, cm1, d, m + 1);
333#if LIBINT_GENERATE_FMA
334 // this form is amenable to generation of fmsub
335 if (is_simple()) {
336 expr_ -= Scalar(c[dir]) * Scalar("oo2e") *
337 (Scalar("roe") * ABCm1D_mp1 - ABCm1D_m);
338 nflops_ += 5;
339 }
340#else
341 if (is_simple()) {
342 expr_ += Scalar(c[dir]) * Scalar("oo2e") *
343 (ABCm1D_m - Scalar("roe") * ABCm1D_mp1);
344 nflops_ += 5;
345 }
346#endif
347 }
348 const F& dm1 = d - _1;
349 if (exists(dm1)) {
350 auto ABCDm1_m = factory.make_child(a, b, c, dm1, m);
351 auto ABCDm1_mp1 = factory.make_child(a, b, c, dm1, m + 1);
352#if LIBINT_GENERATE_FMA
353 // this form is amenable to generation of fmsub
354 if (is_simple()) {
355 expr_ -= Scalar(d[dir]) * Scalar("oo2e") *
356 (Scalar("roe") * ABCDm1_mp1 - ABCDm1_m);
357 nflops_ += 5;
358 }
359#else
360 if (is_simple()) {
361 expr_ += Scalar(d[dir]) * Scalar("oo2e") *
362 (ABCDm1_m - Scalar("roe") * ABCDm1_mp1);
363 nflops_ += 5;
364 }
365#endif
366 }
367 const F& am1 = a - _1;
368 if (exists(am1)) {
369 auto Am1BCD_mp1 = factory.make_child(am1, b, c, d, m + 1);
370 if (is_simple()) {
371 expr_ += Scalar(a[dir]) * Scalar("oo2ze") * Am1BCD_mp1;
372 nflops_ += 3;
373 }
374 }
375 const F& bm1 = b - _1;
376 if (exists(bm1)) {
377 auto ABm1CD_mp1 = factory.make_child(a, bm1, c, d, m + 1);
378 if (is_simple()) {
379 expr_ += Scalar(b[dir]) * Scalar("oo2ze") * ABm1CD_mp1;
380 nflops_ += 3;
381 }
382 }
383 }
384 // Build on D
385 if (part == 1 && where == InKet) {
386 F a(Tint->bra(0, 0));
387 F b(Tint->ket(0, 0));
388 F c(Tint->bra(1, 0));
389 const bool unit_c = (c == F::unit());
390 part1_has_unit |= unit_c;
391 F d(Tint->ket(1, 0) - _1);
392 if (!exists(d)) return;
393
394 std::shared_ptr<DGVertex> ABCD_m;
395 if (not unit_c) ABCD_m = factory.make_child(a, b, c, d, m);
396 auto ABCD_mp1 = factory.make_child(a, b, c, d, m + 1);
397 if (is_simple()) {
398 if (not unit_c) {
399 expr_ = Vector("QD")[dir] * ABCD_m + Vector("WQ")[dir] * ABCD_mp1;
400 nflops_ += 3;
401 } else {
402 expr_ = Vector("WQ")[dir] * ABCD_mp1;
403 nflops_ += 1;
404 }
405 }
406
407 const F& cm1 = c - _1;
408 if (exists(cm1)) {
409 auto ABCm1D_m = factory.make_child(a, b, cm1, d, m);
410 auto ABCm1D_mp1 = factory.make_child(a, b, cm1, d, m + 1);
411#if LIBINT_GENERATE_FMA
412 // this form is amenable to generation of fmsub
413 if (is_simple()) {
414 expr_ -= Scalar(c[dir]) * Scalar("oo2e") *
415 (Scalar("roe") * ABCm1D_mp1 - ABCm1D_m);
416 nflops_ += 5;
417 }
418#else
419 if (is_simple()) {
420 expr_ += Scalar(c[dir]) * Scalar("oo2e") *
421 (ABCm1D_m - Scalar("roe") * ABCm1D_mp1);
422 nflops_ += 5;
423 }
424#endif
425 }
426 // simplified 3-center VRR due to Ahlrichs (PCCP 6, 5119 (2004))
427 const bool ahlrichs_simplification = d.pure_sh() && unit_c;
428 const F& dm1 = d - _1;
429 if (exists(dm1) && not ahlrichs_simplification) {
430 auto ABCDm1_m = factory.make_child(a, b, c, dm1, m);
431 auto ABCDm1_mp1 = factory.make_child(a, b, c, dm1, m + 1);
432#if LIBINT_GENERATE_FMA
433 // this form is amenable to generation of fmsub
434 if (is_simple()) {
435 expr_ -= Scalar(d[dir]) * Scalar("oo2e") *
436 (Scalar("roe") * ABCDm1_mp1 - ABCDm1_m);
437 nflops_ += 5;
438 }
439#else
440 if (is_simple()) {
441 expr_ += Scalar(d[dir]) * Scalar("oo2e") *
442 (ABCDm1_m - Scalar("roe") * ABCDm1_mp1);
443 nflops_ += 5;
444 }
445#endif
446 }
447 const F& am1 = a - _1;
448 if (exists(am1)) {
449 auto Am1BCD_mp1 = factory.make_child(am1, b, c, d, m + 1);
450 if (is_simple()) {
451 expr_ += Scalar(a[dir]) * Scalar("oo2ze") * Am1BCD_mp1;
452 nflops_ += 3;
453 }
454 }
455 const F& bm1 = b - _1;
456 if (exists(bm1)) {
457 auto ABm1CD_mp1 = factory.make_child(a, bm1, c, d, m + 1);
458 if (is_simple()) {
459 expr_ += Scalar(b[dir]) * Scalar("oo2ze") * ABm1CD_mp1;
460 nflops_ += 3;
461 }
462 }
463 }
464
465 // if got here, can decrement by at least 1 quantum
466 // add additional derivative terms
467 if (deriv) {
468 // bf quantum on the build center subtracted by 1
469 F a(part == 0 && where == InBra ? Tint->bra(0, 0) - _1 : Tint->bra(0, 0));
470 F b(part == 0 && where == InKet ? Tint->ket(0, 0) - _1 : Tint->ket(0, 0));
471 F c(part == 1 && where == InBra ? Tint->bra(1, 0) - _1 : Tint->bra(1, 0));
472 F d(part == 1 && where == InKet ? Tint->ket(1, 0) - _1 : Tint->ket(1, 0));
473
474 // treatment of derivative terms differs for shell sets and integrals
475 // since in computing shell sets transfer/build will occur in all 3
476 // directions change in up to all three derivative indices will occur
477 for (unsigned int dxyz = 0; dxyz < 3; ++dxyz) {
478 if (is_simple() && dxyz != dir) // for integrals only consider
479 // derivatives in THE build direction
480 continue;
481
483 _d1.inc(dxyz);
484
485 std::shared_ptr<DGVertex> _nullptr;
486
487 // dA - _1?
488 {
489 const OriginDerivative<3u> dAm1(dA - _d1);
490 if (exists(dAm1)) { // yes
491 a.deriv() = dAm1;
492 auto ABCD_m = (part == 0 && not part0_has_unit)
493 ? factory.make_child(a, b, c, d, m)
494 : _nullptr;
495 auto ABCD_mp1 = factory.make_child(a, b, c, d, m + 1);
496 if (is_simple()) {
497 if (part == 0 && where == InBra) { // building on A
498 if (not part0_has_unit) {
499 expr_ -= Vector(dA)[dxyz] *
500 (Scalar("rho12_over_alpha1") * ABCD_m +
501 Scalar("alpha1_rho_over_zeta2") * ABCD_mp1);
502 nflops_ += 5;
503 } else {
504 expr_ -= Vector(dA)[dxyz] *
505 (Scalar("alpha1_rho_over_zeta2") * ABCD_mp1);
506 nflops_ += 3;
507 }
508 }
509 if (part == 0 && where == InKet) { // building on B
510 if (not part0_has_unit) {
511 expr_ += Vector(dA)[dxyz] *
512 (Scalar("rho12_over_alpha2") * ABCD_m -
513 Scalar("alpha1_rho_over_zeta2") * ABCD_mp1);
514 nflops_ += 5;
515 } else {
516 expr_ -= Vector(dA)[dxyz] *
517 (Scalar("alpha1_rho_over_zeta2") * ABCD_mp1);
518 nflops_ += 3;
519 }
520 }
521 if (part == 1) { // building on C or D
522 expr_ += Vector(dA)[dxyz] * Scalar("alpha1_over_zetapluseta") *
523 ABCD_mp1;
524 nflops_ += 3;
525 }
526 }
527 a.deriv() = dA;
528 }
529 }
530
531 // dB - _1?
532 {
533 const OriginDerivative<3u> dBm1(dB - _d1);
534 if (exists(dBm1)) { // yes
535 b.deriv() = dBm1;
536 auto ABCD_m = (part == 0 && not part0_has_unit)
537 ? factory.make_child(a, b, c, d, m)
538 : _nullptr;
539 auto ABCD_mp1 = factory.make_child(a, b, c, d, m + 1);
540 if (is_simple()) {
541 if (part == 0 && where == InBra) { // building on A
542 if (not part0_has_unit) {
543 expr_ += Vector(dB)[dxyz] *
544 (Scalar("rho12_over_alpha1") * ABCD_m -
545 Scalar("alpha2_rho_over_zeta2") * ABCD_mp1);
546 nflops_ += 5;
547 } else {
548 expr_ -= Vector(dB)[dxyz] *
549 (Scalar("alpha2_rho_over_zeta2") * ABCD_mp1);
550 nflops_ += 3;
551 }
552 }
553 if (part == 0 && where == InKet) { // building on B
554 if (not part0_has_unit) {
555 expr_ -= Vector(dB)[dxyz] *
556 (Scalar("rho12_over_alpha2") * ABCD_m +
557 Scalar("alpha2_rho_over_zeta2") * ABCD_mp1);
558 nflops_ += 5;
559 } else {
560 expr_ -= Vector(dB)[dxyz] *
561 (Scalar("alpha2_rho_over_zeta2") * ABCD_mp1);
562 nflops_ += 3;
563 }
564 }
565 if (part == 1) { // building on C or D
566 expr_ += Vector(dB)[dxyz] * Scalar("alpha2_over_zetapluseta") *
567 ABCD_mp1;
568 nflops_ += 3;
569 }
570 }
571 b.deriv() = dB;
572 }
573 }
574
575 // dC - _1?
576 {
577 const OriginDerivative<3u> dCm1(dC - _d1);
578 if (exists(dCm1)) { // yes
579 c.deriv() = dCm1;
580 auto ABCD_m = (part == 1 && not part1_has_unit)
581 ? factory.make_child(a, b, c, d, m)
582 : _nullptr;
583 auto ABCD_mp1 = factory.make_child(a, b, c, d, m + 1);
584 if (is_simple()) {
585 if (part == 0) { // building on A or B
586 expr_ += Vector(dC)[dxyz] * Scalar("alpha3_over_zetapluseta") *
587 ABCD_mp1;
588 nflops_ += 3;
589 }
590 if (part == 1 && where == InBra) { // building on C
591 if (not part1_has_unit) {
592 expr_ -= Vector(dC)[dxyz] *
593 (Scalar("rho34_over_alpha3") * ABCD_m +
594 Scalar("alpha3_rho_over_eta2") * ABCD_mp1);
595 nflops_ += 5;
596 } else {
597 expr_ -= Vector(dC)[dxyz] *
598 (Scalar("alpha3_rho_over_eta2") * ABCD_mp1);
599 nflops_ += 3;
600 }
601 }
602 if (part == 1 && where == InKet) { // building on D
603 if (not part1_has_unit) {
604 expr_ += Vector(dC)[dxyz] *
605 (Scalar("rho34_over_alpha4") * ABCD_m -
606 Scalar("alpha3_rho_over_eta2") * ABCD_mp1);
607 nflops_ += 5;
608 } else {
609 expr_ -= Vector(dC)[dxyz] *
610 (Scalar("alpha3_rho_over_eta2") * ABCD_mp1);
611 nflops_ += 3;
612 }
613 }
614 }
615 c.deriv() = dC;
616 }
617 }
618
619 // dD - _1?
620 {
621 const OriginDerivative<3u> dDm1(dD - _d1);
622 if (exists(dDm1)) { // yes
623 d.deriv() = dDm1;
624 auto ABCD_m = (part == 1 && not part1_has_unit)
625 ? factory.make_child(a, b, c, d, m)
626 : _nullptr;
627 auto ABCD_mp1 = factory.make_child(a, b, c, d, m + 1);
628 if (is_simple()) {
629 if (part == 0) { // building on A or B
630 expr_ += Vector(dD)[dxyz] * Scalar("alpha4_over_zetapluseta") *
631 ABCD_mp1;
632 nflops_ += 3;
633 }
634 if (part == 1 && where == InBra) { // building on C
635 if (not part1_has_unit) {
636 expr_ += Vector(dD)[dxyz] *
637 (Scalar("rho34_over_alpha3") * ABCD_m -
638 Scalar("alpha4_rho_over_eta2") * ABCD_mp1);
639 nflops_ += 5;
640 } else {
641 expr_ -= Vector(dD)[dxyz] *
642 (Scalar("alpha4_rho_over_eta2") * ABCD_mp1);
643 nflops_ += 3;
644 }
645 }
646 if (part == 1 && where == InKet) { // building on D
647 if (not part1_has_unit) {
648 expr_ -= Vector(dD)[dxyz] *
649 (Scalar("rho34_over_alpha4") * ABCD_m +
650 Scalar("alpha4_rho_over_eta2") * ABCD_mp1);
651 nflops_ += 5;
652 } else {
653 expr_ -= Vector(dD)[dxyz] *
654 (Scalar("alpha4_rho_over_eta2") * ABCD_mp1);
655 nflops_ += 3;
656 }
657 }
658 }
659 d.deriv() = dD;
660 }
661 }
662 }
663 } // end of deriv
664
665 return;
666}
667
668#if LIBINT_ENABLE_GENERIC_CODE
669template <class F, int part, FunctionPosition where>
671 const std::shared_ptr<CompilationParameters>& cparams) const {
672 if (TrivialBFSet<F>::result) return false;
673
674 F sh_a(target_->bra(0, 0));
675 F sh_b(target_->ket(0, 0));
676 F sh_c(target_->bra(1, 0));
677 F sh_d(target_->ket(1, 0));
678 const unsigned int max_opt_am = cparams->max_am_opt();
679 // generic code works for a0c0 of 0a0c classes where am(a) > 1 and am(c) > 1
680 // to generate optimized code for xxxx integral need to generate specialized
681 // code for up to (x+x)0(x+x)0 integrals
682 if (sh_b.zero() && sh_d.zero() &&
683 (sh_a.norm() > std::max(2 * max_opt_am, 1u) ||
684 sh_c.norm() > std::max(2 * max_opt_am, 1u)) &&
685 (sh_a.norm() > 1u && sh_c.norm() > 1u)) {
686 assert(part == 0); // has only implemented build on A in this case
687 return true;
688 }
689 if (sh_a.zero() && sh_c.zero() &&
690 (sh_b.norm() > std::max(2 * max_opt_am, 1u) ||
691 sh_d.norm() > std::max(2 * max_opt_am, 1u)) &&
692 (sh_b.norm() > 1u && sh_d.norm() > 1u)) {
693 assert(part == 0); // has only implemented build on B in this case
694 return true;
695 }
696 return false;
697}
698
699template <class F, int part, FunctionPosition where>
701 F sh_a(target_->bra(0, 0));
702 F sh_b(target_->ket(0, 0));
703 F sh_c(target_->bra(1, 0));
704 F sh_d(target_->ket(1, 0));
705 const bool xsxs = sh_b.zero() && sh_d.zero();
706 const bool sxsx = sh_a.zero() && sh_c.zero();
707
708 const OriginDerivative<3u> dA = target_->bra(0, 0).deriv();
709 const OriginDerivative<3u> dB = target_->ket(0, 0).deriv();
710 const OriginDerivative<3u> dC = target_->bra(1, 0).deriv();
711 const OriginDerivative<3u> dD = target_->ket(1, 0).deriv();
712 const bool deriv = !dA.zero() || !dB.zero() || !dC.zero() || !dD.zero();
713
714 if (!deriv) {
715 if (xsxs) return std::string("OSVRR_xs_xs.h");
716 if (sxsx) return std::string("OSVRR_sx_sx.h");
717 } else {
718 if (xsxs) return std::string("OSVRR_xs_xs_deriv.h");
719 if (sxsx) return std::string("OSVRR_sx_sx_deriv.h");
720 }
721 abort(); // unreachable
722}
723
724template <class F, int part, FunctionPosition where>
726 const std::shared_ptr<CodeContext>& context,
727 const std::shared_ptr<CodeSymbols>& args) const {
728 std::ostringstream oss;
729 F sh_a(target_->bra(0, 0));
730 F sh_b(target_->ket(0, 0));
731 F sh_c(target_->bra(1, 0));
732 F sh_d(target_->ket(1, 0));
733 const bool xsxs = sh_b.zero() && sh_d.zero();
734 const bool sxsx = sh_a.zero() && sh_c.zero();
735 bool ahlrichs_simplification = false;
736 bool unit_s = false;
737 bool part0_has_unit = false;
738 bool part1_has_unit = false;
739 if (xsxs) {
740 ahlrichs_simplification = (sh_a.pure_sh() && sh_b.is_unit()) ||
741 (sh_c.pure_sh() && sh_d.is_unit());
742 unit_s = sh_b.is_unit();
743 part0_has_unit = sh_b.is_unit();
744 part1_has_unit = sh_d.is_unit();
745 }
746 if (sxsx) {
747 ahlrichs_simplification = (sh_b.pure_sh() && sh_a.is_unit()) ||
748 (sh_d.pure_sh() && sh_c.is_unit());
749 unit_s = sh_a.is_unit();
750 part0_has_unit = sh_a.is_unit();
751 part1_has_unit = sh_c.is_unit();
752 }
753
754 const OriginDerivative<3u> dA = target_->bra(0, 0).deriv();
755 const OriginDerivative<3u> dB = target_->ket(0, 0).deriv();
756 const OriginDerivative<3u> dC = target_->bra(1, 0).deriv();
757 const OriginDerivative<3u> dD = target_->ket(1, 0).deriv();
758 const bool deriv = !dA.zero() || !dB.zero() || !dC.zero() || !dD.zero();
759
760 oss << "using namespace libint2;" << std::endl;
761
762 if (!deriv) { // for regular integrals I know exactly how many prerequisites
763 // I need
764 if (xsxs) {
765 oss << "libint2::OS" << (ahlrichs_simplification ? "A" : "")
766 << "VRR_xs_xs<" << part << "," << sh_a.norm() << "," << sh_c.norm()
767 << ",";
768 }
769 if (sxsx) {
770 oss << "libint2::OS" << (ahlrichs_simplification ? "A" : "")
771 << "VRR_sx_sx<" << part << "," << sh_b.norm() << "," << sh_d.norm()
772 << ",";
773 }
774 if (not ahlrichs_simplification) oss << (unit_s ? "true," : "false,");
775 oss << ((context->cparams()->max_vector_length() == 1) ? "false" : "true");
776 oss << ">::compute(inteval";
777
778 oss << "," << args->symbol(0); // target
779 if (not ahlrichs_simplification &&
780 unit_s) // purely to avoid having a 4-term generic RR, reuse 5-term
781 // with dummy argument
782 oss << ",0"; // src0-> 0x0
783 const unsigned int nargs = args->n();
784 for (unsigned int a = 1; a < nargs; a++) {
785 oss << "," << args->symbol(a);
786 }
787 oss << ");";
788 } else { // deriv == true -> only some arguments are needed
789 if (xsxs) {
790 oss << "libint2::OS" << (ahlrichs_simplification ? "A" : "")
791 << "VRR_xs_xs_deriv<" << part << "," << sh_a.norm() << ","
792 << sh_c.norm() << ",";
793 }
794 if (sxsx) {
795 oss << "libint2::OS" << (ahlrichs_simplification ? "A" : "")
796 << "VRR_sx_sx_deriv<" << part << "," << sh_b.norm() << ","
797 << sh_d.norm() << ",";
798 }
799
800 for (unsigned int xyz = 0; xyz < 3; ++xyz)
801 oss << sh_a.deriv().d(xyz) << ",";
802 for (unsigned int xyz = 0; xyz < 3; ++xyz)
803 oss << sh_b.deriv().d(xyz) << ",";
804 for (unsigned int xyz = 0; xyz < 3; ++xyz)
805 oss << sh_c.deriv().d(xyz) << ",";
806 for (unsigned int xyz = 0; xyz < 3; ++xyz)
807 oss << sh_d.deriv().d(xyz) << ",";
808 if (not ahlrichs_simplification) oss << (unit_s ? "true," : "false,");
809 oss << ((context->cparams()->max_vector_length() == 1) ? "false" : "true");
810 oss << ">::compute(inteval";
811 // out of all 22 possible prerequisites first few have same derivative
812 // degree as the target 5 if standard 4-center integral 1+4 if the center
813 // opposite the build center carries a unit function
814 // will pass 0 instead of src0
815 // 2 if Ahlrichs
816 oss << "," << args->symbol(0); // target
817 if (not ahlrichs_simplification &&
818 unit_s) // purely to avoid having a 4-term generic RR, reuse 5-term
819 // with dummy argument
820 oss << ",0"; // src0-> 0x0
821 // const unsigned int nargs = args->n();
822 unsigned int arg = 1;
823 for (;
824 arg <
825 (ahlrichs_simplification ? 3 : (unit_s ? 5 : 6)); // nargs + 1 target
826 arg++) {
827 oss << "," << args->symbol(arg);
828 }
829 for (unsigned int xyz = 0; xyz < 3; ++xyz) {
830 if (sh_a.deriv().d(xyz) > 0) {
831 // see the dA-1 clause: (ab|cd)^m is skipped
832 oss << ","
833 << (part0_has_unit ? std::to_string(0) : args->symbol(arg++));
834 oss << "," << args->symbol(arg++);
835 } else
836 oss << ",0,0";
837 if (sh_b.deriv().d(xyz) > 0) {
838 // see the dB-1 clause: (ab|cd)^m is skipped
839 oss << ","
840 << (part0_has_unit ? std::to_string(0) : args->symbol(arg++));
841 oss << "," << args->symbol(arg++);
842 } else
843 oss << ",0,0";
844 if (sh_c.deriv().d(xyz) > 0) {
845 oss << "," << args->symbol(arg++);
846 } else
847 oss << ",0";
848 if (sh_d.deriv().d(xyz) > 0) {
849 oss << "," << args->symbol(arg++);
850 } else
851 oss << ",0";
852 }
853 oss << ");";
854 }
855
856 return oss.str();
857}
858#endif // #if !LIBINT_ENABLE_GENERIC_CODE
859
860}; // namespace libint2
861
862#endif
Set of basis functions.
Definition bfset.h:43
Helps GenericRecurrenceRelation to work around the compiler problem with make_child.
Definition generic_rr.h:150
Generic integral over a two-body operator with one bfs for each particle in bra and ket.
Definition integral_11_11.h:36
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
static bool default_directional()
is this recurrence relation parameterized by a direction (x, y, or z).
Definition generic_rr.h:101
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
Represents cartesian derivatives of atom-centered basis functions.
Definition bfset.h:101
bool zero() const
norm() == 0
Definition bfset.h:158
void inc(unsigned int xyz, unsigned int c=1u)
Add c quanta along xyz.
Definition bfset.h:140
VRR Recurrence Relation for 2-e ERI.
Definition vrr_11_twoprep_11.h:36
static bool directional()
Default directionality.
Definition vrr_11_twoprep_11.h:48
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