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