{* * @(#) simpas.pas - Event Simulation Unit. ** * Language: Turbo Pascal * Tested with: Turbo Pascal v6.0 * Last modified: 1997-11-20 13:20:00 GMT+03:00 *} unit SimPas; interface type DataPntr=Pointer; { ^DataType } { Pointer type to event data } NotePntr=^NoteType; { Pointer type to event record } NoteType=record Numb: Integer; { Number of event activity } Time: Real; { Event time } Addr: DataPntr; { Event data address } Next,Prev: NotePntr; { Prev and next addresses } end; StatType=array[1..3] of record { Statistics data type } Numb, { Activity number } Exist, { Counter of existing events in the list } Simul, { Happened events counter } Prep, { Happened schedulings counter } Canc: Integer; { Happened cancellations counter } end; GenerType=array[1..3] of record { Stream regeneration data type } Numb, { Activity number } Count, { Regeneration cycles counter } ID: Integer; { Generator type identifier } Param1,Param2: Real; { Two parameters } end; var ActNumb: Integer; { Activity number of the active event } ActTime: Real; { Time of the active event } ActAddr: DataPntr; { Data address of the active event } Repeater: Integer; { Repeation counter of installations } Inform: Integer; { Debug info switch } RND_INT: Integer; { Pseudo-random seed } Node: NotePntr; { Head list chain pointer } Route: NotePntr; { Current list chain pointer } SlyNode: NotePntr; { Control duplication of 'Node' } Addr: DataPntr; { Event data working pointer } Stat: ^StatType; { Statistics data pointer } Gener: ^GenerType; { Stream generation data pointer } procedure Initiate; { Variables initialization } function RND: Real; { Generator of random numbers in range from 0 (inclusive) to 1 (exclusive) } function Uniform(Min, Max: Real): Real; { Generator of unifor random numbers in range from Min to Max } function Normal(M,S: Real): Real; { Gaussian random numbers generator } function NegExp(L: Real): Real; { Generator of 'neg_exp' random numbers (L>0) } procedure Start(N: Integer; T: Real; A:DataPntr; Time: Real); { Setting of installation start (the first record in list and end time } procedure Finish; { Stopping of simulation } function Simulate: Boolean; { Do one step of simulation } procedure ViewList; { List show routine } procedure ViewStat; { Statistics array show routine } procedure ViewNote(P: NotePntr); { List record show routine } function IncNote(P1,P2: NotePntr; N: Integer; T: Real; A: DataPntr): NotePntr; { List record addition } procedure DelNote(P: NotePntr); { List record deletion } function GetNextT(T: Real): NotePntr; { List record searching } function GetStatI(var Numb: Integer): Integer; { Find statistics index of event number } function GetGener(var Numb: Integer): Integer; { Find generation index of event number } procedure StatCanc(var Numb: Integer); { Statistics correction on cancellation } procedure StatPrep(var Numb: Integer); { Statistics correction on event planning } procedure Statistics(Numb: Integer); { Do statistics gathering } procedure Generate(Numb,Distr: Integer; Par1,Par2: Real; Count: Integer); { Do stream generation } function Cancel(P: NotePntr): DataPntr; { Event cancellation } function CancMin(N: Integer): DataPntr; { Event cancellation (with the specified number and min time } procedure PrepBefore(P: NotePntr; N: Integer; A: DataPntr); { Event addition before the specified record } procedure PrepAfter(P: NotePntr; N: Integer; A: DataPntr); { Event addition after the specified record } procedure Prepare(N: Integer; DT: Real; A: DataPntr); { Event addition before the record with the time greater than (current+DT) } procedure PrepPrior(N: Integer; DT: Real; A: DataPntr); { Event addition before the record with the time not less than (current+DT) } function Have(Numb: Integer): Integer; { Returns records counter for the the specified statistics number } function Done(Numb: Integer): Real; { Returns average counter of happened events with the specified number } function Prep(Numb: Integer): Real; { Returns average counter of scheduled events with the specified number } function Canc(Numb: Integer): Real; { Returns average counter of cancelled events with the specified number } implementation procedure ViewNote(P: NotePntr); var A: Char; begin if P^.Addr=nil then A:='_' else A:='#'; WriteLn('Number=':10,P^.Numb:5,'Time=':15,P^.Time:10:3,'Address=':15,A); end; function RND: Real; const M=113; D=12703; B=66; var C: Integer; begin C:=RND_INT div M; RND_INT:=B*C+M*(RND_INT-M*C); if RND_INT>D then RND_INT:=RND_INT-D; RND:=RND_INT/D; end; procedure DelNote(P: NotePntr); begin P^.Next^.Prev:=P^.Prev; P^.Prev^.Next:=P^.Next; Dispose(P); end; function IncNote(P1,P2: NotePntr; N: Integer; T: Real; A: DataPntr): NotePntr; var P: NotePntr; begin New(P); P1^.Next:=P; P2^.Prev:=P; IncNote:=P; P^.Numb:=N; P^.Prev:=P1; P^.Next:=P2; P^.Time:=T; P^.Addr:=A; end; function GetNextT(T: Real): NotePntr; var P: NotePntr; begin if SlyNode<>Node then begin GetNextT:=nil; if Inform>0 then WriteLn('No List!'); end else begin P:=Node^.Next; while (P<>Node) and (P^.Time<=T) do P:=P^.Next; GetNextT:=P; end; end; function GetStatI(var Numb: Integer): Integer; begin GetStatI:=0; if Stat<>nil then if Stat^[1].Numb=Numb then GetStatI:=1 else if Stat^[2].Numb=Numb then GetStatI:=2 else if Stat^[3].Numb=Numb then GetStatI:=3; end; function GetGener(var Numb: Integer): Integer; begin GetGener:=0; if Gener<>nil then if Gener^[1].Numb=Numb then GetGener:=1 else if Gener^[2].Numb=Numb then GetGener:=2 else if Gener^[3].Numb=Numb then GetGener:=3; end; procedure StatCanc(var Numb: Integer); var I: Integer; begin I:=GetStatI(Numb); if I>0 then begin Stat^[I].Canc:=Stat^[I].Canc+1; Stat^[I].Exist:=Stat^[I].Exist-1; end; end; procedure StatPrep(var Numb: Integer); var I: Integer; begin I:=GetStatI(Numb); if I>0 then begin Stat^[I].Prep:=Stat^[I].Prep+1; Stat^[I].Exist:=Stat^[I].Exist+1; end; end; procedure Initiate; begin Inform:=0; Repeater:=0; RND_INT:=7531; Node:=nil; Route:=nil; SlyNode:=nil; Stat:=nil; Gener:=nil; end; procedure Statistics(Numb: Integer); var I: Integer; begin if Stat=nil then begin New(Stat); Stat^[1].Numb:=0; Stat^[2].Numb:=0; Stat^[3].Numb:=0; end; I:=GetStatI(Numb); if I=0 then begin I:=GetStatI(I); if I=0 then I:=3; end; Stat^[I].Numb:=Numb; Stat^[I].Exist:=0; Stat^[I].Simul:=0; Stat^[I].Prep:=0; Stat^[I].Canc:=0; end; procedure Generate(Numb,Distr: Integer; Par1,Par2: Real; Count: Integer); var I: Integer; begin if Gener=nil then begin New(Gener); Gener^[1].Numb:=0; Gener^[2].Numb:=0; Gener^[3].Numb:=0; end; I:=GetGener(Numb); if I=0 then begin I:= GetGener(I); if I=0 then I:=3 end; Gener^[I].Numb:=Numb; Gener^[I].Param1:=Par1; Gener^[I].Count:=Count; Gener^[I].Param2:=Par2; Gener^[I].ID:=Distr; end; procedure Start(N: Integer; T: Real; A: DataPntr; Time: Real); begin ActNumb:=0; ActTime:=0.0; ActAddr:=nil; New(Node); SlyNode:=Node; Repeater:=Repeater+1; if Stat<>nil then begin Stat^[1].Exist:=0; Stat^[2].Exist:=0; Stat^[3].Exist:=0; end; if Inform>0 then begin Write('Start of realization ',Repeater); if Time>0 then WriteLn(' until time ',Time:10:3) else WriteLn; end; Node^.Numb:=0; Node^.Time:=0; Node^.Addr:=nil; New(Route); Node^.Next:=Route; if N<>0 then StatPrep(N); Route^.Prev:=Node; Route^.Numb:=N; Route^.Time:=T; Route^.Addr:=A; Route:=Node; if Time>0 then begin New(Route); Route^.Numb:=0; Route^.Time:=Time; Route^.Addr:=nil; Route^.Next:=Node; Node^.Prev:=Route; end; Node^.Next^.Next:=Route; Route^.Prev:=Node^.Next; if Inform>0 then begin Write('First record '); ViewNote(Node^.Next); end; if Inform>2 then ReadLn; end; procedure Finish; begin if Inform>0 then Write('Finish':11); if SlyNode<>Node then begin if Inform>0 then WriteLn('No List!'); end else begin Route:=IncNote(Node,Node^.Next,0,Node^.Time,nil); if Inform>0 then ViewNote(Route); end; end; function Cancel(P: NotePntr): DataPntr; begin Cancel:=nil; if Inform>1 then Write('Cancel':11); if P<>Node then begin StatCanc(P^.Numb); Cancel:=P^.Addr; if Inform>1 then ViewNote(P); DelNote(P); end else if Inform>1 then WriteLn('Head Element?!?'); end; function CancMin(N: Integer): DataPntr; var P:NotePntr; B: Boolean; begin CancMin:=nil; if Inform>1 then Write('CancMin':11); if SlyNode<>Node then begin if Inform>0 then WriteLn('No List!'); end else begin B:=False; P:=Node; repeat P:=P^.Next; if P^.Numb=N then B:=True; until (P=Node) or (B=True); if B=False then begin if Inform>1 then WriteLn('No Event ',n:3,'in the List!'); end else begin if Inform>1 then ViewNote(P); StatCanc(N); CancMin:=P^.Addr; DelNote(P); end; end; end; procedure PrepBefore(P: NotePntr; N: Integer; A: DataPntr); var X: NotePntr; begin if Inform>1 then Write('Before':11); if P<>Node then begin StatPrep(N); X:=IncNote(P^.Prev,P,N,P^.Time,A); if Inform>1 then ViewNote(X); end else if Inform>1 then WriteLn('Head Element?!?'); end; procedure PrepAfter(P: NotePntr; N: Integer; A: DataPntr); var X: NotePntr; begin if Inform>1 then Write('After':11); if P<>Node then begin StatPrep(N); X:=IncNote(P,P^.Next,N,P^.Time,A); if Inform>1 then ViewNote(X); end else if Inform>1 then WriteLn('Head Element?!?'); end; procedure Prepare(N: Integer; DT: Real; A: DataPntr); var X: NotePntr; begin if Inform>1 then Write('Prepare':11); DT:=ActTime+DT; X:=GetNextT(DT); if X<>nil then begin StatPrep(N); X:=IncNote(X^.Prev,X,N,DT,A); if Inform>1 then ViewNote(X); end; end; procedure PrepPrior(N: Integer; DT: Real; A: DataPntr); var X: NotePntr; begin if Inform>1 then Write('Prior':11); DT:=ActTime+DT; if SlyNode<>Node then begin if Inform>0 then WriteLn('No List!'); end else begin StatPrep(N); X:=Node^.Next; while (X<>Node) and (X^.Time1 then ViewNote(X); end; end; function Uniform(Min,Max: Real): Real; begin if Min0 then NegExp:=-Ln(RND)/L else NegExp:=0; end; function Have(Numb: Integer): Integer; var I: Integer; begin I:=GetStatI(Numb); if I>0 then Have:=Stat^[I].Exist else Have:=I; end; function Done(Numb: Integer): Real; var I: Integer; begin I:=GetStatI(Numb); if I>0 then Done:=Stat^[I].Simul/Repeater else Done:=0; end; function Prep(Numb: Integer): Real; var I: Integer; begin I:=GetStatI(Numb); if I>0 then Prep:=Stat^[I].Prep/Repeater else Prep:=0; end; function Canc(Numb: Integer): Real; var I: Integer; begin I:=GetStatI(Numb); if I>0 then Canc:=Stat^[I].Canc/Repeater else Canc:=0; end; function Simulate: Boolean; var P: NotePntr; I: Integer; begin Simulate:=False; if Inform>0 then Write('Simulate':11); if SlyNode<>Node then begin if Inform>0 then WriteLn('No List!'); end else begin if (Node^.Next^.Numb=0) or (Node^.Next=Node) then begin Route:=Node^.Next; while Route<>Node do begin if Route^.Addr<>nil then Dispose(Route^.Addr); P:=Route^.Next; Dispose(Route); Route:=P; end; Dispose(Node); if Inform>0 then begin WriteLn('Simulation Finished!'); WriteLn; end; end else begin ActNumb:=Node^.Next^.Numb; ActTime:=Node^.Next^.Time; ActAddr:=Node^.Next^.Addr; if Inform>0 then ViewNote(Node^.Next); DelNote(Node^.Next); Node^.Time:=ActTime; Simulate:=True; I:=GetGener(ActNumb); if I>0 then with Gener^[I] do if Count>1 then begin Count:=Count-1; if ID<1 then Prepare(Numb, Uniform(Param1, Param2),nil) else if ID>1 then Prepare(Numb, NegExp(Param1), nil) else Prepare(Numb, Normal(Param1, Param2),nil); end else Numb:=0; I:=GetStatI(ActNumb); if I>0 then begin Stat^[I].Simul:=Stat^[I].Simul+1; Stat^[I].Exist:=Stat^[I].Exist-1; end; if Inform>3 then ReadLn; end; end; end; procedure ViewList; var P: NotePntr; begin Write('List:':11); P:=Node^.Next; while P<>Node do begin ViewNote(P); P:=P^.Next; Write(' ':11); end; WriteLn; end; procedure ViewStat; begin if Stat<>nil then begin WriteLn(' Numb',' Exist',' Simul',' Prep',' Canc'); WriteLn(Stat^[1].Numb:5,Stat^[1].Exist:6,Stat^[1].Simul:6, Stat^[1].Prep:5,Stat^[1].Canc:5); WriteLn(Stat^[2].Numb:5,Stat^[2].Exist:6,Stat^[2].Simul:6, Stat^[2].Prep:5,Stat^[2].Canc:5); WriteLn(Stat^[3].Numb:5,Stat^[3].Exist:6,Stat^[3].Simul:6, Stat^[3].Prep:5,Stat^[3].Canc:5); end; end; begin Initiate; end.