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 #include <cmath> 22 #include <cstdlib> 23 #include <ctime> 24 #include <smart_ptr.h> 25 #include <time.h> 26 27 #ifndef _libint2_src_bin_libint_tactic_h_ 28 #define _libint2_src_bin_libint_tactic_h_ 29 30 namespace libint2 { 31 32 class DirectedGraph; 33 class RecurrenceRelation; 34 35 class DummyRandomizePolicy; 36 class StdRandomizePolicy; 37 38 /** Tactic is used to choose the optimal (in some sense) recurrence relation to reduce 39 a vertex. 40 */ 41 class Tactic { 42 public: 43 typedef SafePtr<RecurrenceRelation> RR; 44 typedef std::vector<RR> rr_stack; 45 Tactic()46 Tactic() {} ~Tactic()47 virtual ~Tactic() {} 48 49 virtual RR optimal_rr(const rr_stack& stack) const =0; 50 51 // make return true if need to debug Tactic classes class_debug()52 static constexpr bool class_debug() { 53 return false; 54 } 55 }; 56 57 /** FirstChoiceTactic simply chooses the first RR 58 */ 59 template <class RandomizePolicy = DummyRandomizePolicy> 60 class FirstChoiceTactic : public Tactic { 61 public: Tactic()62 FirstChoiceTactic(const SafePtr<RandomizePolicy>& rpolicy = SafePtr<RandomizePolicy>(new RandomizePolicy)) : Tactic(), rpolicy_(rpolicy) {} ~FirstChoiceTactic()63 virtual ~FirstChoiceTactic() {} 64 optimal_rr(const rr_stack & stack)65 RR optimal_rr(const rr_stack& stack) const { 66 if (!stack.empty()) 67 return stack[0 + rpolicy_->noise(stack.size())]; 68 else 69 return RR(); 70 } 71 72 private: 73 SafePtr<RandomizePolicy> rpolicy_; 74 }; 75 76 /** FewestNewVerticesTactic chooses RR which adds fewest new vertices to 77 DirectedGraph dg 78 */ 79 class FewestNewVerticesTactic : public Tactic { 80 public: FewestNewVerticesTactic(const SafePtr<DirectedGraph> & dg)81 FewestNewVerticesTactic(const SafePtr<DirectedGraph>& dg) : Tactic(), dg_(dg) {} ~FewestNewVerticesTactic()82 virtual ~FewestNewVerticesTactic() {} 83 84 RR optimal_rr(const rr_stack& stack) const; 85 86 private: 87 SafePtr<DirectedGraph> dg_; 88 }; 89 90 /** ZeroNewVerticesTactic chooses first RR which adds no new vertices on 91 DirectedGraph dg 92 */ 93 class ZeroNewVerticesTactic : public Tactic { 94 public: ZeroNewVerticesTactic(const SafePtr<DirectedGraph> & dg)95 ZeroNewVerticesTactic(const SafePtr<DirectedGraph>& dg) : Tactic(), dg_(dg) {} ~ZeroNewVerticesTactic()96 virtual ~ZeroNewVerticesTactic() {} 97 98 RR optimal_rr(const rr_stack& stack) const; 99 100 private: 101 SafePtr<DirectedGraph> dg_; 102 }; 103 104 /** RandomChoiceTactic chooses randomly among the applicable RRs 105 */ 106 class RandomChoiceTactic : public Tactic { 107 public: 108 RandomChoiceTactic(); ~RandomChoiceTactic()109 virtual ~RandomChoiceTactic() {} 110 111 RR optimal_rr(const rr_stack& stack) const; 112 }; 113 114 /** NullTactic always returns null RecurrenceRelation 115 */ 116 class NullTactic : public Tactic { 117 public: NullTactic()118 NullTactic() : Tactic() {} ~NullTactic()119 virtual ~NullTactic() {} 120 121 RR optimal_rr(const rr_stack& stack) const; 122 }; 123 124 /** 125 * ParticleDirectionTactic returns the first RR that transfers the quantum numbers between particles in 126 * the desired direction. 127 */ 128 class ParticleDirectionTactic : public Tactic { 129 public: 130 /** 131 * @param increasing if true, quanta should be transferred from lower to higher particle indices. 132 */ ParticleDirectionTactic(bool increase)133 ParticleDirectionTactic(bool increase) : Tactic(), increase_(increase) {} ~ParticleDirectionTactic()134 virtual ~ParticleDirectionTactic() {} 135 136 RR optimal_rr(const rr_stack& stack) const; 137 private: 138 bool increase_; 139 }; 140 141 /** 142 * TwoCenter_OS_Tactic decides graph build for <bra0|ket0> 143 */ 144 class TwoCenter_OS_Tactic : public Tactic { 145 public: 146 /** 147 * @param lbra0 148 * @param lket0 149 */ TwoCenter_OS_Tactic(unsigned lbra0,unsigned lket0)150 TwoCenter_OS_Tactic(unsigned lbra0, 151 unsigned lket0) : Tactic(), lbra0_(lbra0), lket0_(lket0) {} ~TwoCenter_OS_Tactic()152 virtual ~TwoCenter_OS_Tactic() {} 153 154 RR optimal_rr(const rr_stack& stack) const; 155 private: 156 unsigned lbra0_; 157 unsigned lket0_; 158 }; 159 160 /** 161 * FourCenter_OS_Tactic decides graph build for (bra0 ket0| bra1 ket1) = <bra0 bra1|ket0 ket1> 162 */ 163 class FourCenter_OS_Tactic : public Tactic { 164 public: 165 /** 166 * @param lbra0 167 * @param lbra1 168 * @param lket0 169 * @param lket1 170 */ FourCenter_OS_Tactic(unsigned lbra0,unsigned lket0,unsigned lbra1,unsigned lket1)171 FourCenter_OS_Tactic(unsigned lbra0, 172 unsigned lket0, 173 unsigned lbra1, 174 unsigned lket1) : Tactic(), lbra0_(lbra0), lket0_(lket0), 175 lbra1_(lbra1), lket1_(lket1) {} ~FourCenter_OS_Tactic()176 virtual ~FourCenter_OS_Tactic() {} 177 178 RR optimal_rr(const rr_stack& stack) const; 179 private: 180 unsigned lbra0_; 181 unsigned lket0_; 182 unsigned lbra1_; 183 unsigned lket1_; 184 }; 185 186 ///////////////////////////////// 187 188 struct DummyRandomizePolicy { noiseDummyRandomizePolicy189 unsigned int noise(unsigned int nrrs) const { return 0; } 190 }; 191 192 /** The shift parameter is computed as follows: 193 delta = floor(nrrs*scale*random()/RAND_MAX) 194 where nrrs is the number of possibilities, scale 195 is the user-specified parameter. 196 */ 197 class StdRandomizePolicy { 198 public: StdRandomizePolicy(double scale)199 StdRandomizePolicy(double scale) : scale_(scale) { 200 // Initialize state randomly 201 time_t t; 202 srandom(time(&t)); 203 } 204 noise(unsigned int nrrs)205 unsigned int noise(unsigned int nrrs) const { 206 unsigned long rand = random(); 207 const unsigned long range = RAND_MAX; 208 const unsigned int result = static_cast<unsigned int>(std::floor(nrrs*scale_*rand/range)); 209 return result; 210 } 211 212 private: 213 double scale_; 214 }; 215 216 217 }; 218 219 #endif 220 221