1 //
2 // BAGEL - Brilliantly Advanced General Electronic Structure Library
3 // Filename: gamma_task.h
4 // Copyright (C) 2013 Toru Shiozaki
5 //
6 // Author: Shane Parker <shane.parker@u.northwestern.edu>
7 // Maintainer: Toru Shiozaki
8 //
9 // This file is part of the BAGEL package.
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 //
24 
25 #ifndef __ASD_GAMMA_TASK_H
26 #define __ASD_GAMMA_TASK_H
27 
28 #include <src/asd/gamma_tree.h>
29 #include <src/ci/ras/apply_block.h>
30 
31 namespace bagel {
32 
33 template <typename VecType>
34 class GammaTask {
35   protected:
36     const int a_;                            // Orbital
37     const GammaSQ  operation_;               // Which operation
38     const std::shared_ptr<GammaTree<VecType>> tree_;  // destination
39 
40   public:
GammaTask(const std::shared_ptr<GammaTree<VecType>> tree,const GammaSQ operation,const int a)41     GammaTask(const std::shared_ptr<GammaTree<VecType>> tree, const GammaSQ operation, const int a) : a_(a), operation_(operation), tree_(tree) {}
42 
compute()43     void compute() {
44       constexpr int nops = 4;
45       const int norb = tree_->norb();
46 
47       auto action = [] (const int op) { return is_creation(GammaSQ(op)); };
48       auto spin = [] (const int op) { return is_alpha(GammaSQ(op)); };
49 
50       std::shared_ptr<GammaBranch<VecType>> first = tree_->base()->branch(operation_);
51       assert(first->active()); // This should have been checked before sending it to the TaskQueue
52 
53       std::shared_ptr<const VecType> avec = tree_->ket()->apply(a_, action(static_cast<int>(operation_)), spin(static_cast<int>(operation_)));
54       for (auto& ibra : first->bras())
55         dot_product(ibra.second, avec, first->gammas().find(ibra.first)->second->element_ptr(0,a_));
56 
57       for (int j = 0; j < nops; ++j) {
58         auto second = first->branch(j);
59         if (!second->active()) continue;
60 
61         for (int b = 0; b < norb; ++b) {
62           if (b==a_ && j==static_cast<int>(operation_)) continue;
63           std::shared_ptr<const VecType> bvec = avec->apply(b, action(j), spin(j));
64           for (auto& jbra : second->bras())
65             dot_product(jbra.second, bvec, second->gammas().find(jbra.first)->second->element_ptr(0, a_*norb + b));
66 
67           for (int k = 0; k < nops; ++k) {
68             std::shared_ptr<GammaBranch<VecType>> third = second->branch(k);
69             if (!third->active()) continue;
70 
71             for (int c = 0; c < norb; ++c) {
72               if (b==c && k==j) continue;
73               std::shared_ptr<const VecType> cvec = bvec->apply(c, action(k), spin(k));
74               for (auto& kbra : third->bras())
75                 dot_product(kbra.second, cvec, third->gammas().find(kbra.first)->second->element_ptr(0, a_*norb*norb + b*norb + c));
76             }
77           }
78         }
79       }
80     }
81 
82     private:
dot_product(std::shared_ptr<const VecType> bras,std::shared_ptr<const VecType> kets,double * target)83       void dot_product(std::shared_ptr<const VecType> bras, std::shared_ptr<const VecType> kets, double* target) const {
84         const int nbras = bras->ij();
85         const int nkets = kets->ij();
86 
87         for (int iket = 0; iket < nkets; ++iket) {
88           for (int jbra = 0; jbra < nbras; ++jbra, ++target) {
89             *target = bras->data(jbra)->dot_product(*kets->data(iket));
90           }
91         }
92       }
93 };
94 
95 template <>
96 void GammaTask<CASDvec>::compute();
97 
98 
99 template <class Branch>
100 class RASTask {
101   protected:
102     const int holes_;
103     const int particles_;
104 
105   public:
RASTask(const int h,const int p)106     RASTask(const int h, const int p) : holes_(h), particles_(p) {}
107     virtual std::shared_ptr<const RASString> stringspace(const int, const int, const int, const int , const int, const int) = 0;
108 
next_block(std::shared_ptr<Branch> branch,std::shared_ptr<const RASBlock<double>> base_block,const int & orbital,const bool & action,const bool & spin)109     std::shared_ptr<RASBlock<double>> next_block(std::shared_ptr<Branch> branch, std::shared_ptr<const RASBlock<double>> base_block,
110                                                  const int& orbital, const bool& action, const bool& spin) {
111       std::shared_ptr<const RASString> sa = base_block->stringsa();
112       std::shared_ptr<const RASString> sb = base_block->stringsb();
113 
114       std::array<int, 3> ras{{sa->ras<0>().second, sa->ras<1>().second, sa->ras<2>().second}};
115 
116       const int ras_space = ( orbital >= ras[0] ) + ( orbital >= (ras[0]+ras[1]) );
117       std::array<int, 6> info{{ras[0] - sa->nholes(), ras[0] - sb->nholes(), sa->nele2(), sb->nele2(), sa->nparticles(), sb->nparticles()}};
118 
119       const int mod = action ? +1 : -1;
120       info[2*ras_space]   += spin ? mod : 0;
121       info[2*ras_space+1] += spin ? 0 : mod;
122 
123       // make sure it is a valid result
124       for (int i = 0; i < 6; ++i)
125         if (info[i] < 0 || info[i] > ras[i/2]) return nullptr;
126 
127       // is it out of space?
128       const int nholes = 2*ras[0] - (info[0] + info[1]);
129       const int nparts = info[4] + info[5];
130       if (nholes > holes_ || nparts > particles_) {
131         // peek ahead along the branch to see whether it will come back into the space
132 
133         // set of operations that would bring state back
134         std::set<int> needed;
135         if (nholes == (holes_+1)) {
136           if (info[0] == ras[0]) {
137             // no alpha holes, only beta holes
138             needed.insert(static_cast<int>(GammaSQ::CreateBeta));
139           } else if (info[1] == ras[0]) {
140             // no beta holes, only alpha holes
141             needed.insert(static_cast<int>(GammaSQ::CreateAlpha));
142           } else {
143             // both types of holes present
144             needed.insert(static_cast<int>(GammaSQ::CreateAlpha));
145             needed.insert(static_cast<int>(GammaSQ::CreateBeta));
146           }
147         } else if (nparts == (particles_+1)) {
148           if (info[4] == 0) {
149             // no alpha particles, only beta particles
150             needed.insert(static_cast<int>(GammaSQ::AnnihilateBeta));
151           } else if (info[5] == 0) {
152             // no beta particles, only alpha particles
153             needed.insert(static_cast<int>(GammaSQ::AnnihilateAlpha));
154           } else {
155             // both present
156             needed.insert(static_cast<int>(GammaSQ::AnnihilateBeta));
157             needed.insert(static_cast<int>(GammaSQ::AnnihilateAlpha));
158           }
159         } else {
160           // impossible to contribute
161           return nullptr;
162         }
163 
164         // search down branch for active branches with needed operations
165         if (!branch->if_contributes(needed))
166           return nullptr;
167       }
168 
169       std::shared_ptr<const RASString> ta = spin ? stringspace(info[0], ras[0], info[2], ras[1], info[4], ras[2]) : sa;
170       std::shared_ptr<const RASString> tb = spin ? sb : stringspace(info[1], ras[0], info[3], ras[1], info[5], ras[2]);
171 
172       auto out = std::make_shared<RASBlock_alloc<double>>(ta,tb);
173 
174       RAS::Apply_block apply_block(orbital, action, spin);
175       apply_block(base_block, out, branch->is_distterminal());
176 
177       return out;
178     }
179 };
180 
181 template <>
182 class GammaTask<RASDvec> : public RASTask<GammaBranch<RASDvec>> {
183   protected:
184     const int a_;                                     // Orbital
185     const GammaSQ  operation_;                        // Which operation
186     const std::shared_ptr<GammaTree<RASDvec>> tree_;  // destination
187 
188     // to avoid rebuilding the stringspaces repeatedly
189     std::map<std::tuple<int, int, int, int, int, int>, std::shared_ptr<const RASString>> stringspaces_;
190 
191   public:
GammaTask(const std::shared_ptr<GammaTree<RASDvec>> tree,const GammaSQ operation,const int a)192     GammaTask(const std::shared_ptr<GammaTree<RASDvec>> tree, const GammaSQ operation, const int a)
193               : RASTask<GammaBranch<RASDvec>>(tree->ket()->det()->max_holes(), tree->ket()->det()->max_particles()),
194                 a_(a), operation_(operation), tree_(tree) {}
195 
compute()196     void compute() {
197       constexpr int nops = 4;
198       const int norb = tree_->norb();
199 
200       auto action = [] (const int op) { return is_creation(GammaSQ(op)); };
201       auto spin = [] (const int op) { return is_alpha(GammaSQ(op)); };
202 
203       std::shared_ptr<GammaBranch<RASDvec>> first = tree_->base()->branch(operation_);
204       assert(first->active()); // This should have been checked before sending it to the TaskQueue
205 
206       std::shared_ptr<const RASDeterminants> base_det = tree_->ket()->det();
207 
208       const int nkets = tree_->ket()->ij();
209       for (int iket = 0; iket < nkets; ++iket) {
210         std::shared_ptr<const RASCivec> ketvec = tree_->ket()->data(iket);
211         for (auto& ketblock : ketvec->blocks()) {
212           if (!ketblock) continue;
213           std::shared_ptr<const RASBlock<double>> ablock
214             = next_block(first, ketblock, a_, action(static_cast<int>(operation_)), spin(static_cast<int>(operation_)));
215           if (!ablock) continue;
216 
217           for (auto& ibra : first->bras())
218             dot_product(ibra.second, ablock, first->gammas().find(ibra.first)->second->element_ptr(iket*ibra.second->ij(), a_));
219 
220           for (int j = 0; j < nops; ++j) {
221             auto second = first->branch(j);
222             if (!second->active()) continue;
223 
224             for (int b = 0; b < norb; ++b) {
225               if (b==a_ && j==static_cast<int>(operation_)) continue;
226               std::shared_ptr<const RASBlock<double>> bblock = next_block(second, ablock, b, action(j), spin(j));
227               if (!bblock) continue;
228 
229               for (auto& jbra : second->bras())
230                 dot_product(jbra.second, bblock, second->gammas().find(jbra.first)->second->element_ptr(iket*jbra.second->ij(), a_*norb + b));
231 
232               for (int k = 0; k < nops; ++k) {
233                 std::shared_ptr<GammaBranch<RASDvec>> third = second->branch(k);
234                 if (!third->active()) continue;
235 
236                 for (int c = 0; c < norb; ++c) {
237                   if (b==c && k==j) continue;
238                   std::shared_ptr<const RASBlock<double>> cblock = next_block(third, bblock, c, action(k), spin(k));
239                   if (!cblock) continue;
240                   for (auto& kbra : third->bras())
241                     dot_product(kbra.second, cblock, third->gammas().find(kbra.first)->second->element_ptr(iket*kbra.second->ij(), a_*norb*norb + b*norb + c));
242                 }
243               }
244             }
245           }
246         }
247       }
248     }
249 
250     private:
dot_product(std::shared_ptr<const RASDvec> bras,std::shared_ptr<const RASBlock<double>> ketblock,double * target)251       void dot_product(std::shared_ptr<const RASDvec> bras, std::shared_ptr<const RASBlock<double>> ketblock, double* target) const {
252         const int nbras = bras->ij();
253 
254         if (bras->det()->allowed(ketblock->stringsb(), ketblock->stringsa())) {
255           for (int jbra = 0; jbra < nbras; ++jbra, ++target) {
256             std::shared_ptr<const RASBlock<double>> brablock = bras->data(jbra)->block(ketblock->stringsb(), ketblock->stringsa());
257             if (brablock)
258               *target += blas::dot_product(brablock->data(), brablock->size(), ketblock->data());
259           }
260         }
261       }
262 
stringspace(const int a,const int b,const int c,const int d,const int e,const int f)263       std::shared_ptr<const RASString> stringspace(const int a, const int b, const int c, const int d, const int e, const int f) final {
264         auto iter = stringspaces_.find(std::make_tuple(a,b,c,d,e,f));
265         if (iter != stringspaces_.end()) {
266           return iter->second;
267         }
268         else {
269           stringspaces_.emplace(std::make_tuple(a,b,c,d,e,f), std::make_shared<RASString>(a,b,c,d,e,f));
270           return stringspaces_[std::make_tuple(a,b,c,d,e,f)];
271         }
272       }
273 };
274 
275 }
276 
277 #endif
278