This commit is contained in:
2025-01-15 16:59:52 +01:00
parent 695add3440
commit ad160877de
8 changed files with 662 additions and 0 deletions

4
.gitignore vendored
View File

@@ -22,3 +22,7 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
# mine
pdf/*

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

149
SimulatoreBCNN/src/Sim.java Normal file
View File

@@ -0,0 +1,149 @@
import SimUtils.*;
import SimUtils.Queue;
import java.util.*;
class Sim {
// Class Sim variables
public static double Clock, MeanInterArrivalTime, MeanServiceTime, SIGMA, LastEventTime,
TotalBusy, MaxQueueLength, SumResponseTime;
public static long NumberOfCustomers, QueueLength, NumberInService,
TotalCustomers, NumberOfDepartures, LongService;
public final static int arrival = 1;
public final static int departure = 2;
public static EventList FutureEventList;
public static Queue Customers;
public static Random stream;
public static void main(String argv[]) {
MeanInterArrivalTime = 4.5; MeanServiceTime = 3.2;
SIGMA = 0.6; TotalCustomers = 1000;
long seed = Long.parseLong(argv[0]);
stream = new Random(seed); // initialize rng stream
FutureEventList = new EventList();
Customers = new Queue();
Initialization();
// Loop until first "TotalCustomers" have departed
while(NumberOfDepartures < TotalCustomers ) {
Event evt = (Event)FutureEventList.getMin(); // get imminent event
FutureEventList.dequeue(); // be rid of it
Clock = evt.get_time(); // advance simulation time
if( evt.get_type() == arrival ) ProcessArrival(evt);
else ProcessDeparture(evt);
}
ReportGeneration();
}
// seed the event list with TotalCustomers arrivals
public static void Initialization() {
Clock = 0.0;
QueueLength = 0;
NumberInService = 0;
LastEventTime = 0.0;
TotalBusy = 0 ;
MaxQueueLength = 0;
SumResponseTime = 0;
NumberOfDepartures = 0;
LongService = 0;
// create first arrival event
Event evt = new Event(arrival, exponential( stream, MeanInterArrivalTime));
FutureEventList.enqueue( evt );
}
public static void ProcessArrival(Event evt) {
Customers.enqueue(evt);
QueueLength++;
// if the server is idle, fetch the event, do statistics
// and put into service
if( NumberInService == 0) ScheduleDeparture();
else TotalBusy += (Clock - LastEventTime); // server is busy
// adjust max queue length statistics
if (MaxQueueLength < QueueLength) MaxQueueLength = QueueLength;
// schedule the next arrival
Event next_arrival = new Event(arrival, Clock+exponential(stream, MeanInterArrivalTime));
FutureEventList.enqueue( next_arrival );
LastEventTime = Clock;
}
public static void ScheduleDeparture() {
double ServiceTime;
// get the job at the head of the queue
while (( ServiceTime = normal(stream, MeanServiceTime, SIGMA)) < 0 );
Event depart = new Event(departure,Clock+ServiceTime);
FutureEventList.enqueue( depart );
NumberInService = 1;
QueueLength--;
}
public static void ProcessDeparture(Event e) {
// get the customer description
Event finished = (Event) Customers.dequeue();
// if there are customers in the queue then schedule
// the departure of the next one
if( QueueLength > 0 ) ScheduleDeparture();
else NumberInService = 0;
// measure the response time and add to the sum
double response = (Clock - finished.get_time());
SumResponseTime += response;
if( response > 4.0 ) LongService++; // record long service
TotalBusy += (Clock - LastEventTime );
NumberOfDepartures++;
LastEventTime = Clock;
}
public static void ReportGeneration() {
double RHO = TotalBusy/Clock;
double AVGR = SumResponseTime/TotalCustomers;
double PC4 = ((double)LongService)/TotalCustomers;
System.out.println( "SINGLE SERVER QUEUE SIMULATION - GROCERY STORE CHECKOUT COUNTER ");
System.out.println( "\tMEAN INTERARRIVAL TIME "
+ MeanInterArrivalTime );
System.out.println( "\tMEAN SERVICE TIME "
+ MeanServiceTime );
System.out.println( "\tSTANDARD DEVIATION OF SERVICE TIMES " + SIGMA );
System.out.println( "\tNUMBER OF CUSTOMERS SERVED " + TotalCustomers );
System.out.println();
System.out.println( "\tSERVER UTILIZATION " + RHO );
System.out.println( "\tMAXIMUM LINE LENGTH " + MaxQueueLength );
System.out.println( "\tAVERAGE RESPONSE TIME " + AVGR + " MINUTES" );
System.out.println( "\tPROPORTION WHO SPEND FOUR ");
System.out.println( "\t MINUTES OR MORE IN SYSTEM " + PC4 );
System.out.println( "\tSIMULATION RUNLENGTH " + Clock + " MINUTES" );
System.out.println( "\tNUMBER OF DEPARTURES " + TotalCustomers );
}
public static double exponential(Random rng, double mean) {
return -mean*Math.log( rng.nextDouble() );
}
public static double SaveNormal;
public static int NumNormals = 0;
public static final double PI = 3.1415927 ;
public static double normal(Random rng, double mean, double sigma) {
double ReturnNormal;
// should we generate two normals?
if(NumNormals == 0 ) {
double r1 = rng.nextDouble();
double r2 = rng.nextDouble();
ReturnNormal = Math.sqrt(-2*Math.log(r1))*Math.cos(2*PI*r2);
SaveNormal = Math.sqrt(-2*Math.log(r1))*Math.sin(2*PI*r2);
NumNormals = 1;
} else {
NumNormals = 0;
ReturnNormal = SaveNormal;
}
return ReturnNormal*sigma + mean ;
}
}

View File

@@ -0,0 +1,21 @@
package SimUtils;
public class Event implements Comparable {
public Event(int a_type, double a_time) { _type = a_type; time = a_time; }
public double time;
private int _type;
public int get_type() { return _type; }
public double get_time() { return time; }
public Event leftlink, rightlink, uplink;
public int compareTo(Object _cmpEvent ) {
double _cmp_time = ((Event) _cmpEvent).get_time() ;
if( this.time < _cmp_time) return -1;
if( this.time == _cmp_time) return 0;
return 1;
}
}

View File

@@ -0,0 +1,195 @@
package SimUtils;
// EventList is implemented as a splay tree
// v1. class Event knows this and has fields
// leftlink, rightlink, uplink
public class EventList {
Event root;
Event update_p;
Event left,right,next,temp,farleft,farfarleft;
double ntime;
boolean update_code;
int size = 0;
Object owner;
public EventList(){ }
public String toString(){
return "EventList ";
}
public boolean isEmpty(){
return (this.root == null);
}
public void enqueue(Event n){
size++;
n.uplink = null;
next = this.root;
this.root = n;
if (next == null){
n.leftlink = null;
n.rightlink = null;
}
else{
mainblock: {
ntime = n.time;
left = n;
right = n;
if (next.time > ntime){
//2222222222222222222222222
do{
temp = next.leftlink;
if (temp == null){
right.leftlink = next;
next.uplink = right;
left.rightlink = null;
break mainblock;
}
if (temp.time <= ntime){
right.leftlink = next;
next.uplink = right;
right = next;
next = temp;
break;
}
next.leftlink = temp.rightlink;
if (temp.rightlink != null)
temp.rightlink.uplink = next;
right.leftlink = temp;
temp.uplink = right;
temp.rightlink = next;
next.uplink = temp;
right = temp;
next = temp.leftlink;
if (next == null){
left.rightlink = null;
break mainblock;
}
}while (next.time > ntime);
}
forblock:
for( ; ; ){
//111111111111111111111111111
do{
temp = next.rightlink;
if (temp == null){
left.rightlink = next;
next.uplink = left;
right.leftlink = null;
break forblock;
}
if (temp.time > ntime){
left.rightlink = next;
next.uplink = left;
left = next;
next = temp;
break;
}
next.rightlink = temp.leftlink;
if (temp.leftlink!=null)
temp.leftlink.uplink = next;
left.rightlink = temp;
temp.uplink = left;
temp.leftlink = next;
next.uplink = temp;
left = temp;
next = temp.rightlink;
if (next == null){
right.leftlink = null;
break forblock;
}
}while (next.time <= ntime);
//2222222222222222222222222222
do{
temp = next.leftlink;
if (temp == null){
right.leftlink = next;
next.uplink = right;
left.rightlink = null;
break forblock;
}
if (temp.time <= ntime){
right.leftlink = next;
next.uplink = right;
right = next;
next = temp;
break;
}
next.leftlink = temp.rightlink;
if (temp.rightlink != null)
temp.rightlink.uplink = next;
right.leftlink = temp;
temp.uplink = right;
temp.rightlink = next;
next.uplink = temp;
right = temp;
next = temp.leftlink;
if (next == null){
left.rightlink = null;
break forblock;
}
}while (next.time > ntime);
}
}
//99999999999999999999999999999
temp = n.leftlink;
n.leftlink = n.rightlink;
n.rightlink = temp;
}
}
public Event getMin(){
//assumed that the tree is not empty
next = this.root;
left = next.leftlink;
if (left ==null){
update_code = true;
return next;
}
else{
for ( ; ; ){
farleft = left.leftlink;
if (farleft == null){
update_code = false;
update_p = next;
return left;
}
farfarleft = farleft.leftlink;
if (farfarleft==null){
update_code = false;
update_p = left;
return farleft;
}
next.leftlink = farleft;
farleft.uplink = next;
left.leftlink = farleft.rightlink;
if (farleft.rightlink!=null)
farleft.rightlink.uplink = left;
farleft.rightlink = left;
left.uplink = farleft;
next = farleft;
left = farfarleft;
}
}
}
public void dequeue(){
size--;
//assumed that getMin has been the last splay tree operation invoked. Removes that element.
if (update_code){
next = null; //remove pointer to the returned Event
root = root.rightlink;
if (root!=null)
root.uplink = null;
}
else{
left = farleft = null; //remove pointers to the returned event
if (update_p.leftlink.rightlink!=null)
update_p.leftlink.rightlink.uplink = update_p;
update_p.leftlink = update_p.leftlink.rightlink;
}
}
}

View File

@@ -0,0 +1,253 @@
package SimUtils;
/**
This class provides a fairly efficient implementation of a FIFO
queue. We use an array to implement the queue which is
automatically increased in size when necessary. Note that the queue
is never shrunk in the current implementation.
@author Mark Astley
@version $Revision: 1.5 $ ($Date: 1998/09/07 23:00:37 $)
*/
// public class Queue implements Cloneable, Serializable {
public class Queue {
/**
This constant sets the initial size of a queue when the default
constructor is invoked to create a queue. Users requiring a
different initial size may invoke the appropriate constructor
below.
*/
public static final int INITIAL_SIZE = 10;
/**
This array holds the queue. We use a dynamically growing circular
array to represent the queue. Queue size is doubled when
necessary which should make for a rather efficient implementation.
*/
Object[] theQ;
/**
These two fields hold indices to the first and last element of the
queue respectively. Technically, <em>back</em> points to the
first open spot in the queue rather than the last element.
*/
int front;
int back;
/**
Default constructor for the <em>Queue</em> class.
*/
public Queue() {
theQ = new Object[INITIAL_SIZE];
front=back=0;
}
/**
Alternative constructor for the <em>Queue</em> class which allows
the specification of the initial size of the queue.
@param <b>initialSize</b> The initial size of the new <em>Queue</em>.
*/
public Queue(int initialSize) {
theQ = new Object[initialSize];
front=back=0;
}
/**
This private method is used to double the size of the queue when
more space is required (as a result of calling enqueue). Note
that because the implementation is in terms of a circular array,
we have to be careful when copying elements from the old array to
the new array.
*/
synchronized private void grow() {
Object[] newQ = new Object[2 * theQ.length];
if (back >= front)
System.arraycopy(theQ, front, newQ, front, back - front + 1);
else {
System.arraycopy(theQ, front, newQ, front, theQ.length - front);
System.arraycopy(theQ, 0, newQ, theQ.length, back);
back = front + theQ.length - 1;
}
theQ = newQ;
}
/**
Determine if the queue is empty.
@return <b>true</b> if the queue contains no elements,
<b>false</b> otherwise.
*/
synchronized public boolean empty() {
return (front == back);
}
/**
Add an object to the end of the queue.
@param <b>q</b> A reference to the object to add.
@return <b>void</b>
*/
synchronized public void enqueue(Object q) {
if (((back + 1) % theQ.length) == front)
grow();
theQ[back] = q;
back = (back + 1) % theQ.length;
}
/**
Remove an object from the front of the queue. The returned object
is removed from the queue.
@return A reference to the <b>Object</b> at the front of the
queue. Returns <em>null</em> if the queue is empty.
*/
synchronized public Object dequeue() {
Object toReturn = null;
if (!empty()) {
toReturn = theQ[front];
front = (front + 1) % theQ.length;
}
return toReturn;
}
/**
Get the object at the front of the queue without removing it.
@return A reference to the <b>Object</b> at the front of the
queue.
*/
synchronized public Object peekFront() {
if (!empty())
return theQ[front];
else
return null;
}
/**
Determine how many objects are currently stored in the queue.
@return An <b>int</b> indicating the number of objects in the
queue.
*/
synchronized public int numElements() {
if (front <= back)
return (back - front);
else
return (back + (theQ.length - front));
}
/**
This function allows arbitrary queue elements to be removed.
Elements which are equal (according to the <em>equal</em>
function) to the argument are removed from the queue. Note that
this version of the function only removes the FIRST element
found. Use the <em>removeAll</em> function to remove ALL elements
equal to the argument.
@param <b>rem</b> The object to be removed from the queue.
@return <b>true</b> if an element was removed, <b>false</b>
otherwise.
*/
synchronized public boolean remove(Object rem) {
int i, x, y;
// PRAGMA [debug,osl.util.Queue] Log.println("<Queue.remove> Searching for element: " + rem);
// First track down the element to remove (if there is one)
for(i=front; i != back; i = (i + 1) % theQ.length)
if (rem.equals(theQ[i]))
break;
// If nothing found then return false...
if (i == back)
// PRAGMA [debug,osl.util.Queue] {
// PRAGMA [debug,osl.util.Queue] Log.println("<Queue.remove> Element not found, returning");
return false;
// PRAGMA [debug,osl.util.Queue] } else {
// PRAGMA [debug,osl.util.Queue] Log.println("<Queue.remove> Element found at position: " + i);
// PRAGMA [debug,osl.util.Queue] }
// Otherwise remove the one element. This is a bit of a hack but
// should be fairly efficient.
Object[] newQ = new Object[theQ.length];
for(x=front, y=0; x != back; x = (x + 1) % theQ.length)
if (x != i) {
newQ[y] = theQ[x];
y++;
}
theQ = newQ;
front = 0;
back = y;
return true;
}
/**
This function has the same behavior as <em>remove</em> except that
ALL matching elements are removed from the queue.
@param <b>rem</b> The object to be removed from the queue.
@return The number of elements removed.
*/
synchronized public int removeAll(Object rem) {
int i, match, x, y, z;
// Track down all the elements to remove.
int[] toRemove = new int[numElements()];
for(i=front, match=0; i != back; i = (i + 1) % theQ.length)
if (rem.equals(theQ[i])) {
toRemove[match] = i;
match++;
}
// See if anything matched, if not then just return
if (match == 0)
return 0;
// Now make a new array with all the matching elements removed
Object[] newQ = new Object[theQ.length];
for(x=front, y=0, z=0; x != back; x = (x + 1) % theQ.length)
if (z < match)
if (x != toRemove[z]) {
newQ[y] = theQ[x];
y++;
} else
z++;
else {
newQ[y] = theQ[x];
y++;
}
theQ = newQ;
front = 0;
back = y;
// match holds the number of things we removed
return match;
}
/**
The canonical toString method.
*/
synchronized public String toString() {
String returnVal = "Queue: ";
if (empty())
return returnVal + "no elements";
for(int i=front; i != back; i = (i + 1) % theQ.length)
returnVal = returnVal + theQ[i].toString() + " ";
return returnVal;
}
}

13
pdf/README.txt Normal file
View File

@@ -0,0 +1,13 @@
Il file SimulatoreJava-BCNNcapitolo4.zip contiene il simulatore presentato nel capitolo 4 del libro di testo
Il file SimulatoreBCNNintelliJ.zip contiene un export da IntelliJ IDEA dello stesso simulatore;
unica differenza: le classi di utilità generale sono contenute in un package "SimUtils"
Il file QueueingTools.xls contiene vari fogli di calcolo che implementano il calcolo dei principali indici
di prestazione per alcune categorie di modelli costituiti da una sola coda (si veda il capitolo 6 del libro di testo).
Per esempio un foglio è dedicato alla M/M/c mentre un altro foglio è dedicato alla M/G/1.
Potete usare questi fogli di calcolo per confrontare i risultati ottenuti con il simulatore e quelli ricavati dalle formule
dei fogli excel, come strumento di verifica del buon funzionamento del simulatore.
Potete anche confrontare i risultati ottenuti con questo simulatore e quelli ottenuti con JMT (Java Modelling Tools), a parità
di parametri e di distribuzione dei tempi di interarrivo e di servizio.

16
pom.xml Normal file
View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.berack</groupId>
<artifactId>valpre</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>23</maven.compiler.source>
<maven.compiler.target>23</maven.compiler.target>
</properties>
</project>