A Simple Discrete-Event Simulation: Part 55

Today I got a lot of updates into the mechanism for forwarding entities from one component to another. The changes were chiefly made to the Queue and Process components with some supplementary changes to the Path component. The first change involved saving the destination chosen when an entity first tries to exit a component. This only applies when using model routing logic. The component then keeps trying to forward the entity to the chosen location until it is successful, at which point it resets the savedDestination property to its initialized value of -1, meaning that the method should generate a new destination.

The next changes involved handling pull requests from downstream components. When an exclusive component forwards an entity it sends a request back to a previous component to forward an entity if one is available. There are several things to consider during this process. One is that the request is only sent if the discharging component goes from being at capacity to being at less than capacity. If a component (usually a Queue in this case) is not at capacity then the upstream component(s) should have been able to forward entities to the present component as needed, so there is no reason to send the pull request. The second consideration is important when there are multiple upstream components that might be pulled from. The code was changed to select the entity that has been waiting the longest. I discussed this in yesterday’s post and I still have to address the method of setting the “age” of each entity.

Finally, I changed the pull mechanism to ensure that the item is forwarded to the component that requested it. It would make no sense to send a pull request and have the upstream component randomly generate a new destination and send the entity someplace else. In order to do this I had to add a new array to the Queue and Process components to store the index of the first non-Path component linked to in each of the nextComponentList references. The array is initialized using the new getNextComponentIDs method, which has to be called when the components are defined and linked but before the model runs. The componentID of the pulling component is relayed to the upstream component, which then cycles through its own downstream connection indices until it finds a match (which it should be guaranteed to do). Once the match is found the upstream component can forward the entity (if it’s available) to the proper downstream component. This method of selecting a forwarding destination overrides the one normally used.

Here’s the new code for the forwardEntity method:

Here’s the new code for the pullFromPrevious method:

Here’s the new code for the getNextComponentIDs method:

The Path component was modified so the pullFromPrevious method could relay the index of the requesting element.

The Path component was also modified to add a method to pass requests for component IDs through multiple paths.

Blissfully I think I’m pretty close to getting the major routing and plumbing issues worked out so I can move on with things that are more “fun” and interesting. That said, the hard part will be done when it’s done. I’ll begin next week by working off the comments and TODOs in the code.

At the end of another week here is the current To Do list:

  • Standardize linking and exclusivity process
  • Resolve and standardize new vs. advance issue
  • Rework drawing of Path components so correct elements are always on top
  • New property for forward exclusivity as opposed to receiving exclusivity.
  • Formalize and implement method of receiving from multiple upstream components in turn. Implementing and observing this may illuminate the behaviors that will need to be implemented for the general path solution described in one or more previous posts.
  • Rework the Queue mechanism to flexibly handle finite-traversal time and zero-traversal time configurations
  • Revisit distribution logic to make sure it’s cycling the way it should be.
  • Learn JavaScript’s prototype object pattern and re-implement everything in that in place of the closure pattern I’ve been using; I’ll want to bite that bullet before this thing goes much farther
  • Add Control, Bag, and Stack components
  • Expand function of Process components to handle multiple entities in parallel, in effect making a single component function as if it were multiple, associated ones
  • Discrete-event simulation frameworks often include the concept of sets (logical containers that that be iterated and compared for intersection and so on, so that idea should be implemented; this would expand on things were doing now with lists of components and entities; the need for this was inspired by thinking about the bag data structure in general
  • Ponder the idea of implementing a combined Queue-Process component
  • Expand Path component representation so it can incorporate multiple line segments
  • Add ability to sense reaching tail end of FIFO queue based on stopping to wait on a Path component; collect statistics accordingly (possibly add wait flag to entities so they can test against the next entity in line)
  • Look into creating a zero-duration, zero-queue decision component
  • Create standardized routing mechanism (to components of different types) based on process logic (vs. distribution logic to multiple components of the same type)
  • Implement mechanism to identify combinations of related components into groups (e.g., a group of tollbooths represent a single toll plaza)
  • Gather and report system-, component-, and group-level statistics
  • Add ability to stream large volumes of output information which can be post-processed and quantified via a parsing mechanism
  • Streamline the process of defining the endpoints of Path components (i.e., attach standard nodes to other components and connect to those automatically, which will greatly save on the number of x,y locations the designer must specify manually)
  • Add an edit mode that allows designers to change component properties interactively (ultimately including being able to drag them)
  • Use the new, completely external mechanism for displaying component data
  • Describe how abstract representation can be used to represent detailed layouts and interactions; include ability to flag or alarm situations which would cause conflicts in the real world that would not necessarily be captured in a model unless specifically tested for
  • Add the ability to graph outputs as part of reporting
  • Add scrolling, animated graphs to illustrate progress as simulations run
  • Include ability for users to call up component and entity status by written or graphical display interactively while runs are in progress
  • Create streamlined graphical representations of all component types; create data display for Path components
  • Add ability to display entities inside relevant non-path components
  • Abstract the current x,y locations of all elements and scale them to the screen so the user can zoom in and out
  • Add ability for users to interactively change things during runs
  • Add Monte Carlo mechanisms to various timing and routing events (beyond what’s already been demonstrated)
  • Allow designer to build Monte Carlo and other distributions from acquired data using standardized tools
  • Add ability to perform multiple runs and statistically quantify generated outputs
  • Make simulation display update at regular intervals of simulated time rather than intervals defined by individual events; also make this “speed” scalable
  • Include ability to add arbitrary graphic elements to models (labels, keys, tables, etc.)
  • Include ability to display an underlay “below” the model display (e.g., a floor plan of a modeled process)
  • Allow user to turn off display and run model in “fire-and-forget” mode where it generates results without wasting time redrawing graphics.
  • Allow user to selectively turn different display elements on and off
  • Create suite of test configurations to exercise every combination of connections and support regression testing.
  • Add ability to assign open/close schedules for components and groups
  • Add ability to introduce multiple types of entities in model with different processing rules for routing and timing
  • Add ability to combine multiple queues into a single, logical unit
  • Add ability to adapt stand base components to represent varied and specialized things (this applies mostly to Process components)
  • Add ability to save and restore model definitions (in files/XML and in databases, requires PHP/MySql, Node.js or other back end capability)
  • Add ability to represent more abstract processes:
    • Reintroduce wait..until mechanism that uses the current events queue
    • Include pools of resources that are needed by different processes
    • Implement non-FIFO queues or collections that receive and forward entities based on arbitrary (user-defined) criteria
    • Include ability to accept events that happen according to fixed schedules rather than random ones (e.g., to match observed data)
    • Include the ability to change representation of entities and components to represent state changes (by color, shape, labels, flags, etc.)
    • Support input and editing of modular packages of information used to define and drive models
    • Add ability to represent BPM processes using standard BPMN notation
  • Really complex stuff
    • Develop more complex, arbitrary node-and-link representation of model, which brings up worlds of complications on its own!
    • Polish related sections of code and break them into modules which can be included on a modular basis
    • Make modules and examples distributable for use by a wider community
      • Write documentation for modules as needed
      • Share on GitHub
      • Create dedicated project page on my website
      • Update and enhance my custom Graph component as well as the simulation framework
  • Re-implement this system in a more appropriate language like C++ or at least Java

Finally, just for kicks and giggles, I was inspired by a demo I saw at a recent Meetup of the three.js framework for creating 3D models simply. I’m therefore going to add an item to the list to render a simulated system in 3D. I’ll keep it simple, but it should still be pretty punchy. If I go really crazy I’ll run that through a simple VR framework I also saw demoed. I’m sure it won’t be as easy as the speaker made it look, but it’s so much fun it might be a good thing to do over the holidays.

Posted in Simulation | Tagged | Leave a comment

A Simple Discrete-Event Simulation: Part 54

Today I updated the mechanism by which the components pull entities from previous components when there are multiple options. This involves pulling the entity that has been waiting the longest. Each entity is timestamped using a new member named forwardAttemptTime, for which a getter and setter have also been created. In the current implementation the value is set to Infinity when an entity is received and then to the current time when an entity completes its minimum traverse time for Queue components or its process time for Process components. I’m thinking this needs to be updated to the time each entity finishes its traverse or process and then reaches the head of the queue, instead. In this case the timestamp could be stored once with each component rather than once for each entity within each component. That’s how I originally implemented the mechanism. It didn’t work because I updated the timestamp every time a forward was attempted whether it was successful or not. It would have worked correctly if the timestamp is updated correctly. I’ll experiment with that and report back tomorrow. In the meantime the existing animation illustrates the intent.

Here’s the important bit of code. It polls all backwards connections to find the one whose head entity has been waiting the longest. This is why the default value for the timestamp is Infinity and not zero. Once the oldest item is identified the call is sent back to forward the entity to the current component.

Here’s the code that gets the relevant forwardAttemptTime value from Queue and Process components. Per the discussion above this may be reworked.

Here’s the code that defines the example system.

Thinking about this also points out that the pullFromPrevious method needs to call the forwardEntity method from the sending component so it’s guaranteed to forward the requested entity to the right place. If the previous entity has only one forward connection, which is the case in our present example, then there’s no way to make an error. However, if the upstream component is using distributed or model routing logic the situation could become much more complicated. If an upstream component is using distribution logic then it’s safe for the receiving component to request the pull because all of the upstream component’s possible destinations are equally valid. If an upstream component is using model routing logic, however, and the waiting entity is not scheduled to be forwarded to the requesting component, then the pull would not be allowed. Indeed, in this case the upstream component should not even be picked in this case. I’ve added a comment to the code to remind myself of this.

Posted in Simulation | Tagged | Leave a comment

A Simple Discrete-Event Simulation: Part 53

The framework is meant to work without including Path components, which would be the case when transfer between components is effectively instantaneous, as would be the case when simulating an information or logical system rather than a physical system of some kind. We can see here that the system works the same way without them, although none of the queues back up as far because a lot of transit time has been removed from the model.

Visualizations are much more difficult to follow without Path connections and the animated movement of entities. However, once we know that the components and transfer mechanisms work as we expect, we can use them with some confidence.

Here’s the new configuration code.

Posted in Simulation | Tagged | Leave a comment

A Simple Discrete-Event Simulation: Part 52

Today I reworked the future events mechanism to streamline it in a big way. I knew it needed this and the essential insight about how to do it occurred to me in the shower about ten days ago. I decided to do this now because I was going cross-eyed looking at the connection logic, which itself needs one more extension.

The main insight involved the need to recycle the reference to the most recent future event item or to create a new future event item. New items are generated as needed and placed in the future events queue. Items are then pulled off the queue in time order and processed one by one. The items are stored in the feqCurrent variable, which can be updated and recycled back into the queue. The variable should then be set to null, which signals that a new event item will have to be created so it can be placed into the future events queue.

I also created standalone functions to process the reuse or generation of new future event items. The advance function defines and event that takes place by a specified offset from the current time, whenever that is. That’s the most commonly used function and models a fixed delay, process time, or event duration in general. The jump function works the same way except that the absolute time (from time zero, the beginning of the simulation) is used. This function is more likely to be used to specify a schedule of known events as the simulation is initialized.

The code is shown below in its now much abbreviated form.

Here are a couple of examples of the advance function in use. The second example shows the extra parameter being used to reference an entity that needs to be processed within a component.

Posted in Simulation | Tagged | Leave a comment

A Simple Discrete-Event Simulation: Part 51

Today I tried a configuration that included instances of consecutively linked Path components, one exclusive and one non-exclusive. They both worked the way I intended them to once I cleaned up a couple of typos.

Here’s the new code that sets the configuration.

Posted in Simulation | Tagged | Leave a comment

A Simple Discrete-Event Simulation: Part 50

Today I got the new permission logic working. It uses a simpler and more consistent mechanism for determining whether new entities can go into exclusive components and the Path components that feed them. When an entity is ready to be forwarded to the next component it has to check to see if the next component (including the Path components that feed them) is open. It does this by comparing the number of entities in the destination component (and feeding paths) to the maximum capacity of the destination component.

Here’s how the Queue and Process components, each of which can be linked to multiple, incoming Path components, count the number of entities present. Notice that the method also sets the open/closed status for the component, but not the open/closed status for the incoming Path components. This status sets the color of the component when it is drawn. Green and red indicate open and closed, respectively.

Here’s how the Path component does it. Note that this method is recursive to count the entities in multiple Path components linked in series. It has the side-effect of setting the open/closed status for each Path and destination component.

The isOpen calls are made whenever an entity is testing to see whether it can enter a component, when it enters a component, and in some cases when it leaves a component. If an entity entering a Path or destination component and brought the system up to its capacity you can imagine that it might have a problem moving between components in the system. I therefore found it necessary to add a permissionToMove flag in the entity object. This is set to true whenever an entity is received by an exclusive Path component and set to false whenever an entity is received by a non-Path component (that also isn’t an Entry or Exit component).

When an entity leaves a non-Path component it checks to see if leaves the component in an open status (which it should always do). If so, it reaches back to all the incoming paths to set their statuses to open as well. Here’s the forwardEntity code for the Queue and Process components.

Here’s the setPreviousOpen method from the Path component.

It occurs to me that the entire isOpen mechanism doesn’t need to be invoked when an external entity wants to test to see if it can enter. It may be that, since the openStatus of each component should be properly set based on events, we can simplify things by testing against that status directly.

Posted in Simulation | Tagged | Leave a comment

A Simple Discrete-Event Simulation: Part 49

Today I was trying to sort out some of the issues I had outstanding for yesterday and came across the idea of setting the open status of collections of components (Path components and the non-Path component at which they terminate) based on comparing the number of entities in the system (component and paths) vs. the capacity of the terminating component. It was easy to come up with a method to count all the entities in that collection, and the routine even accounts for multiple, incoming Path connections. By making the same method recursive in the Path component the process can even count entities across multiple Path components in series. This applies to components that are flagged as exclusive, that have a finite capacity. This logic would not be needed for components that were non-exclusive and have an effectively infinite capacity.

It then occurred to me that setting the capacity of components to infinity (JavaScript supports this as a numerical value directly, but any sufficiently large number would work) or to a fixed value, and returning an actual count for exclusive components and zero for non-exclusive ones, might allow the same logic to be used in all cases in a way that would handle the open/not-open status of Path and non-Path components implicitly using simpler logic.

I’m still working my way through this thought process, drawing out the possibilities on paper. Two sticking points as I write this are how to chains of Path components in series and whether to store a flag in the entity marking it as cleared to proceed into a related collection of exclusive elements (Path components and non-Path terminating component). This is because I’ve required that individual components have individual open/not-open values so permissions have to be calculated and granted as an entity moves from component to component (especially along consecutive Path components).

Obviously I’ll let you know how it turns out. I may not actually implement this methodology but it’s worth exploring. Simpler and more streamlined is always better.

Posted in Simulation | Tagged | Leave a comment

A Simple Discrete-Event Simulation: Part 48

I got an awful lot done over the weekend and today toward making the various behaviors for each type of component as similar as possible. This really helped me replicate the different controls and interlocks I had come up with for individual components across all of them in a consistent way. The process of continually revisiting everything also makes everything more clear over time.

I tried a new configuration to test different combinations of components and permissions. Specifically, I had a main queue that was non-exclusive feed a pair of exclusive local queues that each feed an exclusive process. The main queue is of infinite size while the local queues have a maximum capacity of three. I increased the number of entities generated and shortened up some of the queue traverse and process times, which allows us to observe the behavior of the local queues when they fill up completely. I see a couple of things I still need to fix. One is that the Path components feeding each of the local Queue components should not be flagged as exclusive unless the number of entities on the path and in the local queue are equal to the maximum capacity. I also need to review the code for the distribution logic (in this case from Queue 4 to local Queues 7 and 8). The code that calculates where the next entity is going to go gets called more often than an entity is available to be forwarded, so the distribution method does not operate as smoothly as it should.

Here’s the code that initializes the current configuration. It’s a lot of code so it won’t be long before I start trying to streamline and automate these declarations.

Here’s the code for the entire Queue component. Of special note is the logic for the forwardEntity method which supports three different methods for calculating the next destination of the forwarded entity (1: single connection, 2: distribution logic, 3: model routing logic). I’m going to have to adjust this a bit so I test for whether an entity can be forwarded before I run the distribution logic, or possibly all three types of logic. Pull requests sent from downstream components can exercise the logic when no entity is available to be pulled, and entities can finish traversing the queue but be preventing from moving downstream because the next components are blocked. It may be a simple matter of calculating a potential destination and saving it as a temporary variable, and then acting on it and updating the persistent variable when an entity can actually be forwarded.

The Process component works almost exactly the same way as the Queue component, except for the time being the maximum capacity is one.

Here’s the code for the Path component. It works largely the same way but each path currently supports only one previous and one next connection. Note the recursiive nature of the pullFromPrevious method, which passes the request through contiguous Path components until asking the first-enncountered non-Path (non-Entry) component to forward an entity.

At this point I’ve mostly worked out the procedures for routing entities forward using different kinds of logic, but I haven’t examined support for complex logic for pulling entities forward from multiple upstream connections. So far the pull logic has only been used for components with a single upstream connection (the code blindly references this.previousConnectionList[0]). What if multiple components are all trying to forward entities to the same exclusive component downstream? When the downstream component clears by forwarding one of its own entities, how does it know which upstream component to pull from? I’ve mentioned previously that the required logic, applicable only to pulling to exclusive components (non-exclusive components can simply receive everything sent to them) should work something like the distribution logic going forward, but an extra queue may be required. It’s also possible that the need to do this can be largely finessed by ensuring that some kind of non-exclusive queue is always included so the complex, rotating pull logic is never required. Alternatively, there may be a simpler solution I simply haven’t seen because I haven’t experimented with it yet. The pulling component, for example, could poll all of the connections to see which upstream has the oldest forwarding request outstanding, but there could be other considerations that demand a different priority order.

I’m slowly trying different combinations and catching inconsistencies but I’m getting the feeling that things are getting a little entropic. Continued inspection, testing, and honing should bring more loose ends into focus so they can be continually corrected and streamlined as opportunities present themselves. At some point I’m going to have to run tests against a number of configurations to ensure every combination of components is operating properly. That’s going on the To Do list.

I reworked the drawing of Path components so the line segment is drawn at the same time as all the other components are drawn, and then the drawModel function circles back to draw all of the nodes and then all of the entities. This makes the display look more consistent. I also removed the ending times for the display of entry and exit entity IDs since we know that mechanism works and because it saves space. Never mind that I added the maximum Capacity to the Queue component displays and the exit count to the Exit component. Finally, I changed the lower text region to stop displaying messages when the entry and exit ID information clears for each component. This means that some steps will execute without generating a message. This was done to reduce clutter so I could concentrate on debugging.

Posted in Simulation | Tagged , | Leave a comment

A Simple Discrete-Event Simulation: Part 47

Today I spent quite a lot of time really trying to nail down every facet of the logic to be used to route entities between components. I drew diagrams in Visio and I went through several modifications of a logic table in Excel until things started to become clear to me. The table is shown directly below (scroll sideways to see the whole thing).

 
The Arrivals component is not discussed in the table because it logically transfers entities only to Entry components which must be able to receive them at all times. Entry components forward entities immediately upon receipt to other components that are likewise required to receive them. Exit components are required to immediately receive all entities. Entry components, trivially, should not be connected directly to Exit components. Beyond that things get interesting.

I found that the basic connection logic repeats consistently across most connections between most combinations of components and it works like this. If the receiving components are non-exclusive they can immediately receive any entities forwarded to them. It may be that very few instantiations of Process components would not be exclusive (i.e., limited in the number of entities it can hold at one time) but it is possible to imagine such things. Queues are exclusive when a hard capacity is defined for them (this can be done in many ways but for now we’ve only implemented a simple one that goes by entity count). When downstream components are defined as being exclusive they cannot receive entities until they clear and give permission. If sending entities have to wait for permission to forward entities to exclusive downstream components they “lose” their future events queue item and go into an implicit wait state. It is therefore up to the exclusive downstream entity to send a request back upstream to the sending entity to get things moving again. The upstream entity sends the next entity if one is ready.

If a sending component is connected to a single downstream component (with or without a Path component), the handshaking procedure is straightforward. If a sending component is linked to multiple downstream components of the same type it uses distribution logic to try to forward entities downstream on a rotating basis (subject to those components being closed). When downstream components clear they turn around and send a request back upstream to pull the next entity. If a sending component is linked to multiple downstream components of different types (we’ll discuss this going forward–in this case the downstream components might all be of the same simulation type, e.g., Process, but they may all be different logical types which represent different real world activities, which is the point of this exercise), then the entities are forwarded downstream to destinations based on a routing table. This works the same way as the connection between the Arrivals component and the Entry components where a random number determines the destination. If the upstream component cannot send an entity downstream because the receiving entity is exclusive and closed it waits until the downstream component clears and sends the necessary request.

I had a lot of visions in my head of possible complication from thinking about all of this but filling out the logic table in detail helped me organize and clarify all of them. The first insight I had was that distribution logic is pretty simple. The upstream component can either forward and entity to a downstream component or it can’t. If it can’t it wait for the next downstream component to send a request back upstream. Things get trickier when using routing logic in that the upstream entity might have to wait to send an entity downstream to a component that is exclusive and closed. The question then becomes whether the next entity in the upstream component, that wants to be forwarded to a different downstream component, has to wait for the entity ahead of it to get out of the way. There are some cases where entities do have to wait for others in front of them to clear and other cases where they do not. I refer to this as downstream exclusivity, and I’ll be creating a new component property to handle this setting. Components like Bags (e.g., parking lots) would usually be non-exclusive while single-path/FIFO queues and processes would usually be exclusive. A more general type of queue might be non-exclusive in this way.

The logic for Path components is also a bit confusing. When talking about Path components connecting to other types of components we see that for the most part Path components take on the exclusivity characteristic of the downstream component. When talking about other types of components connecting to Paths we see that the idea of multiple components connecting to a single Path doesn’t make much sense. For the time being, finally, we see that Paths connecting to other Paths only can be done serially without branching.

So far I’ve discussed what happens when a single component connects to one or more components in the downstream direction. We also need to analyze what happens when multiple upstream components connect to a single downstream component. If the downstream component is not exclusive then no big deal–the downstream component (think of an Exit component or a non-exclusive Queue component) simply receives every entity sent to it. If the downstream component is exclusive, however, then the downstream component may have to maintain a queue to keep track of the order in which it should send requests back to the upstream components. Alternatively, it could simply rotate through the upstream components in a mirror of the distribution logic used to forward entities downstream. But wait–it gets even crazier! What if multiple upstream components are connected to multiple downstream components in a many-to-many fashion? In that case it seems like all of the downstream components would have rotate their pull requests through the upstream components. This logic will get tested and implemented after everything else discussed here has been addressed. I’m actually not sure how often it would really come up, but we definitely have to keep this idea in mind.

This idea is captured in the logic table as the lines for downstream components being connected to single upstream components (1 src) or being connected to multiple upstream sources (>1 src). A lot of the logic doesn’t change between having one upstream source or many, but some does.

Let me formally add to the existing To Do list:

  • New property for forward exclusivity as opposed to receiving exclusivity.
  • Formalize and implement method of receiving from multiple upstream components in turn. Implementing and observing this may illuminate the behaviors that will need to be implemented for the general path solution described in one or more previous posts.
Posted in Simulation | Tagged | Leave a comment

A Simple Discrete-Event Simulation: Part 46

Today I got the properties and methods all named consistently and in the same order for every component type, and also included all of the necessary getters and setters (they are good practice to have–though perhaps less so for client-side web code–and will be needed when the display and external data monitoring mechanisms are used), and managed not to break anything. I extended the spreadsheet to include expected definitions for Control, Bag, and Stack components per previous descriptions, though I haven’t implemented them yet.

If I were doing this in a traditional object-oriented language I would definitely implement a base component and add customizations as needed. I may end up doing this after a fashion when I research JavaScript’s prototype object pattern.

As I described yesterday you can see the colors changing on the Process components and the Path components that feed them, according to their ability to receive new entities. I also changed the label for each component data display so it includes the component index. This makes the displayed information a bit more compact. I suppose at this point I could also do away with the labels showing when the entry and exit events notifications are going to be cleared.

Posted in Simulation | Tagged | Leave a comment