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