JSSim
JavaScript Discrete Simulation Tool
Version 2
Contents
2
Object-Oriented Programming in JavaScript
9
Input/Output General Guidelines
J. Sklenar
Department of Statistics and Operations
Research
Faculty of Science
University of Malta
JavaScript is a script language interpreted by web browsers. JavaScript is the original name owned by Netscape, a similar language is called JScript by Microsoft. Both are supposed to be compatible with the standard ECMA-262 that is also approved by the ISO as ISO-16262. That’s why the language is also called ECMAScript. Next the name JavaScript will be used. Compatibility with the ECMA standard does not guarantee equal behavior in all browsers, so it is suggested to check pages that use JSSim code in your favorite browser. Note also that currently JSSim supports only client-side applications.
JavaScript is
not a classical class-based strongly typed object-oriented language (OOL) like
for example Simula or Java. In fact it is the opposite. Nevertheless the object
model of JavaScript enables use of all important techniques of object-oriented
programming (OOP), either directly or with some additional support. For example
inheritance has to be programmed explicitly. That’s why the chapter 2 of this
manual shows how to use the techniques of object-oriented programming in JavaScript. Regarding other features of
the language, JavaScript contains everything that we expect in a high-level
language. Description of the language as such is of course out of the scope of
this manual.
A JavaScript programmer is thus making use of a modern programming language that, together with HTML, supports creation of documents that can contain user-friendly input of validated data, any kind of data processing, and lucid presentation of results. Solutions based on JavaScript and HTML are typically placed on the web and made thus available literally to everybody who has a browser supporting particular versions of these two languages. These capabilities have been applied to create various web-hosted problem-solving tools. Such tools can contain simple and medium-scale simulation models. Several simulation models have already been implemented and placed on the web with very encouraging response. Routines used to create these models, including a simple event-oriented simulation engine together with a collection of classes for general use in discrete simulation, have been collected into a tool called JSSim (JavaScript Simulation). This document is a JSSim manual that assumes that the reader is familiar with JavaScript and HTML.
2 Object-Oriented Programming
in JavaScript
In this chapter we assume that the reader is familiar with basic ideas of
object-oriented programming. A very fundamental introduction is available in my
Turbo Pascal page at: http://staff.um.edu.mt/jskl1/turbo.html#OOP
.
Everything is an object
Some authors would not call JavaScript an OOL, but in fact JavaScript programmer works only with objects and their methods and properties. If not stated explicitly, properties mean value attributes, but in JavaScript there is actually very little difference between value attributes – properties and procedure attributes - methods. Due to loose typing a property can become a method and vice versa. Most JavaScript “programs” are short snippets incorporated into HTML documents by using the tag <SCRIPT> that can also reference a separate file with JavaScript code (default extension js). JavaScript code is processed by the browser’s interpreter as a part of the (re)loading process. Such code typically defines functions and declares and initializes global variables. Using OOP terminology, such code is interpreted in the context of the so-called global object. For each browser window or each frame within a window a separate global object is created. So for example a global variable declared by the following statement:
var
expduration = 1000; //default experiment
duration
in fact creates (declares) a property of the global object that can be called directly by its name, but also as this.expduration or window.expduration. The keyword this is a reference (handle) of the current object. Similarly each global function declared by the user is a method of the particular global object. All standard properties and functions are also pre-defined properties of the global objects (for example mathematical functions and constants are accessible through the Math object that is an automatically created property of the global object). What about the statements written directly in <SCRIPT> tags? Here the best analogy is the “life” as defined for Simula class instances. There can be a lot of such code in several <SCRIPT> tags and in js files. All this code is performed in lexical order as the life of the global object (obviously without any possibility to break and postpone its execution). Interpreted JavaScript has only run-time; compile-time does not exist. Still there are two stages: (re)loading is a sort of early or first run-time stage. During this stage the programmer creates all global data that includes “declaration” of prototypes – see later, and creation of global object instances. Second run-time stage is made of execution of functions activated by browser events (like for example pressing a button). Even now, all is done in the context of the so-called call object. Each activation of a function creates a separate call object, so declaration of a local variable (say var x = 0;) in fact creates a property of the call object. Actual parameters of the function call are also considered as properties of the call object (there is another array property arguments that contains all parameters passed to the function, so in JavaScript it is possible to write functions accepting variable number of parameters).
Every function can be a constructor
In JavaScript object instances are created by the operator new similarly as in practically all OOLs:
queue = new
FifoQueue("q1”,0); // new queue
object
The difference between JavaScript and compiled OOLs is the fact that there is no class declaration in JavaScript. So the constructor has much more important role. Unlike constructors of compiled OOLs that basically just initialize the instance, JavaScript constructor actually creates (constructs) an instance by creating its properties and possibly methods. There is no special keyword to write constructors, so each function can potentially be a constructor. We already know that for each function call JavaScript creates a call object. It in fact creates another initially empty object (here we shall call it created object) that can be in the function body referenced by the keyword this. Functions that are not intended to be constructors ignore it. Note that call object and created object are really two distinct objects. For example consider the following statements anywhere in a function body:
var x =
1;
this.x
= 2;
alert(x);
The value displayed will be 1 (property of the call object), alert(this.x) would display 2 (property of the created object). A constructor function is not supposed to return any value, but it can. If it returns an object, the standard created object is ignored and the returned object will be used instead. But there is more: in JavaScript each function is in fact represented by a function object created during parsing a function. With respect to possible use of the function as a constructor, let’s call this object constructor object or simply constructor. Unlike the other two objects associated with a function call (call and created objects) that exist only temporarily during the function execution, constructor object is permanent (it is removed by loading another document). Because it is an object, it can have properties and methods. The most important one is prototype – see the next chapter. Using OOP terminology each constructor (and so each function) has - or can have - the same role as class declaration in compiled OOLs. Whether a particular function really represents a class depends only on its body (constructors are supposed to create properties by statements like the above one: this.x = 2;) and especially on its use after the new operator. Note that constructors can create value properties and methods in unified way:
Note that all instances created by the above constructor will have their own code of the method shift. The obvious requirement is a code stored only once for all instances. In JavaScript this is achieved by prototypes.
Prototypes
Prototype is the property of each function (constructor), so there is one prototype for every class (provided the function is used as a constructor). JavaScript enables objects (instances) to access prototype properties and methods in the same way as its own private properties and methods: o.m() activates the method m of the object o. It can be either private local method of the instance or a prototype method common to all instances of the class of o. Sharing prototype methods by all instances is no problem, but what about value properties? JavaScript avoids clashes and side-effects by making prototype value properties read-only. They are created and initialized at parse time; instances can only read their values. They can be useful as constants common to all instances of the particular class. Creating prototype properties (not typical) and prototype methods thus completes the class definition. Let's summarize: each class is represented by two permanent objects: constructor and prototype (constructor's property) and then there can be any number of instances that can have their own properties and methods and that can access properties and methods of the two permanent objects. Using the prototype paradigm the class point can be implemented in this way:
Now
the code of the method shift is stored only once with obvious consequence -
after its modification all instances will use the modified version.
The two previous paragraphs give a hint how to create the usual four types of properties and methods associated with a certain class:
Instance value properties are created by the constructor (or by a function called by the constructor – see later) using the handle this.
Instance methods can be created either directly by the constructor or preferably by the prototype – see the two above examples.
Class value properties that are associated with the class as such, not with the individual instances can be created as properties of the constructor:
point.count
= 0; // number of created points
Class constants can be properties of either the constructor:
point.maxX
= 800; // maximum x co-ordinate
or the prototype which ensures the read-only access:
point.prototype.maxX
= 800; // maximum x co-ordinate
Class methods associated with the class as such, not with the individual instances can be created as methods of the constructor:
point.distance = function(p1,p2)
{
var dx = p1.x - p2.x;
var dy = p1.y – p2.y;
return Math.sqrt(dx*dx + dy*dy)
};
Note that the above declaration is logical – distance applies to two points, so it is more natural to declare it as a class method and not as an instance method.
Inheritance
Let’s consider only instance value properties and instance methods and let’s create a subclass colorpoint with one more property color and one more method changecolor. Unfortunately we have to consider separately inheritance of value properties and inheritance of methods.
Regarding value properties it is possible to repeat creation of superclass properties in the subclass constructor. There are two reasons against this approach: first there is redundant code and what’s more important, any modification in the superclass must be repeated in all subclasses with obvious danger of inconsistency. The solution is a function used both by the superclass and the subclass:
Inheritance
outlined in the previous example can continue – colorpoint can be used as a
superclass etc. Note that in order to allow inheritance; constructors just call
functions that create the properties. Of course private methods can be
inherited in the same way as value properties.
Methods stored in prototypes can be inherited either by replacing the whole prototype object or by copying the methods. The first method can be used in our example in this way:
colorpoint.prototype = new point(0,0);
The first statement replaces the standard prototype by a point instance; the second statement creates the new method. There are two flaws – first the new prototype has also the two value properties (x and y). It is not a mistake. Assuming that the constructor creates properties with the same names, prototype read-only properties are not visible and the only problem is wasted memory. The second flaw is more serious. All prototypes have a property constructor that is a reference to the function object of the constructor function that has created this object. It can be very useful to check types of instances (like “is” in Simula). Obviously by replacing the standard prototype by another object as in the above example, the constructor property also changes. To get exactly what we want, methods have to be copied from superclass to subclass. The following function uses the fact, that objects in JavaScript can be treated as associative arrays and a special form of the “for” statement based on this fact:
function
inherit(from,to) {
for(var p in
from.prototype)
if (typeof
from.prototype[p] == "function")
to.prototype[p] = from.prototype[p]
};
inherit(point,colorpoint);
The first statement copies all prototype methods; the second statement creates the new method.
Polymorphism
Polymorphism is basically not compatible with strong typing. That’s why classical compiled OOLs introduce late binding through virtual methods that represents probably the most complicated part of OOP. Note that Java does not have virtual methods, but it means that all methods are in fact virtual. Programmer’s comfort is paid by time. Interpreted loosely typed JavaScript is polymorphic by nature. Moreover polymorphism is not limited to inheritance sequences. Consider the next two statements: p = x; p.m(); They will work for any object x that has a method m. JavaScript does not perform any type check, everything is the programmer’s responsibility. So the flexibility is paid by very limited security. That’s why JavaScript can not compete with classical OOLs in large software development projects.
Other techniques
Interpreted JavaScript enables techniques not conceivable in compiled strongly typed OOLs. Among others the following is possible:
Adding instance properties and methods can be a fast alternative to inheritance, especially in case of small number of instances. At any time it is possible to create new properties and methods:
origin = new
point(0,0);
p =
new point(ix,iy);
p.d = point.distance(origin,p); //New property of p
p.dupdate
= function() {
//New method of p
this.d = point.distance(origin,this)
};
Modification of instance properties and methods is also possible. It can be used for example as an alternative to status variables. Instead of testing a status, activate directly the method that has been updated accordingly. It is also possible to change a method into a property and vice versa, but then they have to be treated accordingly.
Partial inheritance is a technique not allowed in OOLs. Nevertheless there are situations when a simplified version of a certain class is required. This technique has been used in JSSim to create a discrete random distribution object as a simplified version of general random distribution object that has already been available. The point is inheriting only some methods (obviously they must be self-sufficient). The following example shows another version of the function inherit - actually the one available in JSSim and its use. The function first tests the number of actual parameters passed to it. If there are two parameters it copies all methods as in the above example. Otherwise it assumes that after the first two object parameters there is a list of strings – names of methods to be copied:
function
inherit(from,to) {
if
(arguments.length == 2) { // Inherit all
for(var
p in from.prototype)
if (typeof from.prototype[p] == "function")
to.prototype[p]
= from.prototype[p]
} else { // Inherit the listed
methods
for
(var i=2; i<arguments.length; i++)
to.prototype[arguments[i]] =
from.prototype[arguments[i]];
}
};
inherit(Distribution,DiscreteDistribution,
'fixtable','last','compareWithLastValue','showTable',
'accept','edit','insert','deleteit','cleartable',
'confirmtable','generate','save','load');
Only the 13 listed methods are
inherited.
JavaScript programmers can use all fundamental techniques of OOP together with new techniques offered by loose JavaScript typing.
![]()
3 JSSim Basic Ideas
JSSim is a collection of JavaScript declarations that together with appropriate HTML documents support user-friendly development of web hosted tools that contain simple and medium scale simulation models. Simulation models based on JSSim are incorporated into HTML documents. HTML code implements the link between the model and the user – it is used for inputs and outputs of the model and to control it. JavaScript code is made of two parts – JSSim JavaScript source file(s) and the user JavaScript code, preferably also in a separate file. All JSSim declarations are included in the file jssim.js, so a heading of the HTML document is supposed to contain the following script tag:
<SCRIPT LANGUAGE="JavaScript"
SRC="jssim.js"></SCRIPT>
JSSim also exist as a collection of separate source files, so in order to save loading time of the document it is possible to include only files with used declarations. User JavaScript code can be written either directly in a script tag as it is done in the demo examples, or preferably in a separate js file referenced by a script tag similar to the one above. There will also be short snippets of JavaSript code written directly in HTML tags – for example validation of input data. These snippets can be just calls to functions written either by the user or standard JSSim validation functions – see later.
Facilities found in languages and tools for programming discrete simulation models can be classified into the following main groups:
-
Time
control, synchronization and
communication of processes
-
Generation
of random numbers
-
Transparent
collection of statistical data and statistical analysis
-
Advanced
data structures
-
User-friendly
Input and Output
Next chapters will summarize the implementation of these facilities in JSSim together with specific functions given by the web-hosted nature of the models.
To select the time control of JSSim models we have considered only the
two commonly used approaches. While the process-oriented discrete
simulation represents the most advanced way of modeling the dynamics of complex
systems, the classical event-oriented approach is simpler and easier to
learn and to implement. That’s why it has been chosen for a JavaScript based
tool that is not intended for large simulation studies. Assuming that the
reader is familiar with the event-oriented principle, these are the basic
facts: During (re)loading of the document the engine
creates two global variables: the time
and the empty sequencing set (SQS – name borrowed from Simula). Events
are represented by event notices created by the user and stored in the
SQS. Each event notice has the
occurrence time of the event and any other user-defined
data. The engine assigns the time when the event is scheduled. From the user’s
point of view, the SQS is a list of event notices ordered by the time of
occurrence in increasing way. After activation, the engine repeatedly removes
the first event notice from SQS, updates the model time, and activates a user
routine that is given the reference to the event notice. Simulation ends by the
empty SQS or by any user supplied condition. These are the engine routines that
are called from the user’s part of the simulation model:
initialize_run() is a routine that clears the SQS (the previous experiment may have finished with nonempty SQS) and sets the model time to zero. It should be called at the beginning of the model initialization.
evnotice() is the event notice constructor. It returns an object with the time property that is used later by the engine and should not be accessed by the user. The user can add any other properties to distinguish between types of events and to store other model dependent data.
schedule(event,t) schedules the event whose notice is the first parameter at the time given by the second parameter. It is not possible to go back in time, so for t less than modeltime() the event is scheduled at modeltime().
modeltime() is the current time of the model. Scheduling an event e after a delay d is performed as follows:
schedule(e,modeltime()+d)
cancel(event) cancels a scheduled event. The function returns a Boolean value that reports whether canceling was successful – the function returns false if event has not been scheduled.
sim_run(stats,length,run,expers) starts the simulation experiment. This routine should be called after the model initialization that has to schedule at least the first event. The first two arguments control the progress reporting in the status bar. If stats is true, time progress will be reported, length is shown as the duration of the experiment. If stats is false, only the run number is shown. The last two arguments are the current run number and the total number of repetitions. The routine ends by reaching the empty SQS or by the user supplied terminating condition - the user’s routine finish_run().
simulation_run(stats,length) starts the simulation experiment. It is the old version of the above routine before repetitions were implemented. It is kept for compatibility of older models.
The above routines are
common to all simulation models. Model specific behavior is implemented by two
routines that have to be supplied together with the code (preferably
also a routine) that starts the simulation. These are the routines (together
with examples) that represent the user’s part of the simulation control:
finish_run() tests whether simulation should be terminated. It is called by the engine after updating the model time just before activating the next event. It can just test the time against the experiment duration or it can implement a more complicated terminating condition, like for example serving a given number of customers. The following is the function of a model where the experiment is finished by reaching its duration runlength:
function finish_run() {
return
(modeltime()>runlength)
};
eventroutine(event) is activated by the engine each time an event is to occur. The routine is given the reference to the event notice that has been removed from the SQS. The rest is the user's responsibility. Typically there will be some properties created by the user used to switch between various types of events. It might be a good idea to keep this routine short and simple and to write routines for various types of events similarly as they are written in event oriented simulation languages. The following is the function of a model with two types of events. Note that the event notices have two user-defined properties: eventtype and servnum (the server number):
function eventroutine(event) {
switch
(event.eventtype) {
case 1: next_arrival(); break;
case 2: end_of_service(event.servnum); break;
default:
alert("Wrong eventtype: " + event.eventtype)
}
};
The start of
simulation has also to be programmed. For example it can be a function
activated by pressing a button “Run”. This function is supposed to perform the
following activities exactly in this order:
- Initialization of the engine by initialize_run()
- Model specific initialization
- Starting simulation by simulation_run()
- Model specific experiment evaluation.
The following is an example of a function activated by pressing the button “Run” and its link to HTML for the single queue simulation model version #1.
<INPUT
TYPE="button" VALUE="Run" onClick="simulation()">
function simulation() { //
Simulatiom experiment
if
((arrival.disttype=="User") && !(arrival.confirmed)) {
alert("Can't
start simulation. Arrival intervals table
has not been
confirmed.");
return false;
};
if ((service.disttype=="User")
&& !(service.confirmed)) {
alert("Can't
start simulation. Service duration table
has not been
confirmed.");
return false;
};
initialization(); // Model global initialization
runnumber = 1;
while
(runnumber<=numofexp) { //
Repetitions loop
initialize_run(); // This prepares the engine
run_init(); // Run initialization
nextarrival(); // Scheduling first arrival
sim_run(showstatus,runlength,runnumber,numofexp);
// This starts the
simulation
lqe.update(queue.average());
// queue length statistics
wqe.update(wtime.average());
// queue time statistics
le.update(ssize.average()); // system size statistics
we.update(stime.average()); // system time statistics
runnumber++;
};
evaluation(); // Experiment evaluation
return true;
};
JSSim contains a rather complex class used to generate instances (objects) that represent random numbers. These can have either a theoretical distribution, but primarily they are supposed to contain tables used to generate values with a general (for example experimentally obtained) distribution. Methods are available for entering and editing such tables. Working with empirical tables is user-friendly; table entries can be modified, inserted and deleted. Table can be entered as a cdf (cumulative distribution function) or a pdf (probability distribution function). In both cases there is a re-calculation to the other type. During editing tables can be left temporarily inconsistent, but before use a table has to be checked and confirmed. Both values and cdf entries must form non-decreasing sequences. Sum of probabilities has to be 1; a confirmation method offers adjustment of the last entry if the sum is smaller. Associated HTML text contains a help that explains the basic ideas and the inversion method, so only basic knowledge of probability is assumed. Large tables can be saved and loaded (provided cookies are enabled in the browser). Figure 1 shows a table created by HTML used to enter parameters of a random variable. The controls are self-explaining. Figure 1 shows the situation just after confirmation of an empirical cdf table by pressing the button “Check & Confirm”. Inversion is used for generation that can be either discrete or interpolated. The technique of restricted inheritance (simplification) mentioned earlier was used do declare a simplified version of this class for generation of discrete random numbers with empirical distribution only. Its instances have been used for example to represent random movements of customers in queueing networks. Work with random numbers is very simple. Instances are first created by statements similar to the following one located typically in the head code that is interpreted during loading of the document:
var arrival = new Distribution("a1");
The method generaten(n) returns the random values generated by the random stream n. So during simulation statements similar to the next one are used:
var x = arrival.generaten(1);

Figure 1: Entering parameters of a random variable
Initially JSSim used the standard JavaScript random generator Math.random(). Later a Linear Congruential Generator (LCG) has been implemented with constants known as MINSTD (Minimum Standard) that passed all usual tests. JSSim contains routines for initialization and use of any number of random streams, for details see the code. To keep compatibility, the random objects now contain two generation methods. One is using the standard generator Math.random(), the other one is using a JSSim random stream of a given number.
The following is the class summary of the random object that lists the constructor, the value properties that might be useful, and the methods. Next we shall keep this format. For more details see the JavaScript code and the examples.
Class
Distribution
Constructor
Distribution(name) .name = object and screen text name
Properties
status user table distribution status
confirmed whether user distribution has been
confirmed
disttype type of distribution
enterMode entering mode (pdf, cdf)
generMode generation mode (continuous,
discrete)
Methods
scrupdate() screen update
update(index) internal update
index = distribution
type
testpar1(tx) testing first distribution parameter
tx = tested value
(text)
testpar2(tx)
testing second distribution
parameter
tx = tested value
(text)
fixtable() conversion pdf – cdf
last() index of last table entry
compareWithLastValue(textElement) testing next table entry
textElement = the
text value
showTable() converting table to text form
accept(tx,tp) acceptind value,probability pair
tx = value
tp = probability (or
cdf value)
edit() editing a table entry
insert() inserting a table entry
deleteit() deleting a table entry
cleartable() erasing the table and data
confirmtable() checking the table
generate() generating
next random value by using the standard JavaScript generator Math.random()
generaten(n) generating
next random value by using the native JSSim LCG generator
n = number of random stream used
toString() converting all parameters to string
save(cn) saving to a cookie
cn = cookie name
load(cn)
loading from a cookie
cn = cookie name
fromString(cv) extracting parameters from a string
cv = string
Class
DiscreteDistribution
Constructor
DiscreteDistribution(name) name = object and screen text name
Properties
status user distribution status
confirmed whether user distribution has been
confirmed
disttype type of distribution
enterMode entering mode (pdf, cdf)
generMode generation mode (continuous,
discrete)
Methods
scrupdate() screen update
fixtable() conversion pdf – cdf
last() index of last table entry
compareWithLastValue(textElement) testing next table entry
textElement = the
text value
showTable() converting table to text form
accept(tx,tp) acceptind value,probability pair
tx = value
tp = probability (or
cdf value)
edit() editing a table entry
insert() inserting a table entry
deleteit() deleting a table entry
cleartable() erasing the table and data
confirmtable() checking the table
generate() generating
next random value by using the standard JavaScript generator Math.random()
generaten(n) generating
next random value by using the native JSSim LCG generator
n = number of random stream used
toString() converting all parameters to string
save(cn) saving to a cookie
cn = cookie name
load(cn)
loading from a cookie
cn = cookie name
fromString(cv) extracting parameters from a string
cv = string
To collect statistics of a
certain variable x automatically, it is necessary to update certain
figures (like for example its time integral) after each updating of x.
In other words all assignment statements that have x on the left side
must also activate a certain routine that updates what is necessary. Simulation
languages like Simscript do it automatically (Simscript calls this mechanism left monitoring), but
there is of course nothing like that in JavaScript. Transparent collection of statistical data and simple statistical
analysis are implemented by the classes Accumulator and Tally (Simscript terminology is used). The instances of these two classes
are basically real variables with transparent collection of statistics. The
consequence for the user is the difference in the form of the assignment
statement. The usual a = x has to be
replaced by a method call a.updateto(x). They differ in time treatment.
Tally ignores the
time; the statistics is based on the collection of the assigned values only.
Objects of the class Tally are thus used for figures whose statistics does not
depend on time integrals. As an example consider time spent in a queue. It is
calculated for each customer at the beginning of the service by subtracting the
time when the customer arrived to the queue from the current time. Each
calculation then updates the statistical object. The following has to be done:
1) Tally object is created, typically by the head code:
waitingtime
= new tally();
2) Before starting the experiment the Tally object has to be
initialized:
waitingtime.initiate();
3) For each customer it is
updated similarly as follows where cust
is the customer handle and sertimein is the arrival time:
waitingtime.update(modeltime() - cust.ser