Today I defined some new entities that better illustrate the operation of the wait mechanism and the current events queue, which I have modified so it scans the list of current items repeatedly until no conditions are met. Here’s the modified version.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
//the current events queue definition, a list of current events queue items function currentEventsQueue() { this.ceq = new Array(); this.ceqSize = 0; this.addCeqItem = function(ceqItem) { this.ceq.push(ceqItem); this.ceqSize++; } this.processCeq = function() { var trueBlockFound; do { var i = 0; trueBlockFound = false; while ((i < this.ceqSize) && (!trueBlockFound)) { if (this.ceq[i].checkBlockingCondition()) { this.ceq.splice(i,1); this.ceqSize--; trueBlockFound = true; } else { i++; } } } while (trueBlockFound); } }; |
I then created an entity that simply advances to a time, sets a flag, and destroys itself. Note that the flag has to be implemented as an object so it can be passed by reference. Here’s the flag object (see note below) and two instantiations.
1 2 3 4 5 6 7 8 9 10 11 |
var conditionFlag = function(flag) { this.flag = flag; this.getFlag = function () { return this.flag; } this.setFlag = function(flag) { this.flag = flag; } } var flag1 = new conditionFlag(false); var flag2 = new conditionFlag(false); |
Here’s the entity that sets the flag.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//entity item 4 function entity4(initialTime,incrementTime,endTime,flagPointer) { this.entityID = getNewID(); this.initialTime = initialTime; this.incrementTime = incrementTime; this.endTime = endTime; this.flagPointer = flagPointer; this.nextState = "increment"; feq.newItem(initialTime,this); displayProgressText("entity "+this.entityID+" created at time "+globalSimClock+"<br />"); this.activate = function() { bumpGlobalExecutionCount(); if (this.nextState == "increment") { displayProgressText("entity "+this.entityID+" sets flag at time "+globalSimClock+" flag value: "+this.flagPointer.getFlag()+" flag1: "+flag1.getFlag()+" flag2: "+flag2.getFlag()+"<br />"); if (globalSimClock + this.incrementTime >= this.endTime) { this.nextState = "destroy"; } advance(this.incrementTime); } else if (this.nextState == "destroy") { this.flagPointer.setFlag(true); displayProgressText("entity "+this.entityID+" terminated at time "+globalSimClock+" flag value: "+this.flagPointer.getFlag()+" flag1: "+flag1.getFlag()+" flag2: "+flag2.getFlag()+"<br />"); } else { alert("entity "+this.entityID+" went into undefined state"); displayProgressText("entity "+this.entityID+" in undefined state at time "+globalSimClock+"<br />"); } }; //this.activate }; //entity |
I also created an entity that checks the flag and destroys itself when the condition becomes true.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
//entity item 5 function entity5(initialTime,flagPointer) { this.entityID = getNewID(); this.initialTime = initialTime; this.flagPointer = flagPointer; //this.nextState = "block1"; //feq.newItem(initialTime,this); this.ceqItem = new currentEventItem(this); ceq.addCeqItem(this.ceqItem); displayProgressText("entity "+this.entityID+" created at time "+globalSimClock+"<br />"); this.blockingCondition = 0; this.checkBlockingCondition = function() { if (this.blockingCondition < 0) { return false; } else if (this.blockingCondition == 0) { if (this.flagPointer.getFlag()) { displayProgressText("entity "+this.entityID+" unblocks at time "+globalSimClock+" flag value: "+this.flagPointer.getFlag()+"<br />"); return true; } else { displayProgressText("entity "+this.entityID+" still blocked at time "+globalSimClock+" flag value: "+this.flagPointer.getFlag()+" flag1: "+flag1.getFlag()+" flag2: "+flag2.getFlag()+"<br />"); return false; } } } }; //entity5 |
Finally, I created two instantiations of each entity. The idea is for the entity4 types to wait for some period (times 45.0 and 63.7, respectively) and then set the flags which represent the entity5 unblock conditions, and for the entity5 types to check to see if their unblock conditions have been met (via the ceq.processCeq()
call) each time a new future event is processed.
1 2 3 4 5 |
var entityE = new entity4(0.0,45.0,45.0,flag1); var entityF = new entity4(0.0,63.7,63.7,flag2); var entityG = new entity5(0.0,flag1); var entityH = new entity5(0.0,flag2); |
The output indicates that things appear to be working as intended.
104 minutes
entity 1 created at time 0
entity 2 created at time 0
entity 3 created at time 0
entity 4 created at time 0
entity 5 created at time 0
entity 6 created at time 0
entity 7 created at time 0
entity 8 created at time 0
entity 4 reports at time 0 executions: 0
entity 7 still blocked at time 0 flag value: false flag1: false flag2: false
entity 8 still blocked at time 0 flag value: false flag1: false flag2: false
entity 5 sets flag at time 0 flag value: false flag1: false flag2: false
entity 7 still blocked at time 0 flag value: false flag1: false flag2: false
entity 8 still blocked at time 0 flag value: false flag1: false flag2: false
entity 6 sets flag at time 0 flag value: false flag1: false flag2: false
entity 7 still blocked at time 0 flag value: false flag1: false flag2: false
entity 8 still blocked at time 0 flag value: false flag1: false flag2: false
entity 1 updated at time 11
entity 7 still blocked at time 11 flag value: false flag1: false flag2: false
entity 8 still blocked at time 11 flag value: false flag1: false flag2: false
entity 3 updated at time 12 position: -40
entity 7 still blocked at time 12 flag value: false flag1: false flag2: false
entity 8 still blocked at time 12 flag value: false flag1: false flag2: false
entity 2 updated at time 13
entity 7 still blocked at time 13 flag value: false flag1: false flag2: false
entity 8 still blocked at time 13 flag value: false flag1: false flag2: false
entity 3 updated at time 19.009999999999998 position: -35
entity 7 still blocked at time 19.009999999999998 flag value: false flag1: false flag2: false
entity 8 still blocked at time 19.009999999999998 flag value: false flag1: false flag2: false
entity 1 updated at time 21
entity 7 still blocked at time 21 flag value: false flag1: false flag2: false
entity 8 still blocked at time 21 flag value: false flag1: false flag2: false
entity 2 updated at time 26
entity 7 still blocked at time 26 flag value: false flag1: false flag2: false
entity 8 still blocked at time 26 flag value: false flag1: false flag2: false
entity 3 updated at time 26.019999999999996 position: -30
entity 7 still blocked at time 26.019999999999996 flag value: false flag1: false flag2: false
entity 8 still blocked at time 26.019999999999996 flag value: false flag1: false flag2: false
entity 1 updated at time 31
entity 7 still blocked at time 31 flag value: false flag1: false flag2: false
entity 8 still blocked at time 31 flag value: false flag1: false flag2: false
entity 3 updated at time 33.029999999999994 position: -25
entity 7 still blocked at time 33.029999999999994 flag value: false flag1: false flag2: false
entity 8 still blocked at time 33.029999999999994 flag value: false flag1: false flag2: false
entity 2 updated at time 39
entity 7 still blocked at time 39 flag value: false flag1: false flag2: false
entity 8 still blocked at time 39 flag value: false flag1: false flag2: false
entity 3 updated at time 40.03999999999999 position: -20
entity 7 still blocked at time 40.03999999999999 flag value: false flag1: false flag2: false
entity 8 still blocked at time 40.03999999999999 flag value: false flag1: false flag2: false
entity 1 updated at time 41
entity 7 still blocked at time 41 flag value: false flag1: false flag2: false
entity 8 still blocked at time 41 flag value: false flag1: false flag2: false
entity 5 terminated at time 45 flag value: true flag1: true flag2: false
entity 7 unblocks at time 45 flag value: true
entity 8 still blocked at time 45 flag value: false flag1: true flag2: false
entity 3 updated at time 47.04999999999999 position: -15
entity 8 still blocked at time 47.04999999999999 flag value: false flag1: true flag2: false
entity 1 updated at time 51
entity 8 still blocked at time 51 flag value: false flag1: true flag2: false
entity 2 updated at time 52
entity 8 still blocked at time 52 flag value: false flag1: true flag2: false
entity 3 updated at time 54.05999999999999 position: -10
entity 8 still blocked at time 54.05999999999999 flag value: false flag1: true flag2: false
entity 1 updated at time 61
entity 8 still blocked at time 61 flag value: false flag1: true flag2: false
entity 3 updated at time 61.069999999999986 position: -5
entity 8 still blocked at time 61.069999999999986 flag value: false flag1: true flag2: false
entity 6 terminated at time 63.7 flag value: true flag1: true flag2: true
entity 8 unblocks at time 63.7 flag value: true
entity 2 updated at time 65
entity 3 waiting at time 68.07999999999998 wait count: 4
entity 1 updated at time 71
entity 3 waiting at time 75.08999999999999 wait count: 3
entity 2 updated at time 78
entity 1 updated at time 81
entity 3 waiting at time 82.1 wait count: 2
entity 3 waiting at time 89.11 wait count: 1
entity 2 updated at time 91
entity 1 updated at time 91
entity 3 waiting at time 96.12 wait count: 0
entity 1 terminated at time 101
entity 3 terminated at time 103.13000000000001
entity 2 terminated at time 104
As an aside I was reading up on some things related to this mod and discovered that I’ve apparently been using the closure pattern and not the prototypal pattern for creating objects. As I understand it on first reading, the closure pattern carries the overhead of the entire object with each instantiation, while the prototypal pattern causes the method mechanisms to be instantiated only once while the created objects contain only the relevant data and a reference to the prototype mechanisms. This may be important because discrete event simulations can involve huge numbers of entities and we wouldn’t want to carry any more overhead than absolutely necessary. I’ll definitely have to look into this more going forward.