1 // FILE xsplit_data.cc : Implementation of member functions for class ff_data
2 //////////////////////////////////////////////////////////////////////////
3 //
4 // Copyright 1990-2012 Marcus Mo
5 //
6 // This file is part of the eclib package.
7 //
8 // eclib is free software; you can redistribute it and/or modify it
9 // under the terms of the GNU General Public License as published by the
10 // Free Software Foundation; either version 2 of the License, or (at your
11 // option) any later version.
12 //
13 // eclib is distributed in the hope that it will be useful, but WITHOUT
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 // for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with eclib; if not, write to the Free Software Foundation,
20 // Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 //
22 //////////////////////////////////////////////////////////////////////////
23 
24 // Include headers
25 #include "eclib/logger.h"
26 #include "eclib/xsplit.h"
27 
28 /**
29  * ff_data()
30  *
31  * Main constructor.
32  * Simply initiates private variables.
33  */
ff_data(form_finder * ff)34 ff_data::ff_data( form_finder* ff )
35   : ff_( ff ),
36     status_( INTERNAL ),
37     depth_( 0 ),
38     subdim_( 0 ),
39     eigenvalue_( 0 ),
40     eigrange_( 0 ),
41     eiglist_(),
42     abs_space_( NULL ),
43     rel_space_( NULL ),
44     conjmat_(),
45     the_opmat_(),
46     parent_( NULL ),
47     numChildren_( 0 ) {}
48 
49 /**
50  * ~ff_data()
51  *
52  * Destructor.
53  * Only delete the objects which this instance created.
54  * Prevents destruction of objects which may still be required
55  * by others, especially when running concurrently.
56  */
~ff_data()57 ff_data::~ff_data() {
58   // Delete dynamically created objects
59   delete abs_space_;
60   delete rel_space_;
61 }
62 
63 #ifdef ECLIB_MULTITHREAD
64 /**
65  * operator()
66  *
67  * Overloaded operator(). Required for object to be passed to
68  * job queue. Task is to scan test eigenvalues to identify
69  * newforms, or  whether further recursion is necessary.
70  */
operator ()()71 void ff_data::operator()() {
72   // Call go_down() on current node, passing through its parent
73   // to keep interface consistent with original.
74   ff_ -> go_down( *(this->parent_), eigenvalue_, 0 );
75 
76 #ifdef ECLIB_MULTITHREAD_DEBUG
77   ECLOG(1) << "Executing node (eig=" << eigenvalue_ << " depth=" <<depth_ << ")" << endl;
78 #endif
79 
80   // Call find() on current node
81   if( subdim_ > 0 ) ff_ -> find( *this );
82 
83   // Call go_up() only if this branch has ended
84   if( status_ != INTERNAL || subdim_ == 0 ) ff_ -> go_up( *this );
85 
86 #ifdef ECLIB_MULTITHREAD_DEBUG
87   ECLOG(1) << "Completed node (eig=" << eigenvalue_ << " depth=" <<depth_ << " status=" << status_ << ")" << endl;
88 #endif
89 }
90 #endif
91 
92 /**
93  * status()
94  *
95  * Return status of current node.
96  */
status()97 nodestatus ff_data::status() {
98   return status_;
99 }
100 
101 /**
102  * abs_space()
103  *
104  * Returns absolute subspace of current depth.
105  */
abs_space()106 ssubspace* ff_data::abs_space() {
107   return abs_space_;
108 }
109 
110 /**
111  * rel_space()
112  *
113  * Returns relative subspace of current depth.
114  */
rel_space()115 ssubspace* ff_data::rel_space() {
116   return rel_space_;
117 }
118 
119 /**
120  * depth()
121  *
122  * Returns current depth.
123  */
depth()124 long ff_data::depth() {
125   return depth_;
126 }
127 
128 /**
129  * subdim()
130  *
131  * Return subdimension
132  */
subdim()133 long ff_data::subdim() {
134   return subdim_;
135 }
136 
137 /**
138  * eig()
139  *
140  * Returns eigenvalue corresponding to current instance of class.
141  */
eig()142 long ff_data::eig() {
143   return eigenvalue_;
144 }
145 
146 /**
147  * eiglist()
148  *
149  * Build sequence of eigenvalues for current node by traversing up the tree.
150  * If an eiglist has already been computed, we simply return it to
151  * avoid accessing more nodes than necessary.
152  */
eiglist()153 vector< long > ff_data::eiglist() {
154   // Return precomputed eiglist if available
155   if( !eiglist_.empty() ) return eiglist_;
156 
157   // Root node (depth==0). Return empty vector.
158   if( parent_ == NULL ) return vector< long >();
159 
160   // Else, we concatenate lists from further up the tree.
161   eiglist_ = parent_ -> eiglist();
162   eiglist_.push_back( eigenvalue_ );
163 
164   return eiglist_;
165 }
166 
167 /**
168  * child()
169  *
170  * Returns pointer to child w.r.t. given eigenvalue.
171  */
child(long eig)172 ff_data* ff_data::child( long eig ) {
173   return children_[ map(eig) ];
174 }
175 
176 /**
177  * numCompleteChildren()
178  *
179  * Returns number of completed children for current node.
180  */
numCompleteChildren()181 int ff_data::numCompleteChildren() {
182   int completeCount = 0;
183 
184   vector< childstatus >::iterator it;
185   for( it = completedChildren_.begin(); it != completedChildren_.end(); it++ ) {
186     if( *it != NOT_COMPLETE ) completeCount++;
187   }
188 
189   return completeCount;
190 }
191 
192 /**
193  * complete()
194  *
195  * Return true if all children complete.
196  */
complete()197 bool ff_data::complete() {
198   return ( numCompleteChildren() == numChildren_ ) ? true : false;
199 }
200 
201 /**
202  * setStatus()
203  *
204  * Store status of current node.
205  */
setStatus(nodestatus s)206 void ff_data::setStatus( nodestatus s ) {
207   status_ = s;
208 }
209 
210 /**
211  * increaseDepth()
212  *
213  * Increases current depth. First check delta is positive.
214  */
increaseDepth(long delta)215 void ff_data::increaseDepth( long delta ) {
216   assert( delta > 0 );
217   depth_ += delta;
218 }
219 
220 /**
221  * decreaseDepth()
222  *
223  * Decrease current depth. First check delta is positive.
224  */
decreaseDepth(long delta)225 void ff_data::decreaseDepth( long delta ) {
226   assert( delta > 0 );
227   depth_ -= delta;
228 }
229 
230 /**
231  * increaseSubmatUsage()
232  *
233  * Locked counter increment method.
234  */
increaseSubmatUsage()235 void ff_data::increaseSubmatUsage() {
236 #ifdef ECLIB_MULTITHREAD
237   boost::mutex::scoped_lock lock( submat_lock_ );
238 #endif
239 
240 #ifdef ECLIB_MULTITHREAD_DEBUG
241   ECLOG(2) << "Increasing submat usage from " << submatUsage_ << " to " << submatUsage_+1
242            << " for node eig=" << eigenvalue_ << " depth=" << depth_ << endl;
243 #endif
244 
245   ++submatUsage_;
246 }
247 
248 /**
249  * storeBplus()
250  *
251  * Copies given vector into object storage.
252  * Use vec class overloaded operator=.
253  */
storeBplus(vec bp)254 void ff_data::storeBplus( vec bp ) {
255   bplus_ = bp;
256 }
257 
258 /**
259  * storeBminus()
260  *
261  * Copies given vector into object storage.
262  * Use vec class overloaded operator=.
263  */
storeBminus(vec bm)264 void ff_data::storeBminus( vec bm ) {
265   bminus_ = bm;
266 }
267 
268 /**
269  * addChild()
270  *
271  * Adds a new data node to the children vector.
272  */
addChild(long eig,ff_data & child)273 void ff_data::addChild( long eig, ff_data &child ) {
274   child.setParent( this );
275   child.setEigenvalue( eig );
276   children_[map(eig)] = &child;
277 }
278 
279 /**
280  * eraseChild()
281  *
282  * Calls the destructor for the data node corresponding to given eigenvalue.
283  */
eraseChild(long eig)284 void ff_data::eraseChild( long eig ) {
285   eraseChild( map(eig) );
286 }
287 
288 /**
289  * eraseChild()
290  *
291  * Overloaded method. Main method for destroying children.
292  */
eraseChild(int idx)293 void ff_data::eraseChild( int idx ) {
294 #ifdef ECLIB_MULTITHREAD_DEBUG
295   ECLOG(2) << "Deleting node (eig=" << children_[idx]->eigenvalue_
296            << " depth=" << depth_+1 << " status=" << children_[idx]->status_ << ")" << endl;
297 #endif
298 
299   delete children_[ idx ];
300   children_[ idx ] = NULL;
301   completedChildren_[ idx ] = DESTROYED;
302 }
303 
304 /**
305  * setParent()
306  *
307  * Stores pointer to parent data node.
308  */
setParent(ff_data * parent)309 void ff_data::setParent( ff_data *parent ) {
310   parent_ = parent;
311 }
312 
313 /**
314  * setEigenvalue()
315  *
316  * Stores eigenvalue.
317  */
setEigenvalue(long eig)318 void ff_data::setEigenvalue( long eig ) {
319   eigenvalue_ = eig;
320 }
321 
322 /**
323  * numChildren()
324  *
325  * Stores number of children and eigrange, and resize vectors to correct size.
326  */
setChildren(vector<long> eigs)327 void ff_data::setChildren( vector<long> eigs ) {
328   numChildren_ = eigs.size();
329   eigrange_ = eigs;
330 
331   children_.resize( numChildren_, NULL );
332   completedChildren_.resize( numChildren_, NOT_COMPLETE );
333 }
334 
335 /**
336  * childStatus()
337  *
338  * Sets value in map to 'flag', given a child node.
339  * Monitors how many of a nodes children have completed.
340  */
childStatus(long eig,childstatus flag)341 void ff_data::childStatus( long eig, childstatus flag ) {
342 #ifdef ECLIB_MULTITHREAD
343   boost::mutex::scoped_lock lock( childComplete_lock_ );
344 #endif
345 
346   completedChildren_[map(eig)] = flag;
347 }
348 
349 /**
350  * eraseChldren()
351  *
352  * Loops through containers and destroys all children.
353  */
eraseChildren()354 void ff_data::eraseChildren( ) {
355   if( numChildren_ > 0 ) {
356     for( int i = 0; i < numChildren_; i++ ) {
357       if ( children_[i] != NULL) {
358         children_[i] -> eraseChildren();
359         eraseChild( i );
360       }
361     }
362   }
363 }
364 
365 /**
366  * map()
367  *
368  * Hash function to map given eigenvalue
369  * to an index value. Removes dependancy on unordered_map.
370  *
371  * N.B. This function no longer makes assumptions on the eigenvalues,
372  * the number of which is numChildren_: in current practice, if
373  * numChildren_==2, they are [-1,+1] while otherwise
374  * numChildren_==2n+1 and they are [-n,...,-2,-1,0,1,2,...,n], but
375  * this specific choice is no longer relied on.
376  */
map(long eig)377 int ff_data::map( long eig ) {
378   int i = (int)(find(eigrange_.begin(),eigrange_.end(),eig)-eigrange_.begin());
379   return i;
380 }
381 
382 // end of XSPLIT_DATA.CC
383