leveled.cpp
Go to the documentation of this file.00001 /*************************************************************************** 00002 file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/src/model/leveled.cpp $ 00003 version : $LastChangedRevision: 635 $ $LastChangedBy: jdetaeye $ 00004 date : $LastChangedDate: 2007-12-30 15:20:00 +0100 (Sun, 30 Dec 2007) $ 00005 ***************************************************************************/ 00006 00007 /*************************************************************************** 00008 * * 00009 * Copyright (C) 2007 by Johan De Taeye * 00010 * * 00011 * This library is free software; you can redistribute it and/or modify it * 00012 * under the terms of the GNU Lesser General Public License as published * 00013 * by the Free Software Foundation; either version 2.1 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 * This library is distributed in the hope that it will be useful, * 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 00019 * General Public License for more details. * 00020 * * 00021 * You should have received a copy of the GNU Lesser General Public * 00022 * License along with this library; if not, write to the Free Software * 00023 * Foundation Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA * 00024 * * 00025 ***************************************************************************/ 00026 00027 00028 #define FREPPLE_CORE 00029 #include "frepple/model.h" 00030 #include <climits> 00031 00032 00033 // Uncomment the following line to create debugging statements during the 00034 // clustering and leveling algorithm. 00035 //#define CLUSTERDEBUG 00036 00037 00038 namespace frepple 00039 { 00040 00041 00042 DECLARE_EXPORT bool HasLevel::recomputeLevels = false; 00043 DECLARE_EXPORT bool HasLevel::computationBusy = false; 00044 DECLARE_EXPORT short unsigned HasLevel::numberOfClusters = 0; 00045 DECLARE_EXPORT short unsigned HasLevel::numberOfHangingClusters = 0; 00046 00047 00048 DECLARE_EXPORT void HasLevel::computeLevels() 00049 { 00050 computationBusy = true; 00051 // Get exclusive access to this function in a multi-threaded environment. 00052 static Mutex levelcomputationbusy; 00053 ScopeMutexLock l(levelcomputationbusy); 00054 00055 // Another thread may already have computed the levels while this thread was 00056 // waiting for the lock. In that case the while loop will be skipped. 00057 while (recomputeLevels) 00058 { 00059 // Reset the recomputation flag. Note that during the computation the flag 00060 // could be switched on again by some model change in a different thread. 00061 // In that case, the while loop will be rerun. 00062 recomputeLevels = false; 00063 00064 // Reset current levels on buffers, resources and operations 00065 for (Buffer::iterator gbuf = Buffer::begin(); 00066 gbuf != Buffer::end(); ++gbuf) 00067 { 00068 gbuf->cluster = 0; 00069 gbuf->lvl = -1; 00070 } 00071 for (Resource::iterator gres = Resource::begin(); 00072 gres != Resource::end(); ++gres) 00073 { 00074 gres->cluster = 0; 00075 gres->lvl = -1; 00076 } 00077 for (Operation::iterator gop = Operation::begin(); 00078 gop != Operation::end(); ++gop) 00079 { 00080 gop->cluster = 0; 00081 gop->lvl = -1; 00082 } 00083 00084 // Loop through all operations 00085 stack< pair<Operation*,int> > stack; 00086 Operation* cur_oper; 00087 int cur_level; 00088 Buffer *cur_buf; 00089 const Flow* cur_Flow; 00090 bool search_level; 00091 int cur_cluster; 00092 numberOfClusters = 0; 00093 numberOfHangingClusters = 0; 00094 for (Operation::iterator g = Operation::begin(); 00095 g != Operation::end(); ++g) 00096 { 00097 00098 #ifdef CLUSTERDEBUG 00099 logger << "Investigating operation '" << &*g 00100 << "' - current cluster " << g->cluster << endl; 00101 #endif 00102 00103 // Select a new cluster number 00104 if (g->cluster) 00105 cur_cluster = g->cluster; 00106 else 00107 { 00108 cur_cluster = ++numberOfClusters; 00109 if (numberOfClusters >= USHRT_MAX) 00110 throw LogicException("Too many clusters"); 00111 00112 // Detect hanging operations 00113 if (g->getFlows().empty() && g->getLoads().empty() 00114 && g->getSuperOperations().empty() 00115 && g->getSubOperations().empty() 00116 ) 00117 { 00118 ++numberOfHangingClusters; 00119 g->lvl = 0; 00120 continue; 00121 } 00122 } 00123 00124 // Do we need to activate the level search? 00125 // Criterion are: 00126 // - Not used in a super operation 00127 // - Have at no producing Flow on the Operation itself 00128 // or on any of its sub operations 00129 search_level = false; 00130 if (g->getSuperOperations().empty()) 00131 { 00132 search_level = true; 00133 // Does the operation itself have producing flows? 00134 for (Operation::flowlist::const_iterator fl = g->getFlows().begin(); 00135 fl != g->getFlows().end() && search_level; ++fl) 00136 if (fl->isProducer()) search_level = false; 00137 if (search_level) 00138 { 00139 // Do suboperations have a producing flow? 00140 for (Operation::Operationlist::const_reverse_iterator 00141 i = g->getSubOperations().rbegin(); 00142 i != g->getSubOperations().rend() && search_level; 00143 ++i) 00144 for (Operation::flowlist::const_iterator 00145 fl = (*i)->getFlows().begin(); 00146 fl != (*i)->getFlows().end() && search_level; 00147 ++fl) 00148 if (fl->isProducer()) search_level = false; 00149 } 00150 } 00151 00152 // If both the level and the cluster are de-activated, then we can move on 00153 if (!search_level && g->cluster) continue; 00154 00155 // Start recursing 00156 // Note that as soon as push an operation on the stack we set its 00157 // cluster and/or level. This is avoid that operations are needlessly 00158 // pushed a second time on the stack. 00159 stack.push(make_pair(&*g, search_level ? 0 : -1)); 00160 g->cluster = cur_cluster; 00161 if (search_level) g->lvl = 0; 00162 while (!stack.empty()) 00163 { 00164 // Take the top of the stack 00165 cur_oper = stack.top().first; 00166 cur_level = stack.top().second; 00167 stack.pop(); 00168 00169 #ifdef CLUSTERDEBUG 00170 logger << " Recursing in Operation '" << *(cur_oper) 00171 << "' - current level " << cur_level << endl; 00172 #endif 00173 00174 // Push sub operations on the stack 00175 for (Operation::Operationlist::const_reverse_iterator 00176 i = cur_oper->getSubOperations().rbegin(); 00177 i != cur_oper->getSubOperations().rend(); 00178 ++i) 00179 { 00180 if ((*i)->lvl < cur_level) 00181 { 00182 // Search level and cluster 00183 stack.push(make_pair(*i,cur_level)); 00184 (*i)->lvl = cur_level; 00185 (*i)->cluster = cur_cluster; 00186 } 00187 else if (!(*i)->cluster) 00188 { 00189 // Search for clusters information only 00190 stack.push(make_pair(*i,-1)); 00191 (*i)->cluster = cur_cluster; 00192 } 00193 // else: no search required 00194 } 00195 00196 // Push super operations on the stack 00197 for (Operation::Operationlist::const_reverse_iterator 00198 j = cur_oper->getSuperOperations().rbegin(); 00199 j != cur_oper->getSuperOperations().rend(); 00200 ++j) 00201 { 00202 if ((*j)->lvl < cur_level) 00203 { 00204 // Search level and cluster 00205 stack.push(make_pair(*j,cur_level)); 00206 (*j)->lvl = cur_level; 00207 (*j)->cluster = cur_cluster; 00208 } 00209 else if (!(*j)->cluster) 00210 { 00211 // Search for clusters information only 00212 stack.push(make_pair(*j,-1)); 00213 (*j)->cluster = cur_cluster; 00214 } 00215 // else: no search required 00216 } 00217 00218 // Update level of resources linked to current operation 00219 for (Operation::loadlist::const_iterator gres = 00220 cur_oper->getLoads().begin(); 00221 gres != cur_oper->getLoads().end(); ++gres) 00222 { 00223 Resource *resptr = gres->getResource(); 00224 // Update the level of the resource 00225 if (resptr->lvl < cur_level) resptr->lvl = cur_level; 00226 // Update the cluster of the resource and operations using it 00227 if (!resptr->cluster) 00228 { 00229 resptr->cluster = cur_cluster; 00230 // Find more operations connected to this cluster by the Resource 00231 for (Resource::loadlist::const_iterator resops = 00232 resptr->getLoads().begin(); 00233 resops != resptr->getLoads().end(); ++resops) 00234 if (!resops->getOperation()->cluster) 00235 { 00236 stack.push(make_pair(resops->getOperation(),-1)); 00237 resops->getOperation()->cluster = cur_cluster; 00238 } 00239 } 00240 } 00241 00242 // Now loop through all flows of the operation 00243 for (Operation::flowlist::const_iterator 00244 gflow = cur_oper->getFlows().begin(); 00245 gflow != cur_oper->getFlows().end(); 00246 ++gflow) 00247 { 00248 cur_Flow = &*gflow; 00249 cur_buf = cur_Flow->getBuffer(); 00250 00251 // Check whether the level search needs to continue 00252 search_level = cur_level!=-1 && cur_buf->lvl<cur_level+1; 00253 00254 // Check if the Buffer needs processing 00255 if (search_level || !cur_buf->cluster) 00256 { 00257 // Update the cluster of the current buffer 00258 cur_buf->cluster = cur_cluster; 00259 00260 // Loop through all flows of the buffer 00261 for (Buffer::flowlist::const_iterator 00262 buffl = cur_buf->getFlows().begin(); 00263 buffl != cur_buf->getFlows().end(); 00264 ++buffl) 00265 { 00266 // Check level recursion 00267 if (cur_Flow->isConsumer() && search_level) 00268 { 00269 if (buffl->getOperation()->lvl < cur_level+1 00270 && &*buffl != cur_Flow && buffl->isProducer()) 00271 { 00272 stack.push(make_pair(buffl->getOperation(),cur_level+1)); 00273 buffl->getOperation()->lvl = cur_level+1; 00274 buffl->getOperation()->cluster = cur_cluster; 00275 } 00276 else if (!buffl->getOperation()->cluster) 00277 { 00278 stack.push(make_pair(buffl->getOperation(),-1)); 00279 buffl->getOperation()->cluster = cur_cluster; 00280 } 00281 cur_buf->lvl = cur_level+1; 00282 } 00283 // Check cluster recursion 00284 else if (!buffl->getOperation()->cluster) 00285 { 00286 stack.push(make_pair(buffl->getOperation(),-1)); 00287 buffl->getOperation()->cluster = cur_cluster; 00288 } 00289 } 00290 } // End of needs-procssing if statement 00291 } // End of flow loop 00292 00293 } // End while stack not empty 00294 00295 } // End of Operation loop 00296 00297 // The above loop will visit ALL operations and recurse through the 00298 // buffers and resources connected to them. 00299 // Missing from the loop are buffers and resources that have no flows or 00300 // loads at all. We catch those poor lonely fellows now... 00301 for (Buffer::iterator gbuf2 = Buffer::begin(); 00302 gbuf2 != Buffer::end(); ++gbuf2) 00303 if (gbuf2->getFlows().empty()) 00304 { 00305 gbuf2->cluster = ++numberOfClusters; 00306 if (numberOfClusters >= USHRT_MAX) 00307 throw LogicException("Too many clusters"); 00308 ++numberOfHangingClusters; 00309 } 00310 for (Resource::iterator gres2 = Resource::begin(); 00311 gres2 != Resource::end(); ++gres2) 00312 if (gres2->getLoads().empty()) 00313 { 00314 gres2->cluster = ++numberOfClusters; 00315 if (numberOfClusters >= USHRT_MAX) 00316 throw LogicException("Too many clusters"); 00317 ++numberOfHangingClusters; 00318 } 00319 00320 } // End of while recomputeLevels. The loop will be repeated as long as model 00321 // changes are done during the recomputation. 00322 00323 // Unlock the exclusive access to this function 00324 computationBusy = false; 00325 } 00326 00327 } // End Namespace
Documentation generated by
