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_oper_h_
22 #define _libint2_src_bin_libint_oper_h_
23 
24 #include <string>
25 
26 #include <boost/preprocessor/list/for_each.hpp>
27 
28 #include <hashable.h>
29 #include <global_macros.h>
30 #include <util.h>
31 #include <iter.h>
32 #include <vectorn.h>
33 #include <contractable.h>
34 #include <multipole.h>
35 
36 namespace libint2 {
37 
38   /** Permutational symmetries: antisymmetric(anti), symmetric(symm), nonsymmetric (nonsymm),
39       some more complicated symmetry (nonstd) */
40   struct PermutationalSymmetry {
41     typedef enum {anti=-1, symm=1, nonsymm=0, nonstd=-2} type;
42   };
43 
44   /** OperatorProperties describes various properties of an operator or operator set
45       @tparam NP number of particles
46       @tparam multi true if multiplicative
47       @tparam psymmetry symmetry with respect to permutation of bra and ket
48       @tparam origin_dependent true if operator is origin-dependent
49     */
50   template <unsigned int NP, bool multi, PermutationalSymmetry::type psymmetry,
51             bool origin_dependent = false>
52     class OperatorProperties {
53     public:
54       static constexpr auto np = NP;
55       static constexpr auto multiplicative = multi;
56       static constexpr auto psymm = psymmetry;
57       static constexpr auto odep = origin_dependent;
58     };
59 
60   /** OperSet is the base class for all (sets of) operators.
61      OperSet's must be constructable using
62      SafePtr<OperSet> or SafePtr<ConstructablePolymorphically>.
63   */
64   class OperSet : public ConstructablePolymorphically {
65     public:
66       typedef DummyIterator iter_type;
~OperSet()67       virtual ~OperSet() {};
68 
69       /// Returns full human-readable description of the operator
70       virtual std::string description() const =0;
71       /// Returns short label for the operator
72       virtual std::string label() const =0;
73       /** Returns 1, 0, or -1, if each operator in the set is symmetric, nonsymmetric,
74         or antisymmetric with respect to permutation of particles i and j */
75       virtual int psymm(int i, int j) const =0;
76       /** Returns 1, 0, or -1, if each operator in the set is Hermitian, non-Hermitian,
77         or anti-Hermitian w.r.t. particle p */
78       virtual int hermitian(int p) const =0;
79 
80       /// is operator origin-dependent?
81       virtual bool origin_dependent() const =0;
82 
83       /// Number of operators in the set
84       virtual unsigned int num_oper() const =0;
85     };
86 
87   /** Oper is OperSet characterized by properties Props
88   */
89   template <class Props>
90     class Oper : public OperSet {
91     public:
92       typedef Props Properties;
~Oper()93       virtual ~Oper() {}
94 
95       /// Implementation of OperSet::psymm()
96       int psymm(int i, int j) const override;
97       /// Implementation of OperSet::hermitian()
98       int hermitian(int p) const override;
99       /// Implementation of OperSet::origin_dependent()
origin_dependent()100       bool origin_dependent() const override { return Props::odep; }
101 
102       bool operator==(const Oper&) const;
103 
104     protected:
105       /// The only declared constructor is only useable by derived classes
Oper()106       Oper() {}
107 
108     private:
109       /// Must be overloaded by derived classes if Props::psymm == PermutationalSymmetry::nonstd
nonstd_psymm(int i,int j)110       virtual int nonstd_psymm(int i, int j) const { throw ProgrammingError("nonstd_psymm is not overloaded"); }
111       /// Must be overloaded by derived classes if Props::multi != true
nonstd_hermitian(int p)112       virtual int nonstd_hermitian(int p) const { throw ProgrammingError("nonstd_hermitian is not overloaded"); }
113   };
114 
115   template <class Props>
116     int
psymm(int i,int j)117     Oper<Props>::psymm(int i, int j) const
118     {
119       if (i<0 || i>=static_cast<int>(Props::np))
120         throw std::runtime_error("Oper<Props>::psymm(i,j) -- index i out of bounds");
121       if (j<0 || j>=static_cast<int>(Props::np))
122         throw std::runtime_error("Oper<Props>::psymm(i,j) -- index j out of bounds");
123       if (i == j)
124         return 1;
125 
126       switch(Props::psymm) {
127         case PermutationalSymmetry::anti:
128         return -1;
129         case PermutationalSymmetry::symm:
130         return 1;
131         case PermutationalSymmetry::nonsymm:
132         return 0;
133         case PermutationalSymmetry::nonstd:
134         return nonstd_psymm(i,j);
135         default:
136         abort();
137       }
138     }
139 
140   template <class Props>
141     int
hermitian(int p)142     Oper<Props>::hermitian(int p) const
143     {
144       if (Props::multiplicative)
145         return +1;
146       else
147         return nonstd_hermitian(p);
148     }
149 
150   template <class Props>
151   bool
152     Oper<Props>::operator==(const Oper& a) const
153     {
154       return true;
155     }
156 
157 //////////////////////////////
158 
159   /** GenOper is a single operator described by descriptor Descr
160   */
161   template <class Descr>
162     class GenOper : public Oper<typename Descr::Properties>, public Hashable<unsigned,ComputeKey> {
163     public:
164       typedef Descr Descriptor;
165       typedef typename Descr::Properties Properties;
166       typedef Oper<Properties> parent_type;
167       /// GenOper is not a set
168       typedef GenOper iter_type;
169 
num_oper()170       unsigned int num_oper() const override { return 1; }
171       /// Implementation of Hashable::key()
key()172       unsigned int key() const override { return descr_.key(); }
173       /// Range of key is [0,Descr::max_key)
174       static const unsigned int max_key = Descr::max_key;
175       /// Implementation of OperSet::description()
description()176       std::string description() const override { return descr_.description(); }
177       /// Implementation of OperSet::label()
label()178       std::string label() const override { return descr_.label(); }
179       /// Return the descriptor object
descr()180       Descr& descr() { return descr_; }
181       /// Return the descriptor object
descr()182       const Descr& descr() const { return descr_; }
183 
descr_(descr)184       GenOper(Descr descr = Descr()) : descr_(descr) {}
GenOper(const SafePtr<GenOper> & o)185       GenOper(const SafePtr<GenOper>& o) : descr_(o->descr_) {}
GenOper(const SafePtr<OperSet> & o)186       GenOper(const SafePtr<OperSet>& o) : descr_(require_dynamic_cast<GenOper,OperSet>(o)->descr_) {}
GenOper(const SafePtr<ConstructablePolymorphically> & o)187       GenOper(const SafePtr<ConstructablePolymorphically>& o) : descr_(require_dynamic_cast<GenOper,ConstructablePolymorphically>(o)->descr_) {}
GenOper(const ConstructablePolymorphically & o)188       explicit GenOper(const ConstructablePolymorphically& o) : descr_(require_dynamic_cast<GenOper,ConstructablePolymorphically>(&o)->descr_) {}
~GenOper()189       virtual ~GenOper() {}
190 
191     private:
192       Descr descr_;
193 
194       /// Implementation of Oper::nonstd_psymm()
nonstd_psymm(int i,int j)195       int nonstd_psymm(int i, int j) const override {
196         // TODO: figure out how to call this only if Desc::Properties::psymm == PermutationalSymmetry::nonstd
197         if (Descr::Properties::psymm == PermutationalSymmetry::nonstd)
198           return descr_.psymm(i,j);
199         else throw ProgrammingError("GenOper::nonstd_psymm -- descriptor is not nonstd");
200       }
201 
202       /// Implementation of Oper::nonstd_hermitian()
nonstd_hermitian(int i)203       int nonstd_hermitian(int i) const override {
204         // TODO: figure out how to call this only if Desc::Properties::psymm == PermutationalSymmetry::nonstd
205         if (!Descr::Properties::multiplicative)
206           return descr_.hermitian(i);
207         else throw ProgrammingError("GenOper::nonstd_hermitian -- this operator is multiplicative");
208       }
209 
210     };
211 
212 //////////////////////////////
213 
214   typedef OperatorProperties<1,false,PermutationalSymmetry::nonsymm> Nonmultiplicative1Body_Props;
215   typedef OperatorProperties<1,true, PermutationalSymmetry::nonsymm> Multiplicative1Body_Props;
216   typedef OperatorProperties<1,true, PermutationalSymmetry::nonsymm, true> MultiplicativeODep1Body_Props;
217   typedef OperatorProperties<2,true, PermutationalSymmetry::symm> MultiplicativeSymm2Body_Props;
218   typedef OperatorProperties<2,true, PermutationalSymmetry::nonsymm> MultiplicativeNonsymm2Body_Props;
219   typedef OperatorProperties<2,false,PermutationalSymmetry::symm> NonmultiplicativeSymm2Body_Props;
220   typedef OperatorProperties<2,false,PermutationalSymmetry::nonsymm> NonmultiplicativeNonsymm2Body_Props;
221 
222   /** GenMultSymmOper is a generic multiplicative symmetric N-body operator
223   */
224   template <unsigned int N>
225   struct GenMultSymmOper_Descr : public Contractable<GenMultSymmOper_Descr<N> > {
226     typedef OperatorProperties<N,true,PermutationalSymmetry::symm> Properties;
227     static const unsigned int max_key = 1;
keyGenMultSymmOper_Descr228     unsigned int key() const { return 0; }
descriptionGenMultSymmOper_Descr229     std::string description() const { return "generic multiplicative symmetric operator"; }
labelGenMultSymmOper_Descr230     std::string label() const { return "GenMultSymmOper"; }
psymmGenMultSymmOper_Descr231     int psymm(int i, int j) const { abort(); }
hermitianGenMultSymmOper_Descr232     int hermitian(int i) const { abort(); }
233   };
234   typedef GenOper< GenMultSymmOper_Descr<2>  > GenMultSymm2BodyOper;
235 
236 #define BOOST_PP_DECLARE_HERMITIAN_ONEBODY_DESCRIPTOR(r,propprefix,opname)                                  \
237     struct opname ## _Descr : public Contractable<opname ## _Descr> {                                       \
238       typedef propprefix ## 1Body_Props Properties;                                                         \
239       static const unsigned int max_key = 1;                                                                \
240       unsigned int key() const { return 0; }                                                                \
241       std::string description() const { return #opname; }                                                   \
242       std::string label() const { return #opname; }                                                         \
243       int psymm(int i, int j) const { abort(); }                                                      \
244       int hermitian(int i) const { return +1; }                                                             \
245     };                                                                                                      \
246     typedef GenOper<opname ## _Descr> opname ## Oper;                                                       \
247 
248 #define BOOST_PP_HERMITIAN_ONEBODY_OPER_LIST (Kinetic, BOOST_PP_NIL)
249 BOOST_PP_LIST_FOR_EACH ( BOOST_PP_DECLARE_HERMITIAN_ONEBODY_DESCRIPTOR, Nonmultiplicative, BOOST_PP_HERMITIAN_ONEBODY_OPER_LIST)
250 #undef BOOST_PP_HERMITIAN_ONEBODY_OPER_LIST
251 #define BOOST_PP_HERMITIAN_ONEBODY_OPER_LIST (Overlap, BOOST_PP_NIL)
252 BOOST_PP_LIST_FOR_EACH ( BOOST_PP_DECLARE_HERMITIAN_ONEBODY_DESCRIPTOR, Multiplicative, BOOST_PP_HERMITIAN_ONEBODY_OPER_LIST)
253 #undef BOOST_PP_HERMITIAN_ONEBODY_OPER_LIST
254 #define BOOST_PP_HERMITIAN_ONEBODY_OPER_LIST (ElecPot, BOOST_PP_NIL)
255 BOOST_PP_LIST_FOR_EACH ( BOOST_PP_DECLARE_HERMITIAN_ONEBODY_DESCRIPTOR, MultiplicativeODep, BOOST_PP_HERMITIAN_ONEBODY_OPER_LIST)
256 #undef BOOST_PP_HERMITIAN_ONEBODY_OPER_LIST
257 
258 /// cartesian multipole operator in \c NDIM dimensions
259 /// \f$ \hat{O}(\vec{k}) \equiv \vec{r}^{\cdot \vec{k}} = r_1^{k_1} r_2^{k_2} \cdots \f$
260 /// \internal OriginDerivative<NDIM> is used to store cartesian multipole quanta, not the derivative quanta
261 template <unsigned int NDIM>
262 struct CartesianMultipole_Descr : public Contractable<CartesianMultipole_Descr<NDIM>>,
263                                   public CartesianMultipoleQuanta<NDIM> {
264   typedef MultiplicativeODep1Body_Props Properties;
265   using CartesianMultipoleQuanta<NDIM>::max_key;
266 
CartesianMultipole_DescrCartesianMultipole_Descr267   CartesianMultipole_Descr() { }
CartesianMultipole_DescrCartesianMultipole_Descr268   CartesianMultipole_Descr(unsigned int k) { assert(NDIM==1u); this->inc(0,k); }
descriptionCartesianMultipole_Descr269   std::string description() const {
270     std::string descr("CartesianMultipole[");
271     std::ostringstream oss;
272     for(unsigned i=0; i!=NDIM; ++i) {
273       oss << (*this)[i];
274       if (i+1 != NDIM) oss << ",";
275     }
276     return descr + oss.str() + "]";
277   }
labelCartesianMultipole_Descr278   std::string label() const { return description(); }
psymmCartesianMultipole_Descr279   int psymm(int i, int j) const { abort(); }
hermitianCartesianMultipole_Descr280   int hermitian(int i) const { return +1; }
281 };
282 template <unsigned int NDIM> using CartesianMultipoleOper = GenOper<CartesianMultipole_Descr<NDIM>>;
283 
284 /** Represents quantum numbers of \em real spherical multipole operator
285  * defined in Eqs. 5 and 6 of J.M. Pérez-Jordá and W. Yang, J Chem Phys 104, 8003 (1996).
286  * ( \f$ m \geq 0 \f$ corresponds to moments \f$ \mathcal{N}^+ \f$ , \f$ m < 0 \f$ corresponds to \f$ \mathcal{N}^- \f$ )
287  */
288 struct SphericalMultipole_Descr : public Contractable<SphericalMultipole_Descr>, public SphericalMultipoleQuanta {
289   typedef MultiplicativeODep1Body_Props Properties;
290   using SphericalMultipoleQuanta::max_key;
291   using SphericalMultipoleQuanta::Sign;
292 
293   /// Default ctor makes a 0th-order multipole
SphericalMultipole_DescrSphericalMultipole_Descr294   SphericalMultipole_Descr() : SphericalMultipole_Descr(0,0) { }
295   /// constructs \f$ \mathcal{N}^{+}_{l,m} \f$ if \f$ m \geq 0 \f$, otherwise constructs \f$ \mathcal{N}^{-}_{l,m} \f$
SphericalMultipole_DescrSphericalMultipole_Descr296   SphericalMultipole_Descr(int l, int m) : SphericalMultipoleQuanta(l,m) {}
SphericalMultipole_DescrSphericalMultipole_Descr297   SphericalMultipole_Descr(int l, int m, Sign sign) : SphericalMultipoleQuanta(l,m,sign) {}
SphericalMultipole_DescrSphericalMultipole_Descr298   SphericalMultipole_Descr(const SphericalMultipoleQuanta& quanta) : SphericalMultipoleQuanta(quanta) {}
299 
descriptionSphericalMultipole_Descr300   std::string description() const {
301     std::string descr = std::string("SphericalMultipole[") + std::to_string(this->l()) + "," + std::to_string((this->sign() == Sign::plus ? 1 : -1) * this->m()) + "]";
302     return descr;
303   }
labelSphericalMultipole_Descr304   std::string label() const { return description(); }
psymmSphericalMultipole_Descr305   int psymm(int i, int j) const { abort(); }
hermitianSphericalMultipole_Descr306   int hermitian(int i) const { return +1; }
307 };
308 using SphericalMultipoleOper = GenOper<SphericalMultipole_Descr>;
309 
310   /** TwoPRep is the two-body repulsion operator.
311   */
312   struct TwoPRep_Descr : public Contractable<TwoPRep_Descr> {
313     typedef MultiplicativeSymm2Body_Props Properties;
314     static const unsigned int max_key = 1;
keyTwoPRep_Descr315     unsigned int key() const { return 0; }
descriptionTwoPRep_Descr316     std::string description() const { return "1/r_{12}"; }
labelTwoPRep_Descr317     std::string label() const { return "TwoPRep"; }
psymmTwoPRep_Descr318     int psymm(int i, int j) const { abort(); }
hermitianTwoPRep_Descr319     int hermitian(int i) const { return +1; }
320   };
321   typedef GenOper<TwoPRep_Descr> TwoPRep;
322 
323   /** GTG_1d is the two-body 1-dimensional Gaussian geminal
324   */
325   struct GTG_1d_Descr : public Contractable<GTG_1d_Descr> {
326     typedef MultiplicativeSymm2Body_Props Properties;
327     static const unsigned int max_key = 1;
keyGTG_1d_Descr328     unsigned int key() const { return 0; }
descriptionGTG_1d_Descr329     std::string description() const { return "GTG_1d"; }
labelGTG_1d_Descr330     std::string label() const { return "GTG_1d"; }
psymmGTG_1d_Descr331     int psymm(int i, int j) const { abort(); }
hermitianGTG_1d_Descr332     int hermitian(int i) const { return +1; }
333   };
334   typedef GenOper<GTG_1d_Descr> GTG_1d;
335 
336   /** R12_k_G12 is a two-body operator of form r_{12}^k * exp(-\gamma * r_{12}),
337       where k is an integer and \gamma is a positive real number.
338   */
339   class R12_k_G12_Descr : public Contractable<R12_k_G12_Descr> {
340   public:
341     typedef MultiplicativeSymm2Body_Props Properties;
342     /// K can range from -1 to 4
R12_k_G12_Descr(int K)343     R12_k_G12_Descr(int K) : K_(K) { assert(K >= -1 && K <= 4); }
R12_k_G12_Descr(const R12_k_G12_Descr & a)344     R12_k_G12_Descr(const R12_k_G12_Descr& a) : Contractable<R12_k_G12_Descr>(a), K_(a.K_) {}
345     static const unsigned int max_key = 5;
key()346     unsigned int key() const { return K_ + 1; }
description()347     std::string description() const { return label_(K_, this->contracted()); }
label()348     std::string label() const { return symbol_(K_, this->contracted()); }
K()349     int K() const { return K_; }
psymm(int i,int j)350     int psymm(int i, int j) const { abort(); }
hermitian(int i)351     int hermitian(int i) const { abort(); }
352   private:
353     R12_k_G12_Descr();
354     static std::string label_(int K, bool contracted);
355     static std::string symbol_(int K, bool contracted);
356     int K_;
357   };
358   typedef GenOper<R12_k_G12_Descr> R12kG12;
359 
360   /** R12k_R12l_G12 is a two-body operator of form ( r_{12x}^kx * r_{12y}^ky * r_{12z}^kz ) * (r_{12x}^lx * r_{12y}^ly * r_{12z}^lz ) * G12
361       The following restrictions are imposed: 0 <= kx+ky+kz <= 4, 0 <= lx+ly+lz <= 4
362     */
363   class R12k_R12l_G12_Descr : public Contractable<R12k_R12l_G12_Descr> {
364   public:
365     typedef MultiplicativeSymm2Body_Props Properties;
366     static const int kmax = 4;
R12k_R12l_G12_Descr(const IntVec3 & K,const IntVec3 & L)367     R12k_R12l_G12_Descr(const IntVec3& K, const IntVec3& L) : K_(K), L_(L) { }
R12k_R12l_G12_Descr(const R12k_R12l_G12_Descr & a)368     R12k_R12l_G12_Descr(const R12k_R12l_G12_Descr& a) : Contractable<R12k_R12l_G12_Descr>(a), K_(a.K_), L_(a.L_) {}
K()369     const IntVec3& K() const { return K_; }
L()370     const IntVec3& L() const { return L_; }
371     static const unsigned int max_key = kmax * kmax * kmax * kmax * kmax * kmax;
372     unsigned int key() const;
description()373     std::string description() const { return label_(K_,L_, this->contracted()); }
label()374     std::string label() const { return symbol_(K_,L_, this->contracted()); }
psymm(int i,int j)375     int psymm(int i, int j) const { abort(); }
hermitian(int i)376     int hermitian(int i) const { abort(); }
377   private:
378     R12k_R12l_G12_Descr();
379     static std::string label_(const IntVec3& K, const IntVec3& L, bool contracted);
380     static std::string symbol_(const IntVec3& K, const IntVec3& L, bool contracted);
381     IntVec3 K_;
382     IntVec3 L_;
383   };
384   typedef GenOper<R12k_R12l_G12_Descr> R12kR12lG12;
385 
386   /** Ti_G12 is a two-body operator of form [T_i, G12],
387       where i is particle index (0 or 1) and G12 is a Gaussian Geminal.
388   */
389   class Ti_G12_Descr : public Contractable<Ti_G12_Descr> {
390   public:
391     typedef NonmultiplicativeNonsymm2Body_Props Properties;
392     /// K can range from 0 to 1
393     static const unsigned int max_key = 2;
Ti_G12_Descr(int K)394     Ti_G12_Descr(int K) : K_(K) { assert(K >= 0 && K <= 1); }
Ti_G12_Descr(const Ti_G12_Descr & a)395     Ti_G12_Descr(const Ti_G12_Descr& a) : Contractable<Ti_G12_Descr>(a), K_(a.K_) {}
key()396     unsigned int key() const { return K_; }
description()397     std::string description() const { return label_(K_, this->contracted()); }
label()398     std::string label() const { return symbol_(K_, this->contracted()); }
K()399     int K() const { return K_; }
psymm(int i,int j)400     int psymm(int i, int j) const { abort(); }
hermitian(int i)401     int hermitian(int i) const { if (i != K_) return +1; else return -1; }
402   private:
403     Ti_G12_Descr();
404     static std::string label_(int K, bool contracted);
405     static std::string symbol_(int K, bool contracted);
406     int K_;
407   };
408   typedef GenOper<Ti_G12_Descr> TiG12;
409 
410   /** G12_Ti_G12 is a two-body operator of form [G12, [T_i, G12]] = (Nabla_i G12) \dot (Nabla_i G12)
411       where i is particle index (0 or 1) and G12 is a Gaussian Geminal.
412       It is a *multiplicative* operator!
413   */
414   class G12_Ti_G12_Descr : public Contractable<G12_Ti_G12_Descr> {
415   public:
416     typedef MultiplicativeSymm2Body_Props Properties;
417     /// K can range from 0 to 1
418     static const unsigned int max_key = 2;
G12_Ti_G12_Descr(int K)419     G12_Ti_G12_Descr(int K) : K_(K) { assert(K >= 0 && K <= 1); }
G12_Ti_G12_Descr(const G12_Ti_G12_Descr & a)420     G12_Ti_G12_Descr(const G12_Ti_G12_Descr& a) : Contractable<G12_Ti_G12_Descr>(a), K_(a.K_) {}
key()421     unsigned int key() const { return K_; }
description()422     std::string description() const { return label_(K_, this->contracted()); }
label()423     std::string label() const { return symbol_(K_, this->contracted()); }
K()424     int K() const { return K_; }
psymm(int i,int j)425     int psymm(int i, int j) const { abort(); }
hermitian(int i)426     int hermitian(int i) const { return +1; }
427   private:
428     G12_Ti_G12_Descr();
429     static std::string label_(int K, bool contracted);
430     static std::string symbol_(int K, bool contracted);
431     int K_;
432   };
433   typedef GenOper<G12_Ti_G12_Descr> G12TiG12;
434 
435   /** r_1.r_1 x g12 is a result of differentiation of exp( - a r_1^2 - a r_2^2 - c r_{12}^2) geminal .
436   */
437   struct R1dotR1_G12_Descr : public Contractable<R1dotR1_G12_Descr> {
438     typedef MultiplicativeNonsymm2Body_Props Properties;
439     static const unsigned int max_key = 1;
keyR1dotR1_G12_Descr440     unsigned int key() const { return 0; }
descriptionR1dotR1_G12_Descr441     std::string description() const { return "r_1.r_1 x G12"; }
labelR1dotR1_G12_Descr442     std::string label() const { return "R1dotR1_G12"; }
psymmR1dotR1_G12_Descr443     int psymm(int i, int j) const { abort(); }
hermitianR1dotR1_G12_Descr444     int hermitian(int i) const { abort(); }
445   };
446   typedef GenOper< R1dotR1_G12_Descr > R1dotR1_G12;
447 
448   /** r_2.r_2 x g12 is a result of differentiation of exp( - a r_1^2 - a r_2^2 - c r_{12}^2) geminal .
449   */
450   struct R2dotR2_G12_Descr : public Contractable<R2dotR2_G12_Descr> {
451     typedef MultiplicativeNonsymm2Body_Props Properties;
452     static const unsigned int max_key = 1;
keyR2dotR2_G12_Descr453     unsigned int key() const { return 0; }
descriptionR2dotR2_G12_Descr454     std::string description() const { return "r_2.r_2 x G12"; }
labelR2dotR2_G12_Descr455     std::string label() const { return "R2dotR2_G12"; }
psymmR2dotR2_G12_Descr456     int psymm(int i, int j) const { abort(); }
hermitianR2dotR2_G12_Descr457     int hermitian(int i) const { abort(); }
458   };
459   typedef GenOper< R2dotR2_G12_Descr > R2dotR2_G12;
460 
461   /** r_1.r_2 x g12 is a result of differentiation of exp( - a r_1^2 - a r_2^2 - c r_{12}^2) geminal .
462   */
463   struct R1dotR2_G12_Descr : public Contractable<R1dotR2_G12_Descr> {
464     typedef MultiplicativeSymm2Body_Props Properties;
465     static const unsigned int max_key = 1;
keyR1dotR2_G12_Descr466     unsigned int key() const { return 0; }
descriptionR1dotR2_G12_Descr467     std::string description() const { return "r_1.r_2 x G12"; }
labelR1dotR2_G12_Descr468     std::string label() const { return "R1dotR2_G12"; }
psymmR1dotR2_G12_Descr469     int psymm(int i, int j) const { abort(); }
hermitianR1dotR2_G12_Descr470     int hermitian(int i) const { abort(); }
471   };
472   typedef GenOper< R1dotR2_G12_Descr > R1dotR2_G12;
473 
474   /** \f$ (\nabla_I \cdot g_{12}') (g_{12}' \cdot \nabla_K) \f$ is a component of \f$ [g_{12}, [\nabla_I^4, g_{12}]] \f$ integral
475      where I = 1 or 2.
476   */
477   struct DivG12prime_xTx_Descr : public Contractable<DivG12prime_xTx_Descr> {
478     typedef NonmultiplicativeNonsymm2Body_Props Properties;
479     static const unsigned int max_key = 2;
DivG12prime_xTx_DescrDivG12prime_xTx_Descr480     DivG12prime_xTx_Descr(int I) : I_(I) { assert(I >= 0 && I <= 1); }
DivG12prime_xTx_DescrDivG12prime_xTx_Descr481     DivG12prime_xTx_Descr(const DivG12prime_xTx_Descr& a) : Contractable<DivG12prime_xTx_Descr>(a), I_(a.I_) {}
keyDivG12prime_xTx_Descr482     unsigned int key() const { return I_; }
descriptionDivG12prime_xTx_Descr483     std::string description() const { return label_(I_); }
labelDivG12prime_xTx_Descr484     std::string label() const { return symbol_(I_); }
IDivG12prime_xTx_Descr485     int I() const { return I_; }
psymmDivG12prime_xTx_Descr486     int psymm(int i, int j) const { abort(); }
hermitianDivG12prime_xTx_Descr487     int hermitian(int i) const { if (i != I_) return +1; else return -1; }
488     private:
489       DivG12prime_xTx_Descr();
490       static std::string label_(int I);
491       static std::string symbol_(int I);
492       int I_;
493   };
494   typedef GenOper< DivG12prime_xTx_Descr > DivG12prime_xTx;
495 
496 };
497 
498 #endif
499 
500