User Manual, Developers Guide and API Documentation

MarkovContinuousTime.hpp

Go to the documentation of this file.
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 

Generated on Fri May 25 03:31:48 2012 for openWNS by  doxygen 1.5.5