![]() |
User Manual, Developers Guide and API Documentation |
![]() |
00001 /******************************************************************************* 00002 * This file is part of openWNS (open Wireless Network Simulator) 00003 * _____________________________________________________________________________ 00004 * 00005 * Copyright (C) 2004-2007 00006 * Chair of Communication Networks (ComNets) 00007 * Kopernikusstr. 5, D-52074 Aachen, Germany 00008 * phone: ++49-241-80-27910, 00009 * fax: ++49-241-80-22242 00010 * email: info@openwns.org 00011 * www: http://www.openwns.org 00012 * _____________________________________________________________________________ 00013 * 00014 * openWNS is free software; you can redistribute it and/or modify it under the 00015 * terms of the GNU Lesser General Public License version 2 as published by the 00016 * Free Software Foundation; 00017 * 00018 * openWNS is distributed in the hope that it will be useful, but WITHOUT ANY 00019 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 00020 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 00021 * details. 00022 * 00023 * You should have received a copy of the GNU Lesser General Public License 00024 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00025 * 00026 ******************************************************************************/ 00027 00028 #include <WNS/markovchain/MarkovBase.hpp> 00029 #include <WNS/events/MultipleTimeout.hpp> 00030 #include <WNS/logger/Logger.hpp> 00031 00032 #include <WNS/distribution/ForwardRecurrenceTime.hpp> 00033 #include <WNS/distribution/Distribution.hpp> 00034 #include <WNS/pyconfig/View.hpp> 00035 #include <WNS/pyconfig/Parser.hpp> 00036 00037 #include <WNS/distribution/Uniform.hpp> 00038 #include <WNS/container/Matrix.hpp> 00039 00040 #include <boost/numeric/ublas/lu.hpp> 00041 00042 #ifndef WNS_MARKOVCHAIN_MARKOVCONTINUOUSTIME_HPP 00043 #define WNS_MARKOVCHAIN_MARKOVCONTINUOUSTIME_HPP 00044 00045 00046 namespace wns { namespace markovchain { 00047 00053 template<class T> 00054 class MarkovContinuousTime : 00055 public wns::events::MultipleTimeout<int>, // int for the chain number 00056 public MarkovBase<T> 00057 { 00058 public: 00063 MarkovContinuousTime(int _numberOfChains) : 00064 wns::events::MultipleTimeout<int>(), 00065 MarkovBase<T>(_numberOfChains), 00066 transitionScale(1.0), 00067 startTime(0.0), 00068 stopTime(0.0), // infinite 00069 transDistSpec("NegExp(X)") 00070 { 00071 MESSAGE_SINGLE(VERBOSE, MarkovBase<T>::logger, "MarkovContinuousTime(C=" << _numberOfChains << ") called"); 00072 } 00073 00078 MarkovContinuousTime(int _numberOfStates, 00079 int _numberOfChains, 00080 std::vector<T> states, 00081 TransitionMatrixType matrix, 00082 std::vector<int> startStates, 00083 simTimeType startTime, 00084 simTimeType stopTime) : 00085 wns::events::MultipleTimeout<int>(), 00086 MarkovBase<T>(_numberOfStates, _numberOfChains, states, matrix, startStates), 00087 transitionScale(1.0), 00088 startTime(startTime), 00089 stopTime(stopTime), 00090 transDistSpec("NegExp(X)") 00091 { 00092 transitionScale = 1.0; 00093 MESSAGE_SINGLE(VERBOSE, MarkovBase<T>::logger, "MarkovContinuousTime(C=" << _numberOfChains << ",...) called"); 00094 } 00095 00099 ~MarkovContinuousTime() 00100 { 00101 MESSAGE_SINGLE(VERBOSE,MarkovBase<T>::logger, "~MarkovContinuousTime() called"); 00102 } 00103 00107 void 00108 setStartTime(simTimeType _startTime) 00109 { 00110 startTime = _startTime; 00111 } 00112 00116 void 00117 setStopTime(simTimeType _stopTime) 00118 { 00119 stopTime = _stopTime; 00120 } 00121 00125 std::string 00126 stringify(double x) const 00127 { 00128 std::ostringstream o; 00129 o << x; 00130 return o.str(); 00131 } 00132 00137 double 00138 calculateNextState(int chainNumber) 00139 { 00140 int currentState = MarkovBase<T>::actualStates[chainNumber]; 00141 int nextState; 00142 double absTransTime; 00143 double rTime, dTime; 00144 00145 //MESSAGE_SINGLE(NORMAL, MarkovBase<T>::logger, "calculateNextState(chainNumber=" << chainNumber << "):"); 00146 dTime = 1.0e+100; // for finding the minimum 00147 nextState = currentState; 00148 for (int st = 0; st < MarkovBase<T>::numberOfStates; st++){ 00149 if (st != currentState) { 00150 if (matrixDistribution[currentState][st]) { 00151 rTime = (*matrixDistribution[currentState][st])(); // random value 00152 if (rTime < dTime) { 00153 dTime = rTime; 00154 nextState = st; 00155 } 00156 } 00157 } 00158 } 00159 dTime /= transitionScale; 00160 00161 MESSAGE_BEGIN(NORMAL, MarkovBase<T>::logger, m, "NextState(chain=" << chainNumber << "): "); 00162 m << "scheduled transition " << currentState << " -> " << nextState << " after " << dTime << "s"; 00163 MESSAGE_END(); 00164 00165 simTimeType now = wns::simulator::getEventScheduler()->getTime(); // for absolute time 00166 absTransTime = now + dTime; 00167 MarkovBase<T>::nextTransitionTime[chainNumber] = absTransTime; // only for information 00168 00169 if ((stopTime == 0.0) || (absTransTime < stopTime)) { 00170 MarkovBase<T>::nextStates[chainNumber] = nextState; 00171 } else { 00172 MarkovBase<T>::nextStates[chainNumber] = -1; // end the Markov process 00173 dTime = stopTime - now; // trans time set to end time 00174 } 00175 //MESSAGE_SINGLE(NORMAL, log, "stateChangeNotification("<<chainNumber<<") to state "<<currentState); 00176 // this notifies the method of the derived class: 00177 stateChangeNotification(chainNumber); 00178 return dTime; // relative to now 00179 } // NextState 00180 00181 00193 void 00194 setTransitionDistributionSpec(std::string distSpec) 00195 { 00196 assure(MarkovBase<T>::numberOfStates > 1, "Transition Distribution cannot be set at this stage"); 00197 transDistSpec = distSpec; 00198 assure(distSpec.find("X",0),"distSpec must contain at least one X"); 00199 // a call to prepareMatrixOfDistributions() must come after this 00200 } 00201 00206 void 00207 prepareMatrixOfDistributions() 00208 { 00209 double lambda; 00210 MESSAGE_SINGLE(VERBOSE,MarkovBase<T>::logger, "prepareMatrixOfDistributions(): transDistSpec=" << transDistSpec); 00211 assure(MarkovBase<T>::numberOfStates > 0, "numberOfStates not set"); 00212 const MatrixDistType::SizeType sizes[2] = {MarkovBase<T>::numberOfStates, MarkovBase<T>::numberOfStates}; 00213 matrixDistribution = MatrixDistType(sizes); 00214 for (int i = 0; i < MarkovBase<T>::numberOfStates; i++) { // row 00215 double lambdaRowSum = 0.0; // row sum 00216 for (int j = 0; j < MarkovBase<T>::numberOfStates; j++) { // column 00217 if (i == j){ // value on diagonal of matrix 00218 matrixDistribution[i][j] = NULL; 00219 } else { 00220 lambda = MarkovBase<T>::transitionsMatrix(i, j); 00221 if (lambda != 0.0) { 00222 lambdaRowSum += lambda; 00223 wns::pyconfig::Parser config; 00224 config.loadString( 00225 "import openwns.distribution\n" 00226 "X = " + stringify(1.0/lambda) + "\n" 00227 "outcome = openwns.distribution." + transDistSpec + "\n" 00228 ); 00229 wns::pyconfig::View distConfig(config, "outcome"); 00230 std::string distributionName = distConfig.get<std::string>("__plugin__"); 00231 wns::distribution::Distribution* distribution = 00232 wns::distribution::DistributionFactory::creator(distributionName)->create(distConfig); 00233 matrixDistribution[i][j] = distribution; 00234 // Opnet: LoadDistribution(dist_code, lambda, pdf_args); 00235 MESSAGE_BEGIN(VERBOSE, MarkovBase<T>::logger, m, "prepare(): "); 00236 m << "lambda[" << i << "][" << j <<"] = "<< lambda; 00237 m << ", dist=" << *distribution; 00238 MESSAGE_END(); 00239 } else { 00240 matrixDistribution[i][j] = NULL; 00241 } 00242 } // off-diagonal 00243 } // for j 00244 MarkovBase<T>::transitionsMatrix(i, i) = - lambdaRowSum; // diagonal 00245 } // for i 00246 } //prepareMatrixOfDistributions 00247 00248 00254 void 00255 startEvents() 00256 { 00257 prepareMatrixOfDistributions(); 00258 00259 MESSAGE_SINGLE(NORMAL,MarkovBase<T>::logger, "startEvents(): startTime=" << startTime <<", stopTime=" << stopTime ); 00260 00261 wns::distribution::StandardUniform* randomDist = 00262 new wns::distribution::StandardUniform(); 00263 00264 for (int chainNumber = 0; chainNumber<MarkovBase<T>::numberOfChains; chainNumber++){ 00265 int startState = MarkovBase<T>::startStates[chainNumber]; 00266 assure((startState >= -1) && (startState < MarkovBase<T>::numberOfStates), "wrong start state"); 00267 if (startState < 0) { // random (not simple!) 00268 startState = 0; 00269 calculateStateProbabilities(); // only calculated once even if called up to C times here 00270 int nos = MarkovBase<T>::numberOfStates; 00271 double random = (*randomDist)(); 00272 double probSum = 0.0; 00273 MESSAGE_SINGLE(NORMAL,MarkovBase<T>::logger, "determining random start state (r="<<random<<")"); 00274 for(int i=0; i<nos; i++) { 00275 double p=MarkovBase<T>::stateProbabilities[i]; 00276 probSum += p; 00277 if (random <= probSum) { 00278 startState = i; break; 00279 } 00280 } 00281 } 00282 MarkovBase<T>::actualStates[chainNumber] = startState; 00283 MarkovBase<T>::nextStates[chainNumber] = startState; 00284 MarkovBase<T>::nextTransitionTime[chainNumber] = 0.0; 00285 MESSAGE_BEGIN(NORMAL, MarkovBase<T>::logger, m, "startEvents(chain=" << chainNumber<<"):"); 00286 m << " startState=" << startState; 00287 MESSAGE_END(); 00288 double myNextEventTimeOffset = calculateNextState(chainNumber); 00289 double myFirstEventTimeOffset = wns::distribution::forwardRecurrenceTime(myNextEventTimeOffset); 00290 MESSAGE_SINGLE(VERBOSE,MarkovBase<T>::logger, "myFirstEventTimeOffset = "<< myFirstEventTimeOffset); 00291 setTimeout(chainNumber,startTime + myFirstEventTimeOffset); // set the timer to a relative time 00292 /* startTime>0 can be a problem if the current time is already >0 */ 00293 } // for 00294 delete randomDist; 00295 } 00296 00300 virtual void 00301 stateChangeNotification(const int &chainNumber) 00302 { 00303 #ifndef WNS_NO_LOGGING 00304 int newState = 00305 #endif 00306 MarkovBase<T>::actualStates[chainNumber]; 00307 MESSAGE_SINGLE(NORMAL, MarkovBase<T>::logger, "MarkovContinuousTime::stateChange(" << chainNumber << ") to state " << newState); 00308 } 00309 00323 virtual void 00324 calculateStateProbabilities() 00325 { 00326 if (MarkovBase<T>::stateProbabilities[0]>=0.0) { return; } 00327 // ^ already calculated 00328 00329 int nos = MarkovBase<T>::numberOfStates; 00330 for(int row=0; row<nos; row++) { 00331 double lambdaRowSum=0.0; 00332 for(int col=0; col<nos; col++) 00333 if (col != row) 00334 lambdaRowSum += MarkovBase<T>::transitionsMatrix(row, col); 00335 MarkovBase<T>::transitionsMatrix(row, row) = - lambdaRowSum; // diagonal 00336 } 00337 MESSAGE_BEGIN(VERBOSE, MarkovBase<T>::logger, m, "transitionMatrix=\n"); 00338 m << MarkovBase<T>::transitionsMatrix; 00339 MESSAGE_END(); 00340 00341 TransitionMatrixType Qtrans = boost::numeric::ublas::trans(MarkovBase<T>::transitionsMatrix); 00342 00343 MESSAGE_BEGIN(VERBOSE, MarkovBase<T>::logger, m, "System matrix Q^T=\n"); 00344 m << Qtrans << "\n"; 00345 MESSAGE_END(); 00346 00347 // The "Replace an Equation" Approach (see W.J. Stewart Numeric Solution of Markov Chains 2.3.1.2) 00348 00349 boost::numeric::ublas::permutation_matrix<std::size_t> pm(Qtrans.size1()); 00350 boost::numeric::ublas::vector<double> x(nos); 00351 00352 x = boost::numeric::ublas::zero_vector<double>(nos); 00353 x(nos - 1) = 1.0; 00354 00355 // Fill the last row of Qtrans with 1.0 => Qtrans1 00356 for(int col = 0; col < nos; col++) 00357 Qtrans(nos - 1, col) = 1.0; 00358 00359 // Solve Qtrans1*result = x 00360 boost::numeric::ublas::lu_factorize(Qtrans, pm); 00361 boost::numeric::ublas::lu_substitute(Qtrans, pm, x); 00362 // Result is in x 00363 00364 for(int i = 0; i < nos; i++) 00365 MarkovBase<T>::stateProbabilities[i] = x(i); 00366 00367 MESSAGE_BEGIN(NORMAL, MarkovBase<T>::logger, m, "state probabilities: "); 00368 for(int i=0; i<nos; i++) { 00369 double p=MarkovBase<T>::stateProbabilities[i]; 00370 m << p << " "; 00371 } 00372 MESSAGE_END(); 00373 } 00374 00375 protected: 00376 00380 typedef wns::container::Matrix<wns::distribution::Distribution*, 2> MatrixDistType; 00381 00385 MatrixDistType matrixDistribution; 00386 00391 double transitionScale; 00392 00396 simTimeType startTime; // all chains start at this time 00397 00401 simTimeType stopTime; // all chains stop at this time 00402 00406 std::string transDistSpec; // typically "NegExp(X)" 00407 00411 virtual void 00412 onTimeout (const int &chainNumber) 00413 { 00414 double myNextEventTimeOffset; 00415 if (MarkovBase<T>::nextStates[chainNumber] < 0) { 00416 MESSAGE_SINGLE(NORMAL,MarkovBase<T>::logger, "onTimeout(chain "<<chainNumber<<"): Markov process ends."); 00417 } else { 00418 MESSAGE_BEGIN(NORMAL, MarkovBase<T>::logger, m, "onTimeout(chain="<<chainNumber<<"): "); 00419 m << "state change " << MarkovBase<T>::actualStates[chainNumber] 00420 << " -> " << MarkovBase<T>::nextStates[chainNumber]; 00421 MESSAGE_END(); 00422 00423 MarkovBase<T>::actualStates[chainNumber] = MarkovBase<T>::nextStates[chainNumber]; 00424 myNextEventTimeOffset = calculateNextState(chainNumber); 00425 setTimeout(chainNumber,myNextEventTimeOffset); 00426 00427 MESSAGE_BEGIN(VERBOSE, MarkovBase<T>::logger, m, "onTimeout(chain="<<chainNumber<<"): "); 00428 m << "Next state change will occur at t=" 00429 << wns::simulator::getEventScheduler()->getTime() + myNextEventTimeOffset; 00430 MESSAGE_END(); 00431 } 00432 } // onTimeout 00433 00437 virtual void 00438 stopMarkovProcess() 00439 { 00440 MESSAGE_SINGLE(NORMAL,MarkovBase<T>::logger, "MarkovProcess stopped."); 00441 cancelAllTimeouts(); // remove state transition events (from MultipleTimeout.hpp) 00442 } 00443 private: 00444 friend class MarkovContinuousTimeTest; 00445 00446 }; // MarkovContinuousTime 00447 00448 } } 00449 #endif // WNS_MARKOVCHAIN_MARKOVCONTINUOUSTIME_HPP 00450 00451
1.5.5