SIMULA PACKAGES = NESTED CLASSES
Go back to Author's home page
Simula I = Process oriented discrete simulation language based on Algol 60. (1964 - 1965) Simulation language.
Simula = Simula 67 (The number is not used any more, because Simula I has not been used for a very long time).
(Source: Jan Rune Holmevik: Compiling Simula - see REFERENCES)
1952 Kristen Nygaard starts work in Operations Research including writing simulation models. Problem: how to conceptualize complex real world. Since the very beginning Simula intended to be both system description and programming language.
1960 Algol 60 with its true recursive block mechanism structure based on stack principle. All important control structures introduced. Simula intended as a package with preprocessor to Algol 60.
1962 Ole-Johan Dahl and Kristen Nygaard meet in Norwegian Computing Center (NCC) in Oslo. First formal language proposal presented at the IFIP 62 World Congress in Munich.
1962 Simula project supported by UNIVAC, that resulted in UNIVAC 1107 installation in NCC in 1963.
1963 Conflict between strict Algol stack mechanism and Simula's sophisticated simulation facilities oriented more to queue principle. Preprocessor idea abandoned, Simula to be an independent Algol based language.
1963 Ole-Johan Dahl works on a new storage allocation scheme based on a two dimensional list of free areas.
1964 Original idea of passive customers moving through a network of active components (activity approach) became a limiting factor. Other way round possible - active customers moving through a passive network. This resulted in a unifying general process concept:
1964 First prototype of Simula compiler running on NCC's UNIVAC 1107 in December, Simula I manual appeared in May 1965. During the first year Simula applied to a wide area of Operations Research problems.
(Source: Jan Rune Holmevik: Compiling Simula - see REFERENCES)
1965,66 Simula I used in Sweden, Germany, USA (Burroughs B5500), Soviet Union (URAL 16) and other countries. Effort to introduce and teach the language.
1965 Tony Hoare's record class concept presented in Algol bulletin. After a careful examination, Nygaard and Dahl accept the ideas, but a sort of generalized concept still missing.
1966 Introducing the idea of prefixing. Processes (later objects) made of two layers: prefix layer, main layer. Idea of subclasses. Nygaard and Dahl start work on a new general high-level language.
1967 (May). Simula 67 officially introduced by Dahl and Nygaard at the IFIP TC 2 Working Conference on Simulation Languages in Lysebu near Oslo.
1967 (June). Definition of Simula 67 standard called Common Base Standard.
1968 First meeting of Simula Standards Group (SSG). After accepting string handling and I/O done by Bjorn Myhrhaug, Simula formally frozen.
1973 Association of Simula Users (ASU) founded. Simula used in more than 250 sites that year.
Implementations:
1969 CDC 3300, 3600 (Norway - University of Oslo, NDRE)
1971 UNIVAC 1100 (NCC)
1972 IBM 360/370 (NCC)
1972 CII 10070, IRIS 80 (France)
1973/74 CDC 6000 (France, Netherlands), CDC Cyber 70 (NDRE)
1975 DEC 10 (Sweden) etc.
Periodicals:
Proceedings of annual ASU conferences (first 1973 Oslo, last 1997 Slovakia, next 1998 Kiel Germany)
ASU Newsletter
Integer Short Integer
Real Long Real
Boolean Character
Object Reference Declaration: Ref( Object Identifier) (None is the trivial value)
Text Constants: "A", "Simula", Notext
Text is conceptually a class instance, that has its attributes and methods.
Methods:
Boolean Procedure Constant; (True if constant)
Text Procedure Main; (Main string - the text is a part of Main)
Integer Procedure Start; (Starting position in Main)
Integer Procedure Length; (Number of characters)
Integer Procedure Pos; (Current position)
Procedure SetPos(i); Integer i; (Changing position)
Boolean Procedure More; (True if Pos <= Length)
Character Procedure GetChar; (Character from Pos)
Procedure PutChar(c); Character c; (Storing character to Pos)
Text Procedure Sub(i, n); Integer i,n; (Substring at i of length n)
Text Procedure Strip; (Removes right spaces)
De-editing Methods:
Integer Procedure GetInt; (Reads integer)
Long Real Procedure GetReal; (Reads real)
Integer Procedure GetFrac; (Like GetInt, ignores spaces)
Editing methods:
Procedure PutInt(i); Integer i; (Writes integer value)
Procedure PutFix(i, n); Integer i,n; (Writes decimal value)
Procedure PutReal(r, n); Long Real r; Integer n; (Writes in scientific format)
Procedure PutFrac(i, n); Integer i,n; (Groups of 3, spaces)
Text generation:
Text Procedure Blanks(n); Integer n; (Returns n blanks)
Text Procedure Copy(T); Text T; (Returns a copy of T)
Examples of arrays declared in blocks (n, m, a, b are global variables):
Integer Array MyList (1:100);
Array Matrix (1:n, 1:m); (Implicit type is real)
Character Array Buffer(1: If a>b then a else b);
Assignment := Examples: X := If a>b Then a Else b ; X:=Y:=0; ( ** available )
Reference Assignment :- Examples: Queue :- New Head; T :- Blanks(80);
Procedure
Go to Goto
Begin ... End;
If ... Then ... ; If ... Then ... Else ... ;
Switch Example:
Switch Target := L1, L2, L3, ... ; Goto Target( Index_expression ); L1: ... L2: ...
While ... do ... ;
For (very general) Example:
Begin
Integer i;
For i:= 1, 13, 20 step 10 until 40, 70, i+1 while i lt 76,
100 step 50 until 250, 1000, 1500 do OutInt(i,5);
End;
Output: 1 13 20 30 40 70 71 72 73 74 75 100 150 200 250 1000 1500
Parameter Passing Modes:

Example procedure with two input and one output parameters: (Displays a right indented text)
Begin
Procedure RightText(T, N, FitsIn); Text T; Integer N;
Name FitsIn; Boolean FitsIn;
Begin
Integer I;
FitsIn := N >= T.Length;
For i:=1 step 1 until N-T.Length do OutText(" ");
OutText(T)
End of RightText;
RightText("Short", 30); OutImage;
RightText("And the long one", 30);
End of Program;Output:
Short
And the long one
Example integer function with two input parameters: (Computes the greatest common divisor)
Begin
Integer Procedure GCD(M, N); Integer M, N;
Begin
While M<>N do
If M<N then N := N - M else M := M - N;
GCD := M
End of GCD;
Integer A, B;
OutText("Enter an integer number: "); OutImage; A := InInt;
OutText("Enter an integer number: "); OutImage; B := InInt;
OutText("Greatest Common Divisor of your numbers is ");
OutInt(GCD(A,B), 4); OutImage;
End of Program;
Note: A function may be called as if it were a typeless procedure.

Class Rectangle (Width, Height); Real Width, Height;
! Class with two parameters;
Begin
Real Area, Perimeter; ! Attributes;
Procedure Update; ! Methods (Can be Virtual);
Begin
Area := Width * Height;
Perimeter := 2*(Width + Height)
End of Update;
Boolean Procedure IsSquare;
IsSquare := Width=Height;
Update; ! Life of rectangle started at creation;
OutText("Rectangle created: "); OutFix(Width,2,6);
OutFix(Height,2,6); OutImage
End of Rectangle;
Ref(Rectangle) R; (Class reference variable)
...
R :- New Rectangle(50, 40); Activities involved in this object generation:
Memory allocation, reference stored to R.
Copying values to parameters (value passing only).
Starting the object's body (life rules).
Rectangle Class LocRectangle (X, Y); Integer X, Y; Begin ! More parameters; Boolean Tall; ! More attributes;
Procedure Move (Dx, Dy); Integer Dx, Dy; ! More methods;
Begin
X := X + Dx; Y := Y + Dy
End of Move;
! Additional life rules;
Tall := Height > Width;
OutText("Located at: "); OutFix(X,2,6); OutFix(Y,2,6); OutImage
End of LocRectangle;
Ref(Rectangle) R; (Class reference variables)
Ref(LocRectangle) LR;
...
R :- New Rectangle(50, 40);
LR :- New LocRectangle(20, 30, 100, 200); (Note that also parameters for the parent class are given)
Activities involved in the above object generation:
Memory allocation, reference stored to LR.
Copying values to all parameters (parent class first).
Starting the body of the parent class, then the subclass.
This can be generalized to prefix sequence of any length:
Class A; Begin ... LifeA End;
A Class B; Begin ... LifeB End;
B Class C; Begin ... LifeC End;
Ref(C) X;
...
X :- New C;
If not changed by Inner - see next paragraph, the sequence of activities involved in the above object generation is:
LifeA LifeB LifeC
Breaking life rules by the statement Inner:
Example declarations:
Class A; Begin LifeA1 Inner; LifeA2 End;
A Class B; Begin LifeB1 Inner; LifeB2 End;
B Class C; Begin LifeC1 Inner; LifeC2 End;
Ref(C) X;
X :- New C;
The sequence of activities involved in the above object generation is:
LifeA1 LifeB1 LifeC1 (Inner in the life of C ignored) LifeC2 LifeB2 LifeA2
Notes:
1) Missing Inner is the same as Inner just before the class end.
2) Mostly one Inner is allowed in the class body.
Let's assume a program with the following structure:
Begin Class A(P); Integer P; Begin LifeA1 Inner; LifeA2 End;
Part1
A(3) Begin
Block body
End;
Part2
End;
Activities involved in the execution of the above prefixed block:
Creating a class instance of A.
Copying values to its parameter(s).
Starting the body of the class, that includes execution of the block code.
So in the above program the sequence of operations is this:
Part1 LifeA1 Block body LifeA2 Part2
Prefixed block is conceptually a class instance without a name that has:
- parameters of the prefix class
- more attributes (class attributes + local block variables)
- more methods (class methods + local block procedures)
- more complex life rules (class body + block body).
The following text is based on these declarations:
Class A; Begin Ref(A) Link; Procedure Show; ... End;
A Class B; Begin Procedure Show; ... End;
B Class C; Begin Procedure Show; ... End;
Ref(A) XA, First, Current; Ref(B) XB; Ref(C) XC;
1. Qualification by the Inspect statement
a) Simple
Inspect XA do Show; does basically the same as XA.Show;
The difference is that with Inspect if XA = None, the statement after do is ignored. If XA = None, XA.Show results in a run time error.
b) Testing None by the clause Otherwise
Inspect XA do Begin
Show; ...
End
Otherwise Begin
OutText("Sorry, XA not created"); OutImage
End;
c) Testing type by the clause When
Displaying a linked list made of various items of types A, B, and C, whose head pointer is in First:
Current :- First;
While Current ne None do begin
Inspect Current
When A do Show ! Show of A;
When B do Show ! Show of B;
When C do Show ! Show of C;
Otherwise OutText("Not a (sub)class of A");
OutImage;
Current :- Current.Link
End While;
2. Instantaneous Qualification by the Qua clause
Assume these statements based on the above declarations:
XA :- New B; XB :- New B; XA.Show; ! Show of A; XA Qua B.Show; ! Show of B - it is possible to go down; XB Qua A.Show; ! Show of A - it is possible to go up; XA :- New A; XA Qua B.Show; ! This is illegal - attributes of B do not exist;
Note: Normal properties of a reference variable qualified to B declared as Ref(B) XB :
The following code is a method of A that adds the object to the list First:
Procedure Add_to_List(First); Name First; Ref(A) First; Begin Link :- First; First :- This A End;
4. Testing Qualification by Is and In
If XB is B then
OutText("XB is B")
Else
OutText("XB is either subclass of B or None");
If XA in B then
OutText("XA is either B or its subclass")
Else
OutText("XA is either A or None");
5. Protecting attributes
Hidden attributes can be used only in the body of the class where they are declared.

! The program defines the main class "Geometry". ;! It represents a theory with terms "point, rectangle, circle, and line".; Class Geometry; Begin Class Point(X,Y); Real X,Y; Begin Procedure Print; Begin ... End; Procedure Shift(Dx, Dy); Real Dx, Dy; Begin ... End; Print; ! Life of point; End of Point; Class Rectangle(RecName, Width, Height); Text RecName; Real Width, Height; Begin Real Area, Perimeter; Procedure Update; Begin ... End; Procedure Show; Begin ... End; Update; Show; ! Life of rectangle; End of Rectangle; Class Circle(Radius, Center); Real Radius; Ref(Point) Center; Begin Procedure Shift(Dx, Dy); Real Dx, Dy; Begin ... End; OutText("Circle created at "); ! Life of circle; Center.Print; End of Circle; Class Line(M,N); Ref(Point) M,N; ! Line defined by two points; Begin Real Slope; Slope := ... ; ! Life of line; End of Line; !Variables declared in geometry: ; Ref(Point) Origin, A, B; Ref(Line) X,Y; !Life of geometry: ; Origin :- New Point(0,0); ! Creating the origin; A :- New Point(1,0); B :- New Point(0,1); X :- New Line(Origin, A); ! Creating the axes; Y :- New Line(Origin, B); OutText("*** Geometry initialized ***"); OutImage; End of Geometry;
External Class Geometry;Geometry Begin ! Subclasses declared in the prefixed block: ; Point Class Color_Point(C); Character C; Begin ... End; Rectangle Class Square; Begin ... End; ! Variables declared in the prefixed block: ; Ref(Color_Point) A1; Ref(Point) C, D; Ref(Circle) K; Ref(Line) E, F; Ref(Rectangle) R1; Ref(Square) S1; ! Block body: ; C :- New Point(5,6); D :- New Point(20,30); A1 :- New Color_Point(3, 4, 'G'); K :- New Circle(10, C); E :- New Line(C, D); F :- X; K.Shift (1,1); R1 :- New Rectangle("Rec_R1", 5, 4); S1 :- New Square("Square_S1", 4, 6); S1.Show; End of prefixed block;

BeginClass Environment; ... Environment Class BasicIO ... ; Begin Ref(InFile) SysIn; Ref(OutFile) SysOut; ... Class Simset ... ; Simset Class Simulation ... ; Procedure Terminate_Program; Begin ... ; GoTo STOP End; ... SysIn :- New InFile ( ... ); SysOut :- New PrintFile ( ... ); SysIn.Open ( ... ); SysOut.Open ( ... ); Inner; ! This starts the user program; STOP: SysIn.Close ( ... ); SysOut.Close ( ... ) End BasicIO;
BasicIO BeginInspect SysIn do Inspect SysOut do
Begin ! User program starts by this begin;User statements End; ! Last line of user program;
End;End;


removes the last item from Queue1 and inserts it at the beginning of Queue2.

BeginBoolean Mate; Ref(Player) White, Black, Winner; Integer Seed; Class Player(PName); Text PName; Begin Ref(Player) Opponent; Integer Move; ! The life follows; Detach; OutText(PName); OutText("'s First Move"); OutImage; Resume(Opponent); OutText(PName); OutText("'s Second Move"); OutImage; Resume(Opponent); Move := 2; While not Mate do begin Move := Move+1; OutText(PName); OutText("'s Move # "); OutInt(Move,3); OutImage; If Draw(0.3,Seed) then begin Mate := true; Winner :- This Player; End If; Resume(Opponent); End While; End of Player; Begin ! QPS head; OutText("Creating Players, Starting the white one"); OutImage; White :- New Player("White"); Black :- New Player("Black"); White.Opponent :- Black; Black.Opponent :- White; Seed := 17; Resume(White); OutText("Finish: "); OutText(Winner.PName); OutText(" won in move"); OutInt(Winner.Move,3); OutImage; End of QPS End of program;
Creating Players, Starting the white oneWhite's First Move Black's First Move White's Second Move Black's Second Move White's Move # 3 Black's Move # 3 White's Move # 4 Black's Move # 4 Finish: Black won in move 4
BeginBoolean Mate; Ref(Player) White,Black,Winner; Integer Seed; Class Player(PName); Text PName; Begin Ref(Player) Opponent; Integer Move; ! The life follows; Detach; OutText(PName); OutText("'s First Move"); OutImage; Detach; OutText(PName); OutText("'s Second Move"); OutImage; Detach; Move := 2; While true do begin Move := Move+1; OutText(PName); OutText("'s Move # "); OutInt(Move,3); OutImage; If Draw(0.05,Seed) then begin Mate := true; Winner :- This Player; end; Detach; End While; End Player; Begin OutText("Creating Players, Starting the game"); OutImage; White :- New Player("White"); Black :- New Player("Black"); White.Opponent :- Black; Black.Opponent :- White; Seed := 11; While not Mate do begin Call(White); If not Mate then Call(Black) End While; OutText("Finish: "); OutText(Winner.PName); OutText(" won in move"); OutInt(Winner.Move,3); OutImage; End End;
Creating Players, Starting the gameWhite's First Move Black's First Move White's Second Move Black's Second Move White's Move # 3 Black's Move # 3 White's Move # 4 Black's Move # 4 White's Move # 5 Black's Move # 5 White's Move # 6 Finish: White won in move 6
Class Chess; ! Main class with local: Player, Referee;Begin Boolean Mate; Ref(Player) White,Black,Winner; Ref(Referee) Master; Integer Seed; Class Player(PName); Text PName; Begin Ref(Player) Opponent; Integer Move; ! The life of Player; Detach; OutText(PName); OutText("'s First Move"); OutImage; Detach; OutText(PName); OutText("'s Second Move"); OutImage; Detach; Move := 2; While true do begin Move := Move+1; OutText(PName); OutText("'s Move # "); OutInt(Move,3); OutImage; If Draw(0.05,Seed) then begin Mate := true; Winner :- This Player; end; Detach; End While; End Player; Class Referee; Begin Detach; While not Mate do begin Call(White); If not Mate then Call(Black) End While End of Referee; Begin ! Life of Chess; Seed := 11; OutText("Creating the Players and the Master"); OutImage; White :- New Player("White"); Black :- New Player("Black"); White.Opponent :- Black; Black.Opponent :- White; Master :- New Referee; End End of Chess;
The next program uses the main class Chess:
External Class Chess;
Chess Begin
OutText("Resuming the Master"); OutImage;
Resume(Master);
OutText("Finish: "); OutText(Winner.PName);
OutText(" won in move"); OutInt(Winner.Move,3); OutImage;
End of Program;
Creating the Players and the MasterResuming the Master White's First Move Black's First Move White's Second Move Black's Second Move White's Move # 3 Black's Move # 3 White's Move # 4 Black's Move # 4 White's Move # 5 Black's Move # 5 White's Move # 6 Finish: White won in move 6


! Active customer approach;
Simulation Begin
Real TrialDuration; ! Experiment length [min];
Ref(Head) Queue; ! The queue;
Integer Servers; ! Total number of servers;
Integer BusyServers; ! Numbers of working servers;
Integer TrialSeedG, TrialSeedS; ! Seeds of random generators;
Long Real TotalTime, TimeSpent; ! Variables for statistics;
Integer CustomersOut; ! Number of served customers;
Real MinInt, MaxInt; ! Uniform interval between arrivals;
Real SMean, SStd; ! Normal service duration;
Process Class Generator;
Begin
While true do begin
Activate New Customer(Time); ! Time is the current (arrival) time;
! Interval between arrivals: ;
Hold(Uniform(MinInt, MaxInt, TrialSeedG));
End While;
End of Generator;
Process Class Customer(Arrival); Real Arrival;
Begin
Ref(Customer) Next;
If not Queue.Empty or (BusyServers >= Servers) then
Wait(Queue); ! Customer has to wait in the Queue;
! Service can start: ;
BusyServers := BusyServers + 1; ! Seize a server;
! This is the teller service: ;
Hold(Normal(SMean, SStd, TrialSeedS));
BusyServers := BusyServers - 1; ! Release the server;
If not Queue.Empty then begin
Next :- Queue.First;
Next.Out; ! First from Queue served;
Activate Next after Current;
End If;
CustomersOut := CustomersOut + 1; ! Statistics;
TotalTime := TotalTime + (Time - Arrival);
End of Customer;
! MAIN program body: ;
TrialSeedG := 7; TrialSeedS := 23; ! Seeds for random variables;
MinInt := 1; MaxInt := 3; ! Min and Max intervals;
SMean := 8; SStd := 2; ! Random normal servers;
OutText("Enter the number of Servers : "); OutImage;
Servers := InInt; ! Initial numbers;
TrialDuration := 600; ! Other variables initialized to 0;
Queue :- New Head; ! Create an empty queue;
Activate New Generator; ! This starts the experiment;
Hold(TrialDuration); ! Experiment duration;
TimeSpent := TotalTime/CustomersOut;
OutText("Average time spent in the system: ");
OutFix(TimeSpent, 3, 10); OutImage;
InImage
End of program;
! Active server approach;
Simulation Begin
Real TrialDuration; ! Experiment length [min];
Ref(Head) Queue; ! The queue;
Integer Servers; ! Total number of servers;
Integer TrialSeedG, TrialSeedS; ! Seeds of random generators;
Long Real TotalTime, TimeSpent; ! Variables for statistics;
Integer CustomersOut; ! Number of served customers;
Real MinInt, MaxInt; ! Uniform interval between arrivals;
Real SMean, SStd; ! Normal service duration;
Ref(Server) Array ServBank(1:10); ! Max. number of servers is 10;
Integer i;
Process Class Generator;
Begin
While true do begin
Activate New Customer(Time);
! Interval between arrivals: ;
Hold(Uniform(MinInt, MaxInt, TrialSeedG));
End While;
End of Generator;
Process Class Server;
Begin
Ref(Customer) ServedOne;
While true do
If not Queue.Empty then begin
ServedOne :- Queue.First;
ServedOne.Out; ! First from Queue served;
Hold(Normal(SMean, SStd, TrialSeedS));
Activate ServedOne after Current
end
Else
Passivate;
End of Server;
Process Class Customer(Arrival); Real Arrival;
Begin
For i:=1 step 1 until Servers do
If ServBank(i).Idle then
Activate ServBank(i) after Current;
Wait(Queue);
! Service finished: ;
CustomersOut := CustomersOut + 1; ! Statistics;
TotalTime := TotalTime + Time - Arrival;
End of Customer;
! MAIN program body: ;
TrialSeedG := 7; TrialSeedS := 23; ! Seeds for random variables;
MinInt := 1; MaxInt := 3; ! Min and Max intervals;
SMean := 8; SStd := 2; ! Random normal servers;
OutText("Enter the number of Servers : "); OutImage;
Servers := InInt; ! Initial numbers;
TrialDuration := 600;
Queue :- New Head;
For i:=1 step 1 until Servers do begin
ServBank(i) :- New Server;
Activate ServBank(i) ! Create and activate all servers;
End For;
Activate New Generator; ! This starts the experiment;
Hold(TrialDuration); ! Experiment duration;
TimeSpent := TotalTime / CustomersOut;
OutText("Average time spent in the system: ");
OutFix(TimeSpent, 3, 10); OutImage;
InImage
End of program;
Begin
Boolean Mate;
Ref(Player) White, Black, Winner;
Integer Seed;
Class Player(PName); Text PName;
Begin
Ref(Player) Opponent;
Integer Move;
Procedure TestStrategy;
Begin
Class TestPlayer ... ;
Begin
! Internal experiment, similar to the outer QPS;
...
End of internal QPS;
End of TestStrategy;
! The life of Player;
Detach;
TestStrategy;
OutText(PName); OutText("'s First Move"); OutImage;
Resume(Opponent);
TestStrategy;
OutText(PName); OutText("'s Second Move"); OutImage;
Resume(Opponent);
Move := 2;
While not Mate do begin
Move := Move+1;
TestStrategy;
OutText(PName); OutText("'s Move # ");
OutInt(Move,3); OutImage;
If Draw(0.3,Seed) then begin
Mate := true;
Winner :- This Player;
End If;
Resume(Opponent);
End While;
End of Player;
Begin ! This block is the outer QPS head;
OutText("Creating Players, Starting the white one"); OutImage;
White :- New Player("White");
Black :- New Player("Black");
White.Opponent :- Black;
Black.Opponent :- White;
Seed := 17;
Resume(White);
OutText("Finish: "); OutText(Winner.PName);
OutText(" won in move"); OutInt(Winner.Move,3); OutImage;
End of outer QPS;
End of program;


Simulation Begin
Declaration of global variables
Process Class Generator; Begin ... End;
Process Class Customer; Begin ... End;
Initialize the global experiment
For Period:=1 step 1 until 3 do begin
For Trial:=1 step 1 until MaxClerks do
Simulation Begin
Declaration of internal global variables
Process Class Igenerator; Begin ... end;
Process Class Icustomer; Begin ... End;
Perform and evaluate one inner experiment
End of internal simulation;
Show results of internal experiments;
Select the best numbers of tellers and cashiers;
Perform a part of outer experiment for this period
End For;
Evaluate the global experiment
End of program;
The next program is the nested simulation model with the above structure.
! NESTED Simulation using the Simula's class SIMULATION ;
! ;
! The example is a model of a bank. Customers are first ;
! served by tellers, then by cashiers. ;
! The input rate changes in three periods: there is a busy ;
! period, then an idle period and again a busy one. ;
! For each period the repeated inner simulation experiment ;
! simulates the first queue for the particular input rate ;
! and for various numbers of servers. Then it shows the ;
! results (average time spent at the first server) and ;
! prompts the user for the number of tellers and the number;
! of cashiers. Tellers always finish a service that has ;
! already started. The simulation should find the ;
! time customers spend in the bank (average and maximum) ;
! for various numbers of clerks in the three periods. ;
! ;
Simulation Begin
! Global variables: ;
Integer Period,Trial; ! Period, Trial number;
Real Array MinInt,MaxInt(1:3); ! Min and Max intervals;
Real Array Duration(1:3); ! Duration of periods [min];
Ref(Head) Queue1,Queue2; ! The two queues;
Integer MaxClerks, Tellers, Cashiers; ! Total numbers;
Integer BusyTellers, BusyCashiers; ! Numbers of working clerks;
Real S1Mean, S1Std, S2Mean, S2Std; ! Random normal servers;
Integer SeedG, SeedS1, SeedS2; ! Seeds of the random generators;
Long Real TotalTime, MaxTime; ! Variables for statistics;
Integer CustomersOut; ! Number of served customers;
Process Class Generator;
Begin
While true do begin
! Interval between arrivals: ;
Hold(Uniform(MinInt(Period),MaxInt(Period),SeedG));
Activate New Customer(Time);
End While;
End of Generator;
Process Class Customer(Arrival); Real Arrival;
Begin
Ref(Customer) Next;
Real Spent;
If (not Queue1.Empty) or (BusyTellers >= Tellers) then
Wait(Queue1); ! Has to wait in Queue1;
! Service can start;
BusyTellers := BusyTellers + 1;
Hold(Normal(S1Mean, S1Std, SeedS1)); ! This is the teller service;
BusyTellers := BusyTellers - 1;
If (not Queue1.Empty) and (BusyTellers < Tellers) then begin
Next :- Queue1.First;
Next.Out; ! First from Queue1 served;
Activate Next after Current;
End If;
If (not Queue2.Empty) or (BusyCashiers >= Cashiers) then
Wait(Queue2); ! Has to wait in Queue2;
! Service can start;
BusyCashiers := BusyCashiers + 1;
Hold(Normal(S2Mean, S2Std, SeedS2)); ! This is the cashier service;
BusyCashiers := BusyCashiers - 1;
If (not Queue2.Empty) and (BusyCashiers < Cashiers) then begin
Next :- Queue2.First;
Next.Out; ! First from Queue2 served;
Activate Next after Current;
End If;
CustomersOut := CustomersOut + 1;
Spent := Time - Arrival;
TotalTime := TotalTime + Spent;
If Spent > MaxTime then MaxTime := Spent;
End of Customer;
Procedure Report; ! Experiment evaluation;
Begin
OutText(" *** Report on external simulation ***"); OutImage;
OutInt(CustomersOut,6); OutText(" customers ready at time ");
OutFix(Time,2,10); OutImage;
OutText("Average time in system: ");
OutFix(TotalTime/CustomersOut,2,10); OutImage;
OutText("Maximum time in system: ");
OutFix(MaxTime,2,10); OutImage;
End of Report;
! MAIN program body;
SeedG := 11; ! Seeds of random variables;
SeedS1 := 13;
SeedS2 := 17;
MinInt(1) := 1; MaxInt(1) := 4; ! Min and Max intervals;
MinInt(2) := 2; MaxInt(2) := 9;
MinInt(3) := 1; MaxInt(3) := 3;
Duration(1) := 120; ! Duration of periods;
Duration(2) := 240;
Duration(3) := 120;
MaxClerks := 6;
S1Mean := 6; ! Random normal servers;
S1Std := 1;
S2Mean := 8;
S2Std := 2;
Queue1 :- New Head;
Queue2 :- New Head;
Period := 1;
Activate New Generator;
For Period:=1 step 1 until 3 do begin
Real Array TimeSpent(1:MaxClerks);
OutText(" *** Results of internal simulation *** Period ");
OutInt(Period,1); OutImage;
OutText(" Tellers Average time spent"); OutImage;
For Trial:=1 step 1 until MaxClerks do
! ********************************************************** ;
Simulation Begin
! Internal Global variables: ;
Real TrialDuration; ! Internal experiment [min];
Ref(Head) Queue; ! The queue;
Integer Servers; ! Total number;
Integer BusyServers; ! Numbers of working clerks;
Integer TrialSeedG,TrialSeedS; ! Seeds of the random generators;
Long Real TotTime; ! Variables for statistics;
Integer CustOut; ! Number of served customers;
Process Class IGenerator;
Begin
While true do begin
Hold(Uniform(MinInt(Period),MaxInt(Period),TrialSeedG));
Activate New ICustomer(Time); ! Interval between arrivals: ;
End While;
End of IGenerator;
Process Class ICustomer(Arrival); Real Arrival;
Begin
Ref(ICustomer) Next;
If not Queue.Empty or (BusyServers >= Servers) then
Wait(Queue); ! Has to wait in Queue;
! Service can start;
BusyServers := BusyServers + 1;
Hold(Normal(S1Mean, S1Std, TrialSeedS)); ! Teller's service;
BusyServers := BusyServers - 1;
If not Queue.Empty then begin
Next :- Queue.First;
Next.Out; ! First from Queue served;
Activate Next after Current;
End If;
CustOut := CustOut + 1;
TotTime := TotTime + Time - Arrival;
End of ICustomer;
! Internal MAIN program body;
TrialSeedG := 7; ! Seeds for random variables;
TrialSeedS := 23;
Servers := Trial;
TrialDuration := 600;
Queue :- New Head;
Activate New IGenerator;
Hold(TrialDuration); ! Internal experiment duration;
TimeSpent(Trial) := TotTime/CustOut;
OutInt(Trial,13);
OutFix(TimeSpent(Trial),3,23); OutImage;
End of internal simulation;
! ********************************************************** ;
OutText("Enter the number of tellers : "); OutImage;
Tellers := InInt;
OutText("Enter the number of cashiers : "); OutImage;
Cashiers := InInt;
Hold(Duration(Period));
Report;
OutText("Press Enter to Continue."); OutImage; InImage;
End For;
End of program;
*** Results of internal simulation *** Period 1
Tellers Average time spent
1 181.404
2 52.691
3 6.132
4 5.979
5 5.972
6 5.972
Enter the number of tellers :
3
Enter the number of cashiers :
3
*** Report on external simulation ***
42 customers ready at time 120.00
Average time in system: 18.52
Maximum time in system: 25.95
Press Enter to Continue.
*** Results of internal simulation *** Period 2
Tellers Average time spent
1 36.620
2 6.090
3 6.045
4 6.038
5 6.038
6 6.038
Enter the number of tellers :
2
Enter the number of cashiers :
4
*** Report on external simulation ***
91 customers ready at time 360.00
Average time in system: 17.29
Maximum time in system: 27.16
Press Enter to Continue.
*** Results of internal simulation *** Period 3
Tellers Average time spent
1 205.290
2 103.226
3 7.937
4 5.993
5 5.974
6 5.972
Enter the number of tellers :
4
Enter the number of cashiers :
2
*** Report on external simulation ***
119 customers ready at time 480.00
Average time in system: 21.84
Maximum time in system: 63.93
Press Enter to Continue.
Birtwistle, G.M., O.-J. Dahl, B. Myhrhaug and K. Nygaard: SIMULA Begin, AUERBACH Publishers Inc, 1973.
Pooley, R.J.: An Introduction to Programming in SIMULA, Oxford, Blackwell Scientific Publications, 1987.
Kirkerud, B.: Object-Oriented Programming with SIMULA, Addison-Wesley, 1989.
Holmevik, J.R.(1994). "
Compiling SIMULA:
a historical study of technological genesis."
IEEE Annals of the History of Computing, 16 (4), p. 25-37, 1994. The article was also
presented at the 18th ASU Conference in 1992, and published in the SIMULA
Newsletter Vol.20(1), October 1992.
Thanks to Mr. Holmevik's kind permission you can download a local copy of his paper
Compiling SIMULA.