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_dgvertex_h_ 22 #define _libint2_src_bin_libint_dgvertex_h_ 23 24 #include <list> 25 #include <vector> 26 //#include <dg.h> 27 #include <global_macros.h> 28 #include <drtree.h> 29 #include <dgarc.h> 30 #include <iostream> 31 #include <string> 32 #include <smart_ptr.h> 33 #include <memory.h> 34 #include <exception.h> 35 #include <hashable.h> 36 #include <key.h> 37 38 namespace libint2 { 39 40 class DirectedGraph; 41 42 /// This is a vertex of a Directed Graph (DG) 43 class DGVertex : public Hashable<KeyTypes::InstanceID,ComputeKey> { 44 public: 45 /// The address on the stack during computation is described using this type 46 typedef MemoryManager::Address Address; 47 /// The size of a block the stack during computation is described using this type 48 typedef MemoryManager::Size Size; 49 /// Exception thrown if address is not set 50 typedef NotSet<Address> AddressNotSet; 51 /// Exception thrown if graph label is not set 52 typedef NotSet<std::string> GraphLabelNotSet; 53 /// Exception thrown if code symbol is not set 54 typedef NotSet<std::string> SymbolNotSet; 55 /// Type identifier 56 typedef KeyTypes::ClassID ClassID; 57 /// Instance identifier 58 typedef KeyTypes::InstanceID InstanceID; 59 /** DGVertex provides function key() which computes key of type KeyType and 60 returns it using KeyReturnType */ 61 typedef KeyTypes::InstanceID KeyType; 62 typedef Hashable<KeyType,ComputeKey>::KeyReturnType KeyReturnType; 63 /// ArcSetType is a container used to maintain entry and exit arcs 64 typedef std::list< SafePtr<DGArc> > ArcSetType; 65 66 /** typeid stores the ClassID of the concrete type. It is used to check quickly whether 67 2 DGVertices are of the same type. Dynamic casts are too expensive. */ 68 ClassID typeid_; 69 /** instid stores the InstanceID of the object. Only makes sense for Singletons. 70 For other objects it's zero. Can be used to compare objects quickly. */ 71 InstanceID instid_; 72 /// Sets typeid to tid 73 DGVertex(ClassID tid); 74 /// Sets typeid to tid 75 DGVertex(ClassID tid, const std::vector<SafePtr<DGArc> >& parents, const std::vector<SafePtr<DGArc> >& children); 76 /// This is a copy constructor 77 DGVertex(const DGVertex& v); 78 virtual ~DGVertex(); 79 80 /// make_a_target() marks this vertex as a target 81 void make_a_target(); 82 /// is_a_target() returns true if this vertex is a target is_a_target()83 bool is_a_target() const { return target_;}; 84 /** add_exit_arc(arc) adds arc as an arc connecting to children of this vertex. 85 Thus, arcs are owned by their PARENTS. This function is virtual because 86 certain types of vertices have duplicate references to children in their 87 definition (such as AlgebraicOperator). Such DGVertices need to update their 88 private members. 89 */ 90 virtual void add_exit_arc(const SafePtr<DGArc>&); 91 /** del_exit_arcs() removes all exit arcs from this and corresponding children vertices. 92 See documentation for del_exit_arc(). 93 */ 94 virtual void del_exit_arcs(); 95 /** replace_exit_arc() replaces A with B. See documentation for del_exit_arc(). 96 */ 97 void replace_exit_arc(const SafePtr<DGArc>& A, const SafePtr<DGArc>& B); 98 /** this function detaches the vertex from other vertices. It cannot safely remove 99 entry arcs, so the user must previously delete or replace them (see documentation for del_exit_arc()). 100 can throw CannotPerformOperation. 101 */ 102 void detach(); 103 exit_arcs()104 const ArcSetType& exit_arcs() const { return children_; } entry_arcs()105 const ArcSetType& entry_arcs() const { return parents_; } 106 /// returns the number of parents 107 unsigned int num_entry_arcs() const; 108 /// returns parents::begin() first_entry_arc()109 ArcSetType::const_iterator first_entry_arc() const { return parents_.begin(); } 110 /// returns parents::end() plast_entry_arc()111 ArcSetType::const_iterator plast_entry_arc() const { return parents_.end(); } 112 /// returns the number of children 113 unsigned int num_exit_arcs() const; 114 /// returns children::begin() first_exit_arc()115 ArcSetType::const_iterator first_exit_arc() const { return children_.begin(); } 116 /// returns children::end() plast_exit_arc()117 ArcSetType::const_iterator plast_exit_arc() const { return children_.end(); } 118 /// return arc connecting this to v, otherwise null pointer 119 const SafePtr<DGArc>& exit_arc(const SafePtr<DGVertex>& v) const; 120 121 /// computes key 122 virtual KeyReturnType key() const =0; 123 /** equiv(const DGVertex* aVertex) returns true if this vertex is 124 equivalent to *aVertex. 125 */ 126 virtual bool equiv(const SafePtr<DGVertex>&) const =0; 127 128 /** precomputed() returns whether this DGVertex is precomputed. See 129 this_precomputed() for description. 130 */ 131 bool precomputed() const; 132 133 /** Returns the amount of memory (in floating-point words) to be allocated for the vertex. 134 */ 135 virtual unsigned int size() const =0; 136 137 /** label() returns a unique, short, descriptive label of DGVertex (e.g. "( p_x s | 1/r_{12} | d_xy s )^{(1)}") 138 */ 139 virtual const std::string& label() const =0; 140 /** id() returns a very short label of DGVertex which is (almost) 141 guaranteed to be a symbol (e.g. "(p_x s|d_xy s)^1") 142 */ 143 virtual const std::string& id() const =0; 144 /** description() returns a full, human-readable description of DGVertex (e.g. "This is a ( p_x s | 1/r_{12} | d_xy s )^{(1)} integral"). 145 returned by value since not guaranteed to be cached. 146 */ 147 virtual std::string description() const =0; 148 /** print(os) prints vertex info to os */ 149 virtual void print(std::ostream& os) const; 150 151 /// Returns pointer to the DirectedGraph to which this DGVertex belongs to dg()152 const DirectedGraph* dg() const { return dg_; } 153 /// Sets pointer to the DirectedGraph to which this DGVertex belongs to. Should be used with utmost caution dg(const DirectedGraph * d)154 void dg(const DirectedGraph* d) { dg_ = d; } 155 /// returns the label used for this vertex when visualizing graph. can throw GraphLabelNotSet. 156 const std::string& graph_label() const; 157 /// sets the graph label 158 void set_graph_label(const std::string& graph_label); 159 160 /// Returns the subtree to which this vertex belongs subtree()161 const SafePtr<DRTree>& subtree() const { return subtree_; } 162 163 // 164 // NOTE : the following functions probably belong to a separate class, such as Entity! 165 // 166 167 /** 168 refer_this_to(V) makes this vertex act like a reference to V so that 169 calls to symbol() and address() report code symbol and stack address of V 170 */ 171 void refer_this_to(const SafePtr<DGVertex>& V); 172 /// refers to another vertex? refers_to_another()173 bool refers_to_another() const { return referred_vertex_ != 0; } 174 /// returns the code symbol. can throw SymbolNotSet 175 const std::string& symbol() const; 176 /// sets the code symbol 177 void set_symbol(const std::string& symbol); 178 /// returns true if the symbol has been set 179 bool symbol_set() const; 180 /// this function void the symbol, i.e. it is no longer set after calling this member 181 void reset_symbol(); 182 /// returns the address of this quantity on Libint's stack. can throw AddressNotSet 183 Address address() const; 184 /// sets the address of this quantity on Libint's stack 185 void set_address(const Address& address); 186 /// returns true if the address has been set 187 bool address_set() const; 188 /** indicates whether this vertex needs to be computed. 189 Even if this vertex is not precomputed, it may not be desired 190 to compute it. By default, all vertices need to be computed. 191 */ 192 void need_to_compute(bool ntc); 193 /// shortcut to need_to_compute(false) not_need_to_compute()194 void not_need_to_compute() { need_to_compute(false); } 195 /// returns true if this index needs to be computed. 196 bool need_to_compute() const; 197 #if CHECK_SAFETY declared()198 bool declared() const { return precomputed() ? true : declared_; } declared(bool d)199 void declared(bool d) { declared_ = d; } 200 #endif 201 202 /// prepare_to_traverse() must be called before traversal of the graph starts 203 void prepare_to_traverse(); 204 /// tag() tags the vertex and returns the total number of tags this vertex has received 205 unsigned int tag(); 206 /// schedule() marks the vertex as scheduled, hence its code exists schedule()207 void schedule() { scheduled_ = true; } 208 /// scheduled() returns true if the vertex has been scheduled scheduled()209 bool scheduled() const { return scheduled_; } 210 /// Returns pointer to vertex to be computed after this vertex, 0 if this is the last vertex postcalc()211 SafePtr<DGVertex> postcalc() const { return postcalc_; }; 212 /// Sets postcalc set_postcalc(const SafePtr<DGVertex> & postcalc)213 void set_postcalc(const SafePtr<DGVertex>& postcalc) { postcalc_ = postcalc; }; 214 215 /// Resets the vertex, releasing all arcs 216 void reset(); 217 /// If vertex is a singleton then remove it from the SingletonManager. Must be reimplemented in derived singleton class 218 virtual void unregister() const; 219 220 public: 221 222 /** this_precomputed() is used by precomputed() to determine whether this 223 object really is precomputed. E.g. (ss|ss) shell is considered not 224 precomputed, i.e. this_precomputed() will return false. But the (ss|ss) 225 integral is considered precomputed. Usually the shell vertex 226 will refer to the integral vertex. Thus calling precomputed() on it 227 will return true. 228 */ 229 virtual bool this_precomputed() const =0; 230 231 private: 232 /// the pointer to the graph to which this vertex belongs (can be null) 233 const DirectedGraph* dg_; 234 /// label for the vertex within the graph 235 std::string graph_label_; 236 237 /// if not null -- use this vertex to report address and symbol 238 const DGVertex* referred_vertex_; 239 /// vertices that refer to this 240 std::vector<const DGVertex*> refs_; 241 /// increments number of references 242 void register_reference(const DGVertex*); 243 244 /// symbol used in the code 245 std::string symbol_; 246 /// Address on the stack 247 Address address_; 248 // Whether this vertex needs to be computed 249 bool need_to_compute_; 250 #if CHECK_SAFETY 251 // has the symbol been declared in the code? 252 bool declared_; 253 #endif 254 255 /// We also need info about Arcs entering this DGVertex 256 ArcSetType parents_; 257 /// Arcs leaving this DGVertex. Derived classes may need direct access to exit arcs. 258 ArcSetType children_; 259 260 // Whether this is a "target" vertex, i.e. the target of a calculation 261 bool target_; 262 // If set to true -- traversal has started and add_entry... cannot be called 263 bool can_add_arcs_; 264 265 /** del_exit_arc(arc) removes arc c (from this and corresponding child). 266 NOTE: This function is private because for some classes order of exit arcs 267 matters (such as noncommutative AlgebraicOperator). Thus it may not be safe 268 to use del_exit_arc() to replace an arc. replace_exit_arc() should be used 269 in such instances. 270 */ 271 void del_exit_arc(const SafePtr<DGArc>& c); 272 /// add_entry_arc(arc) adds arc as an arc connecting parents to this vertex 273 void add_entry_arc(const SafePtr<DGArc>&); 274 /// del_entry_arc(arc) removes arc as an arc connecting parents to this vertex 275 void del_entry_arc(const SafePtr<DGArc>&); 276 277 //////// 278 // These members used in traversal and scheduling algorithms 279 //////// 280 281 /// num_tagged_arcs keeps track of how many entry arcs have been tagged during traversal 282 unsigned int num_tagged_arcs_; 283 /// Which DGVertex to be computed after this vertex (0, if this is the last vertex) 284 SafePtr<DGVertex> postcalc_; 285 /// has it been scheduled? 286 bool scheduled_; 287 288 289 /////// 290 // Refback to subtree which contains this vertex 291 /////// 292 293 // note that this is a refback (back reference to the "owning" object) so changing it 294 // does not change class invariant -- hence mutable 295 296 /// the subtree which contains this vertex (may be null). subtree is a directed rooted tree. 297 mutable SafePtr<DRTree> subtree_; 298 /// Only DRTree::set_subtree and DRTree::detach_from can change subtree_ 299 friend void DRTree::add_vertex(const SafePtr<DGVertex>& vertex); 300 friend void DRTree::detach_from(const SafePtr<DGVertex>& v); 301 302 }; 303 304 // 305 // Nonmember predicates 306 // 307 /// return true if V is an unrolled IntegralSet 308 struct UnrolledIntegralSet : public std::unary_function<const SafePtr<DGVertex>&,bool> { 309 bool operator()(const SafePtr<DGVertex>& V); 310 }; 311 /// return false if V is an unrolled IntegralSet 312 struct NotUnrolledIntegralSet : public std::unary_function<const SafePtr<DGVertex>&,bool> { 313 bool operator()(const SafePtr<DGVertex>& V); 314 }; 315 /// return true if V is an Integral in an unrolled target IntegralSet 316 struct IntegralInTargetIntegralSet : public std::unary_function<const SafePtr<DGVertex>&,bool> { 317 bool operator()(const SafePtr<DGVertex>& V); 318 }; 319 key(const DGVertex & v)320 inline DGVertexKey key(const DGVertex& v) { 321 return DGVertexKey(v.typeid_,v.instid_); 322 } 323 324 }; 325 326 #endif 327 328