User Manual, Developers Guide and API Documentation

MarkovDiscreteTime.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 
00029 #include <WNS/markovchain/MarkovBase.hpp>
00030 #include <WNS/events/CanTimeout.hpp>
00031 #include <WNS/logger/Logger.hpp>
00032 #include <WNS/module/Base.hpp>
00033 
00034 #include <WNS/distribution/Uniform.hpp>
00035 
00036 #include <boost/numeric/ublas/lu.hpp>
00037 
00038 #ifndef WNS_MARKOVCHAIN_MARKOVDISCRETETIME_HPP
00039 #define WNS_MARKOVCHAIN_MARKOVDISCRETETIME_HPP
00040 
00041 
00042 namespace wns { namespace markovchain {
00043 
00049     template<class T>
00050     class MarkovDiscreteTime :
00051         public wns::events::CanTimeout,
00052         public MarkovBase<T>
00053     {
00054     public:
00059         MarkovDiscreteTime(int _numberOfChains):
00060             wns::events::CanTimeout(),
00061             MarkovBase<T>(_numberOfChains),
00062             slotTime(1.0),
00063             startTime(0.0),
00064             stopTime(0.0)
00065         {
00066             MESSAGE_SINGLE(VERBOSE,MarkovBase<T>::logger, "MarkovDiscreteTime() called");
00067         } // constructor
00068 
00072         MarkovDiscreteTime(int _numberOfStates,
00073                    int _numberOfChains,
00074                    std::vector<T> states,
00075                    TransitionMatrixType matrix,
00076                    std::vector<int> startStates,
00077                    simTimeType startTime,
00078                    simTimeType slotTime,
00079                    simTimeType stopTime):
00080             wns::events::CanTimeout(),
00081             MarkovBase<T>(_numberOfStates, _numberOfChains, states, matrix, startStates),
00082             slotTime(slotTime),
00083             startTime(startTime),
00084             stopTime(stopTime)
00085         {
00086         } // constructor
00087 
00091             ~MarkovDiscreteTime()
00092         {
00093         }
00094 
00098         void
00099         setSlotTime(simTimeType _slotTime)
00100         {
00101             slotTime = _slotTime;
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             wns::distribution::StandardUniform* randomDist;
00143 
00144             // generate a random value
00145             randomDist = new wns::distribution::StandardUniform();
00146             double random = (*randomDist)();
00147 
00148             nextState = currentState;
00149             double probSum = 0.0;
00150             for (int st = 0; st < MarkovBase<T>::numberOfStates; st++){
00151                 double prob = MarkovBase<T>::transitionsMatrix(currentState, st);
00152                 probSum += prob;
00153                 if (random <= probSum) {
00154                     nextState = st;
00155                     break;
00156                 }
00157             } // forall (possible next) states
00158             if (currentState != nextState) {
00159                 MESSAGE_BEGIN(NORMAL, MarkovBase<T>::logger, m, "NextState(chain=" << chainNumber << "): ");
00160                 m << "scheduled transition " << currentState << " -> " << nextState << " after " << slotTime << "s";
00161                 MESSAGE_END();
00162                 MarkovBase<T>::nextStates[chainNumber] = nextState;
00163             }
00164 
00165             delete randomDist;
00166             return slotTime;
00167         } // calculateNextState
00168 
00172         bool
00173         checkSum()
00174         {
00175             for (int i = 0;i < MarkovBase<T>::numberOfStates; i++) {
00176                 double checkSum = 0.0;
00177                 for (int j = 0; j < MarkovBase<T>::numberOfStates; j++)
00178                     checkSum += MarkovBase<T>::transitionsMatrix(i, j);
00179                 assure(fabs(checkSum - 1.0) < 1e-3, "wrong matrix row sum");
00180                 if (fabs(checkSum - 1.0) >= 1e-3) {
00181                     MESSAGE_SINGLE(NORMAL,MarkovBase<T>::logger, "wrong matrix row sum");
00182                     return false;
00183                 }
00184             } // for i
00185             return true;
00186         } // checkSum()
00187 
00188 
00193         void
00194         startEvents()
00195         {
00196             checkSum();
00197             MESSAGE_SINGLE(NORMAL,MarkovBase<T>::logger,
00198                        "startEvents(): startTime=" << startTime <<
00199                        ", stopTime=" << stopTime );
00200 
00201             wns::distribution::StandardUniform* randomDist = 
00202                 new wns::distribution::StandardUniform();
00203 
00204             for (int chainNumber = 0; chainNumber<MarkovBase<T>::numberOfChains; chainNumber++) {
00205                 int startState = MarkovBase<T>::startStates[chainNumber];
00206                 assure((startState >= -1) && (startState < MarkovBase<T>::numberOfStates), "wrong start state");
00207                 if (startState < 0) { // random (not simple!)
00208                     startState = 0;
00209                     calculateStateProbabilities(); // only calculated once even if called up to C times here
00210                     double random = (*randomDist)();
00211                     double probSum = 0.0;
00212                     MESSAGE_SINGLE(NORMAL,MarkovBase<T>::logger, "determining random start state (r="<<random<<")");
00213                     int nos = MarkovBase<T>::numberOfStates;
00214                     for(int i=0; i<nos; i++) {
00215                         double p=MarkovBase<T>::stateProbabilities[i];
00216                         probSum += p;
00217                         if (random <= probSum) {
00218                             startState = i; break;
00219                         }
00220                     }
00221                 }
00222                 MarkovBase<T>::actualStates[chainNumber] = startState;
00223                 MarkovBase<T>::nextStates[chainNumber]   = startState;
00224                 MESSAGE_BEGIN(NORMAL, MarkovBase<T>::logger, m, "startEvents(chain=" << chainNumber<<"):");
00225                 m << " startState=" << startState;
00226                 MESSAGE_END();
00227 
00228                 calculateNextState(chainNumber);
00229 
00230                 // this notifies the method of the derived class:
00231                 stateChangeNotification(chainNumber);
00232             } // forall chains
00233             setTimeout(startTime + slotTime); // set the timer to a relative time
00234             /* startTime>0 can be a problem if the current time is already >0 */
00235             delete randomDist;
00236         } // startEvents()
00237 
00241         virtual void
00242         stateChangeNotification(const int &chainNumber)
00243         {
00244 #ifndef WNS_NO_LOGGING
00245             int newState =
00246 #endif
00247                 MarkovBase<T>::actualStates[chainNumber];
00248             MESSAGE_SINGLE(NORMAL, MarkovBase<T>::logger, "MarkovContinuousTime::stateChange(" << chainNumber << ") to state " << newState);
00249         } // stateChangeNotification()
00250 
00254         virtual void
00255         stopMarkovProcess()
00256         {
00257             MESSAGE_SINGLE(NORMAL,MarkovBase<T>::logger, "MarkovProcess stopped.");
00258             if (hasTimeoutSet()) cancelTimeout();
00259             // remove state transition events (from CanTimeout.hpp)
00260         } // stopMarkovProcess()
00261 
00262     private:
00263 
00264         friend class MarkovDiscreteTimeTest;
00265 
00266     protected:
00267 
00278         virtual void
00279         calculateStateProbabilities()
00280         {
00281             if (MarkovBase<T>::stateProbabilities[0]>=0.0) { return; }
00282             // ^ already calculated
00283 
00284             int nos = MarkovBase<T>::numberOfStates;
00285             MESSAGE_BEGIN(VERBOSE, MarkovBase<T>::logger, m, "transitionMatrix=\n");
00286             m << MarkovBase<T>::transitionsMatrix;
00287             MESSAGE_END();
00288 
00289             TransitionMatrixType Ptrans = boost::numeric::ublas::trans(MarkovBase<T>::transitionsMatrix);
00290 
00291             MESSAGE_BEGIN(VERBOSE, MarkovBase<T>::logger, m, "System matrix P^T=\n");
00292             m << Ptrans << "\n";
00293             MESSAGE_END();
00294 
00295             TransitionMatrixType ident = boost::numeric::ublas::identity_matrix<double>(nos, nos);
00296             TransitionMatrixType PtransMinus = TransitionMatrixType(Ptrans - ident);
00297 
00298             MESSAGE_BEGIN(VERBOSE, MarkovBase<T>::logger, m, "Matrix (P^T - I)=\n");
00299             m << PtransMinus << "\n";
00300             MESSAGE_END();
00301 
00302             // The "Replace an Equation" Approach (see W.J. Stewart Numeric Solution of Markov Chains 2.3.1.2)
00303 
00304             boost::numeric::ublas::permutation_matrix<std::size_t> pm(PtransMinus.size1());
00305             boost::numeric::ublas::vector<double> x(nos);
00306 
00307             x = boost::numeric::ublas::zero_vector<double>(nos);
00308             x(nos - 1) = 1.0;
00309 
00310             // Fill the last row of PtransMinus with 1.0 => PtransMinus1
00311             for(int col = 0; col < nos; col++)
00312                 PtransMinus(nos - 1, col) = 1.0;
00313 
00314             // Solve Qtrans1*result = x
00315             boost::numeric::ublas::lu_factorize(PtransMinus, pm);
00316             boost::numeric::ublas::lu_substitute(PtransMinus, pm, x);
00317             // Result is in x
00318 
00319             for(int i = 0; i < nos; i++)
00320                 MarkovBase<T>::stateProbabilities[i] = x(i);
00321 
00322             MESSAGE_BEGIN(NORMAL, MarkovBase<T>::logger, m, "state probabilities: ");
00323             for(int i=0; i<nos; i++) {
00324                 double p = MarkovBase<T>::stateProbabilities[i];
00325                 m << p << " ";
00326             }
00327             MESSAGE_END();
00328         }
00329 
00333         simTimeType slotTime;
00334 
00338         simTimeType startTime;
00339 
00343         simTimeType stopTime;
00344 
00348         virtual void
00349         onTimeout ()
00350         {
00351             for (int chainNumber = 0; chainNumber < MarkovBase<T>::numberOfChains; chainNumber++){
00352                 if (MarkovBase<T>::actualStates[chainNumber] != MarkovBase<T>::nextStates[chainNumber]){
00353                     MESSAGE_BEGIN(NORMAL, MarkovBase<T>::logger, m, "onTimeout(chain "<<chainNumber<<"): ");
00354                     m << "state change " << MarkovBase<T>::actualStates[chainNumber]
00355                       << " -> "         << MarkovBase<T>::nextStates[chainNumber];
00356                     MESSAGE_END();
00357 
00358                     MarkovBase<T>::actualStates[chainNumber] = MarkovBase<T>::nextStates[chainNumber];
00359                     stateChangeNotification(chainNumber);
00360                 } else { // no state change
00361                     MESSAGE_SINGLE(VERBOSE,MarkovBase<T>::logger,  "onTimeout(chain "<<chainNumber<<"): stays in the state "<<MarkovBase<T>::nextStates[chainNumber]<< " ");
00362                 }
00363                 calculateNextState(chainNumber);
00364             } // forall chains
00365 
00366             if ((stopTime == 0.0) || (wns::simulator::getEventScheduler()->getTime()+slotTime<stopTime)) {
00367                 setTimeout(slotTime); // relative
00368             } // else: this was last event. Stop now
00369         }
00370     };// MarkovDiscreteTime
00371 
00372 } }
00373 #endif // WNS_MARKOVCHAIN_MARKOVDISCRETETIME_HPP
00374 
00375 

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