2 2
3 3
3 Framework Design
3.1 3.2 3.3 3.4 Java and Object Oriented Programming . . . . . . . . . . . . . . . . . . . . . . . . . Build Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Basic Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The Solvers Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
4 4 5 6
4 Examples
4.1 Example: An M/M/2/N with dierent servers . . . . . . . . . . . . . . . . . . . . . . 4.1.1 4.1.2 4.1.3 4.1.4 4.2 4.2.1 4.2.2 4.3 4.3.1 4.3.2 The model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Class QueueMM2dNState . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Class QueueMM2dN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Results
6
6 6 7 7 7 13 13 14 21 21 32
Drive Thru
33
34 35 35 35
6 Advanced Features
6.1 6.2 6.3 6.4 Using the Solvers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Using the Transitions scheme extending jMarkov . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Computing MOPs on the y to save memory
37
37 37 37 37
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
37 37
Introduction
The jMarkov project has been in development since 2002 by the research grup COPA at Universidad de los Andes. The main purpose of jMarkov is facilitating the development and application of large sacale Markovian models, so that they can be used by engineers with basic programming and stochastic skills. The project is composed by four modules
In this manual we explain jMarkov and jQBD, which are used to build Markov Chains and Quasi-Birth and death processes (QBD). The other two modules have their own manulas. With jPhase a user can easily manipulate Phase-Type distributions (PH). These distibutions are quite exible and powerful, and a model that is limited to PH in practical terms can model many situations. For details see [8] and [7] jMDP is used to build and solve Markov Decision Process (MDP).MDP, or, as is often called, Probabilistic Dynamic Programming allows the analyst to design optimal control rules for a Markov Chain.jMDP works for discrete and continous time MDPs.For details see [11] and [10] For up-to date information, downloads and examples check COPA's web page at
edu.co.
2 Building Large - Scale Markov Chains
copa.uniandes.
In this section, we will describe the basic algorithms used by jMarkov to build Markov Chains. Although we limit our description to Continuous Time Markov Chain (CTMC), jMarkov can handle also Discrete Time Markov Chains (DTMC). Let nents
{X (t), t 0}
Q,
with compo-
i, j S .
It is well known that this generator matrix, along with the initial conditions, completely determines the transient and stationary behavior of the Markov Chain (see, e.g, [4]). The diagonal components
qii
are non-positive and represent the exponential holding rate for state
i,
elements
qij
to state
j. P(t)
with components
i, j S .
P(t) = eQt
For an irreducible chain, the stationary distribution to the following system of equations
t > 0. = [1 , 2 , . . . , ]
is determined as the solution
Q = 0 1 = 1,
where
Q can be decomposed as Q = eE Q(e) , where Q(e) contains the transition rates associated with event e, and E is the set of all possible events that may occur. In large systems, it is not easy to
matrix know in advance how many states there are in the model. However, it is possible to determine what events occur in every state, and the destination states produced by each transition when it occurs. jMarkov works based on this observation, using an algorithm similar to the algorithm buildRS presented by Ciardo [1]; see Figure 1. The algorithm builds the space state and the transition rate by a deep exploration of the graph. It starts with an initial state i0 and searches for all other states. At every instant, it keeps a set of unchecked states not been previously found, they are added to the calling the function and the functions
checked. For every unchecked state the algorithm nds the possible destinations and, if they had
active
. From
that determines if an event can occur. If it does, then the possible destination states are found by
dests
rate
this algorithm, we can see that a system is fully described once the states and events are dened
S = , U = {i0 }, E given. while U = do for all e E do if active(i, e) then D := dests(i, e) for all j D do if j / S U then U := U {j }
end if
r be a column vector such that r(i) represents the expected rate at which the system rewards whenever it is in state i S . Here the term reward is used for any measure of
performance that might be of interest, not necessarily monetary. For example, in queueing systems
r(i)
might represent the number of entities in the system,or the number of busy servers, when the
state is
i.
is computed according to
ai = P {X (0) = i} , i S ).
Similarly, for an irreducible CTMC, the long run rate at which the system receives rewards is
1 t t lim
E r(X (s) ds = r.
0
3
Build Package
MarkovProcess SimpleMarkovProcess GeomProcess
Basics Package
JMarkovElement PropertiesElement Event PropertiesEvent State GeomState GeomRelState PropertiesState
Solvers Package
Solver SteadyStateSolver GeometrixtSolver TransientSolver JamaSolver JamaTransientSolver MtjSolver MtjLogRedSolver
As we will see, jMarkov provides mechanisms to dene this type of rewards and can compute both, transient and steady state MOPs. There are other type of rewards, like expected time in the system, which can be easily computed using Little law.
Framework Design
In this section, we give a brief description of jMarkov's framework architecture. We start by describing object-oriented programming and then describe the three packages that compose jMarkov.
We can program the algorithm in terms of these abstract objects and functions and the program works independently of the particular implementation of the aforementioned elements. All the user has to do is to implement the abstract functions. What is particularly nice is that if a function is declared as abstract, then the compiler itself will force the user to implement it before she attempts to run the model.
Process,
processes,
and
GeomProcess (see Figure 3). Whereas the rst two allow to model general Markov GeomProcess is used for Quasi-Birth and Death Processes (QBD) and its description is
MarkovProcess, SimpleMarkov-
given in Section 5.3 below. methods that implement the three aforementioned functions in the algorithm BuildRS:
SimpleMarkovProcess represents a Markov chain process, and contains three abstract active, dests, and rate. In order to model a problem the user has to extend this class and implement the three functions. An example is given in Section 5.4. The class MarkovProcess is the main class in
The class the module, and provides a more general mechanism to describe the dynamics of the system. It also contains tools to communicate with the solvers to compute steady state and transient solutions, and print them in a diverse array of ways. For details, see [9].
MarkovProcess
SimpleMarkovProcess
GeomProcess
State,
and
Event,
which allow the user to code a description of the states and events,
respectively (see Figure 4). The user has freedom to choose any particular coding that best describes the states in her model, like any combination of integers, strings, etc. However, she must establish a complete ordering among the elements since, for eciency, jMarkov works with ordered sets. For simplicity, however, a built-in class is provided, called there is an analogous class called and
PropertiesState,
with an array of integers, something which is quite appropriate for many applications. Similarly,
Events
PropertiesEvent.
States
classes, since all that is required from the user is to provide a mechanism to walk through the elements of the set, taking advantage of Java iterator mechanism. This implies that, for large sets, there is no need to generate (and store) all the elements in the set. For convenience, the package provides implementations of these set classes based on sorted sets classes available in Java.
<<Interface>> JMarkovElement
State
<<Interface>> PropertiesElement
Event
GeomState
GeomRelState
PropertiesState
PropertiesEvent
Solver,
SteadyStateSolver, TransientSolver,
and
GeomSolver
(see Figure 5). As the names indicate, the rst two provide solvers for steady state and transient probabilities, whereas the latter is used for QBDs, as explained in section 5. The implementations provided relay on two popular Java packages to handle matrix operations JAMA [3] and MTJ [2], for dense and sparse matrices, respectively.
Solver
TransientSolver
SteadyStateSolver
GeometrixtSolver
JamaTransientSolver
JamaSolver
MtjSolver
MtjLogRedSolver
Examples
and
that nds the system empty will go to server 1 with probability available server, or join a single FCFS queue. If there are
X(t) = (X (t), Y (t), Z (t)), where X (t) and Y (t) represents Z (t) represents the number in queue, which is a number from 0 to N 2. There are 2 2 N 2 potential states, however not all combinations of X, Y and Z are possible. For example the state (0, 1, 2) is not acceptable since we assume that
a server will not be idle if there are people in the queue. The set of states will be of the form
010
100
110
111
112
...
1,1,N-3
1,1,N-2
2 1 1
(1 ) 2 1 + 2 1 + 2
QueueMM2dN.
SimpleMarkovClass. In the following code you will see how we rst QueueMM2dNState and then model the system implementing the class
These two class are placed in the same le QueueMM2dN, but they could be placed
in separate les. To model the State we begin by creating a constructor that assigns x, y, and z to the properties. We provide methods to access the three properties and a method to check whether the system is empty. We also implement the method label to override the one in the class PropertiesState.
4.1.4 Code
File QueueMM2dN.java
package import import import import import import import import import import
// Lets
examples . jmarkov ;
jmarkov . MarkovProcess ; jmarkov . SimpleMarkovProcess ; jmarkov . b a s i c . Event ; jmarkov . b a s i c . E v e n t s S e t ; jmarkov . b a s i c . P r o p e r t i e s S t a t e ; jmarkov . b a s i c . S t a t e s ; jmarkov . b a s i c . S t a t e s S e t ;
start
defining
the
State
level .
class
/
MM2dNState
extends
PropertiesState
We i d e n t i f y e a c h S t a t e w i t h t h e t r i p l e t a r e t h e s t a t u s o f t h e s e r v e r s and z t h e . . , N 2 ) . /
(x , y , z ) , number in
where queue
and (0 ,1 ,
MM2dNState (
with
properties .
public void
@Override
computeMOPs ( M a r k o v P r o c e s s " Status " Status " Queue " Number Server Server Length " , in 1" , 2" ,
mp)
getStatus1 ( ) ) ; getStatus2 ( ) ) ;
System " ,
Returns @return /
the
status of
of the
the
first
Server
Status
first
Server
getStatus1 () prop [ 0 ] ;
Returns @return /
the
status of
of the
the
second
Server
Status
second
Server
getStatus2 () prop [ 1 ] ;
Returns @return /
the
size of
of
the
Status
the
size
getQSize ( ) prop [ 2 ] ;
boolean i s E m p t y ( ) { return ( g e t S t a t u s 1 ( )
}
@see /
j m a r k o v . b a s i c . S t a t e#i s C o n s i s t e n t ( )
public boolean
}
@Override
isConsistent ()
return true ;
/
// T O D O Complete
We ... /
implement , N
label
so
that
States
are
labeld
1,
1A ,
1B ,
2,
3,
public if if if
}
label ( )
= "0" ; " 1A" ;
String
(( getStatus1 () stg =
= =
1)
& &
( getStatus2 ()
= =
0))
= =
1)
& &
( getStatus1 ()
= =
0))
= = +
1)
& &
( getStatus1 ()
= =
1))
return
/
getQSize ( ) ) ;
stg ;
This /
method
gives
verbal
description
of
the
State .
public
@Override String stg description () = "" ; 1 is 2 are " is " + " + (( getStatus1 () + = = 1) ? 1) " busy " ? : "idle" ); : "idle" ); in queue . " ; {
Server There
(( getStatus2 () + "
= =
return
} }
getQSize ( )
customers
stg ;
class
/
QMM2dNEvent
extends
/
{
Event
public
/ /
Event
types Type
enum An
arrival
/
server 1 ( only for emtpy system )
ARRIVAL, Arrival to
/ /
/ /
DEPARTURE2 ; }
private
/
Type
type ;
@param /
type
type )
@return /
Returns
the
type .
getType ( )
public s t a t i c for
( Type
@return /
the
set
of
all
events .
new
getAllEvents ()
EventsSet< QMM2dNEvent> ( ) ;
return
} }
e v S e t . add ( evSet ;
new
Type . v a l u e s ( ) ) QMM2dNEvent ( t y p e ) ) ;
//
Now
we
define
main
the
class
This c l a s s r e p r e s e n t s i s a system with 2 d i f f e r e n t s e r v e r s w i t h r a t e s mu1 and mu2 , r e s p e c t i v e l y , and lambda . @ a u t h o r Germn R i a o . U n i v e r s i d a d d e l o s Andes . /
QueueMM2dN
public c l a s s
//
extends
S i m p l e M a r k o v P r o c e s s <MM2dNState ,
QMM2dNEvent >
f i n a l int ARRIVAL = 0 ; f i n a l int ARRIVAL1 = 1 ; / / o n l y f i n a l int ARRIVAL2 = 2 ; / / o n l y f i n a l int DEPARTURE1 = 3 ; f i n a l int DEPARTURE2 = 4 ; private double lambda ; private double mu1 , mu2 , a l p h a ; private int N ;
Eventos
for for
emtpy emtpy
system system
C o n s t r u c t s a M/M/ 2 d q u e u e w i t h a r r i v a l r a t e lambda and s e r v i c e r a t e s mu1 and mu 2 . @param lambda A r r i v a l r a t e @param mu1 S e r v e r 1 r a t e @param mu2 S e r v e r 2 r a t e @param a l p h a P r o b a b i l i t y o f an a r r i v i n g c u s t o m e r c h o o s i n g server 1 ( i f both idle ) @param N Max number i n t h e s y s t e m /
mu1 ,
double
mu2 ,
double
alpha ,
int
N)
this . lambda = lambda ; this . mu1 = mu1 ; this . mu2 = mu2 ; this . a l p h a = a l p h a ; this . N = N ;
} /
QMM2dNEvent . g e t A l l E v e n t s ( )
);
//
num
Events
rate 3.0 , 8
public @ O v e r r i d e boolean a c t i v e ( MM2dNState boolean r e s u l t = f a l s e ; switch ( e . g e t T y p e ( ) ) { case ARRIVAL : case case break ; break ; break ; case case
} result result result result = ( ( i . getQSize ( ) < N
Determines /
the
active
events
i ,
QMM2dNEvent
e)
2)
& &
( ! i . isEmpty ( ) ) ) ;
ARRIVAL1 : = i . isEmpty ( ) ;
ARRIVAL2 : = i . isEmpty ( ) ;
DEPARTURE1 :
break ; break ;
result
( i . getStatus1 ()
>
0);
return
result ;
public @ O v e r r i d e S t a t e s <MM2dNState> int newx = i . g e t S t a t u s 1 ( ) ; int newy = i . g e t S t a t u s 2 ( ) ; int newz = i . g e t Q S i z e ( ) ; switch ( e . g e t T y p e ( ) ) { case ARRIVAL : i f ( i . getStatus1 ()
newx = } 1; desocupado = =
d e s t s ( MM2dNState
i ,
QMM2dNEvent
e)
= =
0)
else i f
//
//
serv
( i . getStatus2 () 1; desocupado
0)
newy = } serv 2
11
else
}
//
ambos
ocupados + 1;
newz
i . getQSize ( )
break ;
ARRIVAL1 : newx =
break ; break ; if
}
1;
ARRIVAL2 : newy = 1;
else
newz {
1;
newx =
0;
case
break ; if
} DEPARTURE2 : ( i . getQSize ( ) newy = 1; i . getQSize ( ) != 0) {
else
newz {
1;
newy =
0;
break ;
}
return new
S t a t e s S e t <MM2dNState>(
new
MM2dNState ( newx ,
newy ,
newz ) ) ;
public @ O v e r r i d e double r a t e ( MM2dNState double r e s = 0 ; switch ( e . g e t T y p e ( ) ) { case ARRIVAL : case case case case
}
i , MM2dNState
j ,
QMM2dNEvent
e)
res
lambda ;
ARRIVAL1 : lambda
alpha ;
ARRIVAL2 : lambda
(1
alpha ) ;
DEPARTURE1 : = mu1 ;
DEPARTURE2 : = mu2 ;
return
res ;
@Override
System
with
two are in
with with is
"
maximum
system
+ N;
12
public s t a t i c void
String stg ; BufferedReader
the
class .
main ( S t r i n g [ ]
a)
try
new
rdr
new
BufferedReader (
I n p u t S t r e a m R e a d e r ( System . i n ) ) ;
stg
N =
QueueMM2dN
new
QueueMM2dN ( l d a ,
mu1 ,
mu2 ,
alpha ,
N) ;
t h e Q u e u e . showGUI ( ) ;
} } ; }
catch
theQueue . p r i n t A l l ( ) ; ( IOException e) {
//
class
end
1 , 2 , . . . , K . A customer that nds all servers busy joins N K (so there will be at most N customers in the system).
with probability
a single FCFS queue, with capacity A customer that nds all servers idle
k ,
k =
where
k
I
kI
where
Sk (t) = 1
if
k -th
and departures. However we have to distinguish two type of arrivals. If there is no idle server the
13
arriving customer joins the queue, and we will call this a non-directed arrival. Otherwise we call it a directed arrival. We also make part of the event description the server where the arrival is directed. In order to represent this event we need a more sophisticated structure, so instead of just numbering the events we rather extend the class Event, creating an object with two integer elds (components): the type and the server. Then it is very easy to implement the functions
dest
and
rate
active,
just by querying the values of the type and server associated with the state.
4.2.2 Code
File QueueMMKdN.java
package import import import import import import import import import import
// Lets
examples . jmarkov ;
jmarkov . MarkovProcess ; jmarkov . SimpleMarkovProcess ; jmarkov . b a s i c . Event ; jmarkov . b a s i c . E v e n t s S e t ; jmarkov . b a s i c . P r o p e r t i e s S t a t e ; jmarkov . b a s i c . S t a t e s ; jmarkov . b a s i c . S t a t e s S e t ;
start
defining
the
State
class
extends
PropertiesState
servers ,
and
QueueMMKdNState (
alpha )
We i d e n t i f y e a c h S t a t e w i t h s t s t u s f o t h e k s e r v e r s and t h e number i n q u e u e ( 0 , 1 , . . /
vector
that
counts
the
, N K) .
QueueMMKdNState (
int
Qsize ,
double [ ]
alpha )
14
this . a l p h a = a l p h a ; this . b e t a = new double [ K ] ; int sum = 0 ; / / a d d s t h e number for ( int i = 0 ; i < K ; i ++) {
prop [ i ] sum + = } prop [K] } = Qsize ; = status [ i ] ; status [ i ] ;
of
busy
server
people
in
service
@Override
1) ,
getStatus ( i ) ) ;
System " ,
the
kth
Server
kth
Server
Returns @return /
the
size of
of
the
Status
the
size
Determines i f a l l @ r e t u r n True , i f /
servers all
are
servers
& &
( k < K) ;
k++) = = 1);
( getStatus (k)
Determines i f @ r e t u r n True , /
all if
servers all
are
servers
15
for
} /
int
k = =
0;
& &
( k < K) ;
k++) = = 0);
return
result
result
( getStatus (k)
result ;
@see /
j m a r k o v . b a s i c . S t a t e#i s C o n s i s t e n t ( )
public boolean
} /
@Override
isConsistent ()
return true ;
determines i s kept in /
the
// T O D O Complete
sum
of for
all
intensities use .
for
idle
servers .
The
result
sumProb
future
private double sum ( ) { i f ( sumProb != 1) return sumProb ; double r e s = 0 ; for ( int k = 0 ; k < K ;
res } + = (1
k++)
getStatus (k ))
alpha [ k ] ;
return
( sumProb =
res );
} /
D e t e m i n e s t h e p r o b a b i l i t y o f an i d l e s e r v e r b e i n g c h o o s e n among i d l e s e r v e r s . A c u s t o m e r t h a t f i n d s more t h e n o n e s e r v e r i d l e chooses according to r e l a t i v e i n t e n s i t i e s <t e x t x t ="$ \ a l p h a _ 1 , \ a l p h a _ 2 , \ l d o t s , \ alpha_K$"> a l p h a 1 , a l p h a 2 , e t c </ t e x >. The p r o b a b i l i t y o f c h o o s i n g i d l e s e r v e r k w i l l b e g i v e n by <t e x t x t = " \ [ \ b e t a _ k = \ f r a c { \ a l p h a _ k } { \sum_{ \ e l l \ i n \ c a l I } \ a l p h a _ { \ e l l w h e r e $ \ c a l I $ i s t h e s e t o f i d l e s e r v e r s ." > a l p h a ( k ) / sum ( j , a l p h a ( j ) ) , w h e r e t h e sum i s o v e r t h e s e t o f i d l e s e r v e r s . </ t e x > @param s e r v e r s e r v e r i n d e x @ r e t u r n p r o b a b i l i t y o f an i d l e s e r v e r b e i n g c h o o s e n among i d l e s e r v e r s /
{
}} ,\]
getStatus ( server ))
alpha [ s e r v e r ] )
sum ( ) ) ) ;
R e t u r n s a l a b e l w i t h t h e f o r m a t SxxQz , @ s e e j m a r k o v . b a s i c . S t a t e#l a b e l ( ) /
String
whre
xx
is
the
list
of
busy
servers .
public for
}
@Override
label ( )
= "S" ; 0;
String (
int
stg
k =
k < K;
k++) = = 1)
{ ? "" + (k + 1) : "" ;
stg
+ =
( getStatus (k)
16
return
} /
stg
"Q"
getQSize ( ) ;
This /
method
gives
verbal
description
of
the
State .
public if
String
else for
} stg
stg (
int
+ = "No k =
one 0;
in
k < K;
stg
+ =
( getStatus (k)
return
} } /
+ = "
There
are
"
getQSize ( )
"
customers
waiting
in
queue . " ;
stg ;
This c l a s s d e f i n e the e v e n t s . An e v e n t h a s two c o m p o n e n t s : t y p e w h i c h c a n h a v e t h r e e v a l u e s depending whether i t r e p r e s e n t s a d i r e c t e d a r r i v a l , a non d i r e c t e d a r r i v a l o r a d e p a r t u r e , and s e r v e r , w h i c h r e p r e s e n t s the choosen s e r v e r ( i f a r r i v a l ) or the f i n i s h i n g s e r v e r . F o r non d i r e c t e d a r r i v a l s we s e t s e r v e r 1 by c o n v e n t i o n . @ a u t h o r Germn R i a o /
{
servers
are
int
available ,
QueueMMKdNEvent (
this . t y p e = this . s e r v e r
int
type ,
int
server )
type ; = server ;
static for
} (
E v e n t s S e t <QueueMMKdNEvent >
getAllEvents ( =
int int
new
i
eSet
new
int
K)
E v e n t s S e t <QueueMMKdNEvent > ( ) ;
1));
i ));
e S e t . add (
new new
QueueMMKdNEvent ( DIRARRIVAL ,
for
0;
< K;
i ++)
{ i ));
e S e t . add (
QueueMMKdNEvent (DEPARTURE,
17
return
eSet ;
( nonJ a v a d o c ) @ s e e j a v a . l a n g . O b j e c t#t o S t r i n g ( ) /
String stg =
public
@Override
label ( )
"" ; { :
switch case
stg
String
( type )
(NDARRIVAL) + = "Non
d i r e c t e d
:
arrival ";
+ = " Directed
arrival
to
server
"
( server
1);
+ = " Departure
return
stg ;
} //
// end Lets
//
Now
we
define
the
main
class
This c l a s s r e p r e s e n t s i s a system with K d i f f e r e n t e x p o n e n t i a l s e r v e r s w i t h r a t e s mu1 , mu2 , e t c , r e s p e c t i v e l y , and a r r i v a l r a t e lambda . A c u s t o m e r t h a t f i n d s more t h e n o n e s e r v e r i d l e c h o o s e s a c c o r d i n g to r e l a t i v e i n t e n s i t i e s <t e x t x t ="$ \ a l p h a _ 1 , \ a l p h a _ 2 , \ l d o t s , \ alpha_K$"> a l p h a 1 , a l p h a 2 , e t c </ t e x >. The p r o b a b i l i t y o f c h o o s i n g i d l e s e r v e r k w i l l b e g i v e n by <t e x t x t = " \ [ \ b e t a _ k = \ f r a c { \ a l p h a _ k } { \sum_{ \ e l l \ i n \ c a l w h e r e $ \ c a l I $ i s t h e s e t o f i d l e s e r v e r s ." > a l p h a ( k ) / sum ( a l p h a ( j ) ) , w h e r e t h e sum i s o v e r t h e s e t </ t e x > @ a u t h o r Germn R i a o . U n i v e r s i d a d d e l o s Andes . /
QueueMMKdN
I}
\ alpha_ {\ e l l } } , \ ]
of
idle
servers .
public c l a s s
// Eventos
extends
double lambda ; double [ ] mu , a l p h a ; int K ; / / number o f s e r v e r s int N ; s t a t i c f i n a l int NDARRIVAL = QueueMMKdNEvent . NDARRIVAL ; s t a t i c f i n a l int DIRARRIVAL = QueueMMKdNEvent . DIRARRIVAL ; s t a t i c f i n a l int DEPARTURE = QueueMMKdNEvent .DEPARTURE;
18
public QueueMMKdN( double lambda , double [ ] mu , double [ ] super ( new QueueMMKdNState (mu . l e n g t h , a l p h a ) , this . K = mu . l e n g t h ; this . lambda = lambda ; this . mu = mu ; this . a l p h a = a l p h a ; this . N = N ;
} / QueueMMKdNEvent . g e t A l l E v e n t s (mu . l e n g t h ) ) ;
C o n s t r u c t s a M/M/Kd q u e u e w i t h a r r i v a l r a t e lambda and s e r v i c e r a t e s mu , r e l a t i v e p r o b a b i l i t i e s o f c h o o s i n g e a c h s e r v e r a l p h a @param lambda A r r i v a l r a t e @param mu Server rates @param a l p h a Relative probability o f an a r r i v i n g customer choosing @param N Max number i n t h e s y s t e m /
alpha ,
each
server .
int
N)
1.0 ,
8);
Determines /
the
active
events .
public boolean a c t i v e ( QueueMMKdNState i , QueueMMKdNEvent e ) { boolean r e s u l t = f a l s e ; switch ( e . t y p e ) { case (NDARRIVAL) : / / NDARIIVAL o c c u r s o n l y i f s e r v e r s a r e break ; case (DIRARRIVAL)
{ result = ( i . getStatus ( e . server ) occurs if server is = = 0); / /DirARRIVAL result = ( i . allBusy () & & ( i . getQSize ( ) < N
@Override
busy
and
there
is
roon
in
K) ) ;
break ; case
{ } //
E M P T Y.
(DEPARTURE) ev . type =
= = DEPARTURE = = 1);
result
/ /DEPARTURE } }
busy .
return
result ;
Determines /
the
possible
destination
event
( actually
one
in
this
case ) .
19
public S t a t e s <QueueMMKdNState> int [ ] s t a t u s = new int [ K ] ; for ( int k = 0 ; k < K ; k++) int Q = i . g e t Q S i z e ( ) ; switch ( e . t y p e ) { case (NDARRIVAL) : break ; case (DIRARRIVAL)
Q++; // non status [ k ] = i . getStatus (k ) ;
@Override
d e s t s ( QueueMMKdNState
i ,
QueueMMKdNEvent
e)
// copy
current
values
d i r e c t e d
: = 1;
ARRIVAL
status [ e . server ]
// d i r e c t e d
ARRIVAL,
picks
server .
is 1;
else
//
reduce
queue
status [ e . server ] }
0;
// s e t
server
idle
return new
S t a t e s S e t <QueueMMKdNState>(
new
QueueMMKdNState ( s t a t u s ,
Q,
alpha ) ) ;
@Override
result
= mu [ e . s e r v e r ] ;
lambda ;
arrival
i . prob ( e . s e r v e r )
lambda ;
return
result ;
user
for
parameters
main ( S t r i n g [ ]
a)
BufferedReader (
new
I n p u t S t r e a m R e a d e r ( System . i n ) ) ;
double
Rate :
" );
S y s t e m . o u t . p r i n t l n ( "Num
20
int K = I n t e g e r . p a r s e I n t ( r d r . r e a d L i n e ( ) ) ; double mu [ ] = new double [ K ] ; double a l p h a [ ] = new double [ K ] ; for ( int k = 0 ; k < K ; k++) {
System . o u t . p r i n t l n ( " S e r v i c e mu [ k ] } = rate , server " + (k + 1) + " : " ); Double . p a r s e D o u b l e ( r d r . r e a d L i n e ( ) ) ;
for
int
k =
0;
k < K;
k++)
System . o u t . p r i n t l n ( " Choosing alpha [ k ] } S y s t e m . o u t . p r i n t l n ( "Max = intensity , server " + (k + 1) + " : " );
Double . p a r s e D o u b l e ( r d r . r e a d L i n e ( ) ) ;
int
in
system
" );
N =
QueueMMKdN
new
QueueMMKdN( l d a ,
mu ,
alpha ,
N) ;
t h e M o d e l . showGUI ( ) ; // theModel . s e t D e b u g L e v e l ( 2 ) ;
} }; }
catch
theModel . p r i n t A l l ( ) ; ( IOException e) {
@see /
j m a r k o v . S i m p l e M a r k o v P r o c e s s#d e s c r i p t i o n ( )
public
stg stg
String
"M/M/ k /N SYSTEM\ n \ n " ; server Rate = " queue + with " + + " ,
this . K
Max
"
different in system
s e r v e r s \n" ; " + N;
return
} } // c l a s s
lambda
number
end
package import import import import import import import import import import import
examples . jmarkov ;
java . io . PrintWriter ;
21
DriveThru .
Gloria
Daz .
Universidad
de
los
Andes .
posicion de la y
del
primera N+2
cola
class
// //
extends
State
private private
int
micPos ; micStatus ;
CustStatus
prop
null ;
differents status for a customer .
shows
the
public
/
enum
CustStatus vacio .
Sitio
/ /
micrfono pero no hay servidores para que me atiendan .
EMPTY, En servicio .
ORDERING, / Estoy en el
/
estoy bloqueado .
B L O C K E D _ D O N E; }
State
represinting
an
empty
system
micPos serv
DriveThruState (
int
= 0;
micPos ,
int
serv )
{ 0, { serv ) ;
C u s t S t a t u s [ micPos ] , i i <
EMPTY,
prop . l e n g t h ;
i ++)
22
prop [ i ] } }
= E M P T Y;
C o n s t r u y e un n u e v o e s t a d o D r i v e T h r u . @param v e c Estados desde l a ventana hasta el @param m i c Estado d e l micrfono . @param numQ Cantidad de p e r s o n a s en l a cola . @param a v S e r v s Servidores disponibles /
micrfono
( sin
incluirlo ).
DriveThruState ( CustStatus [ ]
int
=
statusVec ,
CustStatus
micStatus ,
int
numQ,
prop
int
new
avServs )
{ + 1];
micPos
micPos ) ;
micStatus ;
Compute /
all
the
MOPs
for
this
state
@Override
mp)
? 1
1 :
0; 0; ? 1 1 : : 0; 0;
= = B L O C K E D _ D O N E) (s = = WAIT_MIC) ? 1 : 0; ?
blockedBefore total } setMOP ( mp , setMOP ( mp , setMOP ( mp , setMOP ( mp , setMOP ( mp , setMOP ( mp , setMOP ( mp , setMOP ( mp , + setMOP ( mp , } + = (s
+ =
!= E M P T Y)
Cola " ,
getQLength ( ) ) ; Microfono " , servEtapa1 ) ; servEtapa2 ) ; + servEtapa2 ) ; ordenar " , lista " , + blockedBefore ) ; blockedDone ) ; blockedDone ) ; + blockedDone
Bloqueados Bloqueados
de
orden
Bloqueados " , en
blockedBefore
clientes
Espera " ,
blockedBefore
23
Obtiene @return /
el
nmero
de
personas
en
la
cola
Nmero
de
personas
en
la
cola .
getQLength ( ) numQ ;
la
posicin
i .
posicin
i .
i )
Obtiene @return /
el
vector
de
estado
de
los
clientes
Estado
en
la
posicin
numMic
Obtiene @return /
el
estado
de
la
ventana .
Estado
del
cliente
en
el
micrfono
1;
public
Obtiene @return /
el
estado
de
la
ventana .
Estado
de
la
ventana .
CustStatus
getVentana ( )
24
return
} /
prop [ 0 ] ;
Obtiene @return /
el
nmero
de
servidores
disponibles
Estado
de
la
ventana .
getAvlServs () avlServ ;
@see /
j m a r k o v . b a s i c . S t a t e#i s C o n s i s t e n t ( )
public boolean
}
@Override
isConsistent ()
return true ;
@Override String stg
// T O D O Complete
public
label ( )
= "" ; s
for
String
( CustStatus
prop )
stg
+ = "0" ;
ORDERING : + = "m" ;
WAIT_MIC : + = "w" ;
COOKING : + = "c" ;
B L O C K E D _ D O N E: + = "b" ;
return
//
stg
+ stg
"Q" +
return
String
switch ( s t a t ) { case EMPTY: return " empty " ; case ORDERING : return " o r d e r i n g , " ; case WAIT_MIC : return " w a i t i n g " ; case COOKING : return " c o o k i n g " ;
statusDesc ( CustStatus
stat )
25
public
@Override
int for
} stg stg stg
String N = = (
int
" Queue i =
i ++)
stg stg
+ = + =
1)
" ,
"
"" ;
+ = " ). + = ".
Mic Queue
"
statusDesc ( getMicStatus ( ) ) ;
return
} /
getQLength ( ) ;
stg ;
@see /
j m a r k o v . b a s i c . S t a t e#compareTo ( j m a r k o v . b a s i c . S t a t e )
@Override
wrong
types ! " ) ;
int k = 0 ; k <= m i c P o s ; k++) { i f ( getStatus (k ) . ordinal () > u . getStatus (k ) . ordinal ()) return + 1 ; i f ( getStatus (k ) . ordinal () < u . getStatus (k ) . ordinal ()) return 1;
> u . getQLength ( ) ) +1; < u . getQLength ( ) )
if if if if
( getQLength ( )
return
( getQLength ( )
return 1; return
+1;
( getAvlServs ()
>
u . getAvlServs ( ) )
return 1; return 0 ;
} }
( getAvlServs ()
<
u . getAvlServs ( ) )
class
eventos
en
un
Drive
Thru .
Extendiende
la
clase
extends
jmarkov . b a s i c . Event
26
public s t a t i c
/
Event
types .
/
Type the { system . to
enum
Arrivale
/ /
who ordered .
SERVICE_COMPLETION ; }
event //
Posicion
public
}
C r e a t e s an ARRIVAL @param t y p e /
or
MIC_COMPLETION
event .
type ) ||
{ = = MIC_COMPLETION ) ;
this . t y p e
/
assert
type
event
at
he
given
position .
event
occurs
based
).
public int
assert }
@return /
position
where
this
event
occurs .
( valid
only
if
type
= =
SERVICE_COMPLETION ) .
getPos ( ) ( type
return
/
= = SERVICE_COMPLETION ) ;
position ;
@return /
event
type
public s t a t i c
@param m i c P o s @return A s e t /
with
all
the
events
in
the
system .
E v e n t s S e t <D r i v e T h r u E v e n t >
new
eSet
new
getAllEvents (
int
micPos )
E v e n t s S e t <D r i v e T h r u E v e n t > ( ) ;
D r i v e T h r u E v e n t (ARRIVAL ) ) ;
27
for
}
e S e t . add ( (
int
new
i =
D r i v e T h r u E v e n t (MIC_COMPLETION ) ) ;
return
@Override
e S e t . add ( eSet ;
new
0;
<=
micPos ;
i ++)
DriveThruEvent ( i ) ) ;
public
String stg
label ( )
= "" ; {
String
break ; default :
stg } =
position
")" ;
return
stg ;
un
Drive
Thru .
Extendiende
la
clase
extends
DriveThruEvent> { Tasa de de de arribo
S i m p l e M a r k o v P r o c e s s <D r i v e T h r u S t a t e ,
//
Tasa Tasa
servicio servidor de
servidor
mximo de de
entidades
en
el
sistema
public D r i v e T h r u ( double lambda , double mu1 , double mu2 , int M, int S , int super ( ( new D r i v e T h r u S t a t e (N , S ) ) , D r i v e T h r u E v e n t . g e t A l l E v e n t s (N ) ) ;
28
C o n s t r u c t o r d e un D r i v e T h r u . @param lambda Tasa de a r r i b o s @param mu1 Tasa de servicios del micrfono @param mu2 Tasa de servicios de l a v e n t a n a @param M Nmero mximo d e e n t i d a d e s e n e l sistema @param S Nmero d e s e r v i d o r e s @param N Nmero d e p u e s t o s entre l a ventana y e l micrfono /
N)
this . lambda = lambda ; this . mu1 = mu1 ; this . mu2 = mu2 ; this .M = M; this . S = S ; this . N = N ;
}
public D r i v e T h r u ( ) { this ( 8 0 . 0 , 1 2 . 0 ,
} /
Default /
constructor
for
GUI .
30.0 ,
4,
2,
1);
cada
estado
@Override
s ,
DriveThruEvent
ev )
hay
espacio
en
cola
case
break ;
// // se el
result
( s . getQLength ( )
< M
1);
MIC_COMPLETION : puede pedido = ( s . getMicStatus () = = ORDERING ) ; terminar de tomar la orden si una persona esta haciendo
break ; default :
// // se
result
puede
terminar
una
orden
si
la
persona
correspondiente
la
esta
if
esperando ( ev . g e t Po s ( ) = = N) { = = COOKING ) ;
else
result {
( s . getMicStatus ()
result } }
( s . g e t S t a t u s ( ev . g et P o s ( ) )
= = COOKING ) ;
return
result ;
se 2.
termina
un
@Override
DriveThruEvent
e)
29
case
return
lambda ;
MIC_COMPLETION : mu1 ;
mu2 ;
} }
un
evento
ocurre .
E)
@Override
i ,
DriveThruEvent
e)
int n e w Q s i z e = i . g e t Q L e n g t h ( ) ; int numGone = 0 ; boolean micMoves = f a l s e ; int k ; / / u t i l i t y c o u n t e r switch ( e . g e t T y p e ( ) ) { case ARRIVAL : i f ( i . getMicStatus ()
// Hay espacio
newMic =
i . getMicStatus ( ) ;
0)
en
servidores
newMic = ORDERING ;
else i f
//
numServ = numServ
el
( i . getMicStatus () espacio en
Hay
microfono
servidores
else i f
//
en
1)
Micrfono =
espacio 1;
cola .
newQsize
i . getQLength ( )
break ; case
MIC_COMPLETION : newMic = COOKING ;
for if
(k = ;
0;
( ( k < N)
& &
( status [ k ]
!= E M P T Y) ) ;
k++)
//
k (k
es !=
la N)
1a {
posicion // Si hay
status [ k ]
= COOKING ;
newMic = E M P T Y; micMoves =
true ;
//
status [ p ]
= B L O C K E D _ D O N E;
30
else i f else
{ //
(p = = N)
//
Esta
listo
el
mic
status [ 0 ] //
int for if
//
encontramos (k = ; 1;
cliente status [ k ]
no
bloqueado : k++)
( ( k < N)
= = B L O C K E D _ D O N E) ;
numGone = k ; (k != N) {
// //
el El
numero primer
que
salen es el mic
NB NO
pos1 //
El
pos2
for
= N (k =
1;
pos2
ultimo
cola
pos1 ;
k <=
pos2 ; =
k++)
status [ k // } } los
numGone ] todos
status [ k ] ;
movemos
for if
(k = N
numGone ; = E M P T Y;
k < N; // el
k++) resto
{ esta vaco
status [ k ] }
s t a t u s [N
numGone ]
= newMic ;
newMic = E M P T Y;
else i f
//
micMoves
true ;
{ se va
El
newMic = E M P T Y; micMoves } =
true ;
break ;
} // end switch
if
}
0)
;
{ > 0 & & numServ > 0) {
if
( micMoves )
if
( i . getQLength ( )
1;
else i f
newQsize
i . getQLength ( ) >
1; 0) {
( i . getQLength ( )
1;
return
} // end @Override
s e t . add (
new
set
new
DriveThruState ( status ,
newMic ,
set ;
dests
31
"
de
= de
"
= del
sevicio
mic =
+ N +
sistema
+ M;
Print /
all
waiting
times
associated
with
each M O P
public int printMOPs ( P r i n t W r i t e r o u t , int int namesWidth = super . printMOPs ( o u t , double try {
// this rate work for all MOPs ldaEff ;
@Override
width , width ,
int
decimals )
decimals ) ;
ldaEff
String [ ]
for
int
waitTime String
name =
" Waiting
o u t . p r i n t l n ( pad ( name , +
namesWidth , width ,
false )
names [ i ] ;
pad ( w a i t T i m e ,
decimals )
"
minutes " ) ;
catch
( NotUnichainException
e)
out . p r i n t l n ( e ) ; }
return
namesWidth ;
public s t a t i c void
// as in DriveThru // DriveThru
used .
main ( S t r i n g [ ]
a)
handout : theDT =
new
DriveThru ( 8 0 . 0 ,
12.0 ,
30.0 ,
4,
2, 4,
1); 2, 2);
theDT = new
DriveThru ( 8 0 . 0 ,
120.0 ,
30.0 ,
theDT . s e t D e b u g L e v e l ( 5 ) ;
//
class
end
4.3.2 Results
Output for Drive Thru
32
SISTEMA DRIVE T HR U. Tasa Tasa Tasa de en de Entrada el Mic 2 = = = mic = sistema = 4 14 80.0 120.0 30.0 = 5
sevicio del
System
has
498
States .
MEASURES OF P E R F O R M A N C E
M E A N 4.503 0.550 2.199 2.749 antes con de ordenar lista 0.112 1.540 1.652 6.155 8.903
SDEV 2.693 0.498 1.165 1.088 0.316 1.646 1.604 3.487 3.396
orden
clientes Clientes
Espera
EVENTS O C C U R A N C E RATES N A M E Arrival MicEnd SrvEnd ( 0 ) SrvEnd ( 1 ) SrvEnd ( 2 ) SrvEnd ( 3 ) SrvEnd ( 4 ) SrvEnd ( 5 ) M E A N RATE 65.965 65.965 28.019 9.927 9.446 8.333 6.114 4.126
de de de de de de de de de
Cola :
4.096
minutos
orden
minutos
1.503
clientes Clientes
Espera : 8.098
minutos
In this section we give a brief description of Quasi-Birth and Death Processes (QBD), and explain how they can be modeled using jMarkov. QBD are Markov Processes with an innite space state, but with a very specic repetitive structure that makes them quite tractable.
33
(n, i)
to state
(n , i )
only if
n = n, n = n 1
or
n.
..
where, as usual, the rows add up to 0. An innite Markov Process with the conditions described above is called a Quasi-Birth and Death Process (QBD). In general, the level zero might have a number of phases has size
m0 = m. (m0 m)
states the boundary states, and all other states will be called typical states. Note that matrix
m0 B00
m0 m0 ,
whereas
B01
and
B10
(m m0 ),
respectively.
Assume that the QBD is an ergodic Markov Chain. As a result, there is a steady state distribution
to the system
Q = 0, 1 = 1.
Divide this
vector by levels,
was divided, as
= [ 0 , 1 , . . .].
Then, it can be shown that a solution exist that satisfy
n+1 = n R,
where
n > 1, R
is the solution to the equation
[6]. This
A0 + RA1 + R2 A2 = 0.
There are various algorithms that can be used to compute the matrix start with any initial guess
R.
R0
Rk
A1
and
are
0 1
0 1 + 1 (I R)1 1 = 1.
34
ri
n 1.
n r = 1 (I R)1 r,
n=1
where
is an
m-size
ri .
nri ,
of level
n.
n n r = 1 R(I R)2 r.
n=1
rate.
The main dierence is that special care needs to be taken when dening the destination states
for the typical states. Rather than dening a new level for the destination state, the user should give a new relative level, which can be -1, 0, or +1. This is accomplished by using two dierent classes to dene states. The current state of the system is a GeomState, but the destination states are GeomRelState. The process itself must extend the class GeomProcess, which in turn is an extension of MarkovProcess. The building algorithm uses the information stored about the dynamics of the process to explore the graph and build only the rst three levels of the system. extract matrices From this, it is straightforward to
and
A2 .
condition is checked. If the system is found to be stable, then the matrices passed to the solver, which takes care of computing the matrix vectors
A0 , A1 ,
and
A2
are
uses the logarithmic reduction algorithm [5]. This class uses MTJ for matrices manipulations. There are also mechanisms to dene both types of measures of performance mentioned above, and jQBD can compute the long run average value for all of them.
5.4 An Example
To illustrate the modeling process with jQBD, we will show the previous steps with a simple example. Consider a innite queue with a station that has a single hiper-exponential server with phases, with probability
at phase
n service i, where
0 i n. . We will
The station is fed from an external source according to a Poisson processes with rate use this model as an illustrative example of a QBD process, and will show how each
of the previous steps is performed for this example. Of course all measures of performnce for this system can be readilly obtained in closed form since it is a particular case of an distribution, so the hyper-geometric will be a particular case.
M/G/1,
but we
chose this example bacause of its simplicity. The code below actually models any general phase-type
States:
Because of the memoryless property, the state of the system is fully characterized
x = (x1 , x2 ), where x1 0 represents the number of items in the 0 x2 n represents the current phase of the service process.Note that, knowing
this, we can know how many items are in service and how many are queuing. It is important
35
to highlight that the computational representation uses only the phase of the system (x2 ) because the level (x1 )is manged internally by the framework.
Events:
0 i n.
ci
i.
active (i,e):
and the events
ci , 0 i n
i.
The code to achieve this can be seen in Figure 6. When the event
dests (i,e,j):
level, but you need to consider if the server is idle or busy. When the server is idle the new costumer could start in any of the anyone of the rst level busy on service phase phase
i .
i,
the system will reach the next level state with the same service
i. ci ,
no matter which phase type,
the level of the system is reduced by one, but you need to consider if the system is in level 1 or if it is in level 2 or above. When the level is 1, the system reach the unique state (0, 0) where there are no costumer in the system and the server is idle. the 7. On the other hand, if the system level is equal or greater than 2, the system could reach any of
i . a
rate (i,e):
MOPs:
is given simply by
occurrence of an event
ci
is given by
i .
Using the MOPS types dened in jQBD component, we will illustrate its use calcu-
File HiperExQueue.java
return
result ;
( non
J a v a d o c )
Figure 6:
Active
36
File HiperExQueue.java
=
new
int int
n e w Ph a s e rLevel =
= 0;
i . getSrvPhase ( ) ;
if
+1; = = 0) destStates );
( absLevel
else
addDestsFinishServer ( rLevel ,
d e s t S t a t e s . add (
case
break ;
rLevel
new
new
H i p e r E x Q u e u e S t a t e ( n e w P h as e ) ,
FINISH_SERVICE :
if
1;
= = 1)
( absLevel
d e s t S t a t e s . add (
else break ;
}
new
new
G e o m R e l S t a t e<H i p e r E x Q u e u e S t a t e >(
HiperExQueueState ( 0 ) ) ) ;
addDestsFinishServer ( rLevel ,
destStates );
return
end of
} //
the
rate
of
transition
from
to
when
dests
Finally, the output obtained after running the model can be seen in the Graphical User Interface (GUI) in Figure 9. There is no need to use the GUI, but it is helpful to do so during the rst stages of development, to make sure that all transitions are being generated as expected. All the measures of performance dened can be extracted by convenience methods dened in the API or a report printed to standard output. Such a report can be seen in Figure 10.
Advanced Features
Using the Solvers Using the Transitions scheme Computing MOPs on the y to save memory extending jMarkov
Further Development
This project is currently under development, and therefore we appreciate all the feedback we can receive.
37
File HiperExQueue.java
case
i f ( i L e v e l == 0 ) { int n e w Ph a s e = double a l p h a [ ]
rate } = lambda
ARRIVAL :
1];
else {
rate = lambda ;
case
break ; if
FINISH_SERVICE : ( iLevel
int n e w Ph a s e = double a l p h a [ ]
rate =
>
1){
a [ e . getCurPH ( )
1]
a l p h a [ n e w P ha s e
1];
else {
rate = a [ e . getCurPH ( )
1];
break ;
}
return
end of
rate ; rate
} // /
( nonJ a v a d o c ) @ s e e j m a r k o v . S i m p l e M a r k o v P r o c e s s#d e s c r i p t i o n ( ) /
String description () {
public
@Override
Figure 8:
rate
References
[1] G. Ciardo. Tools for formulating Markov models. In W. K. Grassman, editor, Computational
Probability. Kluwer's International Series in Operations Research and Management Science,
Massachusetts, USA, 2000. [2] B. Heimsund. Matrix Toolkits for Java (MTJ). Webpage:
http://rs.cipr.uib.no/mtj/,
December 2005. Last checked on 05-Dec-2005. [3] J. Hicklin, C. Moler, P. Webb, R. F. Boisvert, B. Miller, R. Pozo, and K. Remington. JAMA: A java matrix package. Webpage: http://math.nist.gov/javanumerics/jama/, July 2005. MathWorks and the National Institute of Standards and Technology (NIST). [4] V. Kulkarni. Modeling and analysis of stochastic systems. Chapman & Hall., 1995. [5] G. Latouche and V. Ramaswami. Introduction to matrix analytic methods in stochastic modeling. Society for Industrial and Applied Mathematics (SIAM), Philadelphia, PA, 1999.
[6] M. F. Neuts. Matrix-geometrix solutions in stochastic models. The John Hopkins University Press, 1981.
38
[7] J. F. Prez and G. Riao. jPhase: an object- oriented tool for modeling Phase-Type distributions. In Proceedings of the SMCtools'06, October 2006. Pisa, Italy. [8] J. F. Prez and G. Riao. jPhase user's guide. In Proceedings of the SMCtools'06, October 2006. Pisa, Italy. [9] G. Riao and J. Gez. jMarkov user's guide. Industrial Engineering, Universidad de los Andes, 2005. [10] G. Riao and A. Sarmiento. jMDP: an object-oriented framework for modeling MDPs. Working paper. Universidad de los Andes, 2006. [11] A. Sarmiento and G. Riao. jMDP user's guide. Industrial Engineering, Universidad de los Andes, 2005.
File DriveThru.java
MEASURES OF P E R F O R M A N C E
N A M E
M E A N
SDEV
Expected Server
Level
0.14286 0.12500
? 0.33072
Utilization
39
http://www.java.sun.com/,
Jan. 2006.
[13] P. van der Linden. Just Java(TM) 2. Prentice Hall, 6th edition, 2004.
40
Index
41