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

A Simple Discrete-Event Simulation: Part 45

Today I spent quite a lot of time updating the components so they could handle connections to multiple incoming and outgoing paths where appropriate. I was making some headway when I realized I needed to back up and review what I was doing. I spent the rest of the day figuring out how to make things more consistent, which means trying to use the same property and method names in the same order as much as possible, as well as implementing similar methods as close as possible to the same way. There is still a lot to do on that front, which I will hopefully finish tomorrow. I made a spreadsheet that listed all the characteristics for each component type, and the three sections of it are shown below. I made them scrollable so they remain readable but can also be viewed on smaller devices.

The first section shows how the main functions the components have in common incorporate mostly the same steps.

 
The second section shows all the properties currently used in the components, and whether they are common to most or all of the components or unique to that type.

 
The third section shows all of the methods used in the components, and whether they are common or unique to that type.

 
This work illustrates that there are still a lot of opportunities to polish things. Now that I have most of my thoughts in place in a semi-organized way I can also use this information to draw the connections out graphically — by hand, on paper, in this case — so I can get the clearest understanding of what I want to do.

There were a couple of side-tracks today as well. One involved the first bits of the routing system based on model logic vs. distribution logic. This idea has already been touched on in the mechanism the Arrivals component uses to distribute entities to the Entry components, but there are a few more shades of complexity to discuss and work through still.

The other involved changing the color of component lines or outlines to show their open status, which is the ability for components marked as “exclusive” to receive additional entities. This is just a hack for now because I’m using the (old version of) the data display mechanisms to stand in for the representation of the components. Doing that in a more visually appealing way, along with using the newer version of the data display mechanism, will make things a lot cleaner. The exclusivity logic is moderately tricky because I’m trying to plan for a lot of contingencies, including supporting this functionality across multiple incoming or outgoing connections. Again, drawing things out should help.

Posted in Simulation | Tagged | Leave a comment

A Simple Discrete-Event Simulation: Part 44

Tackling the first item on yesterday’s to do list requires thinking about what we want to implement in an organized way. I found that writing out the requirements helped clarify things. Here’s what we need component by component:

Arrivals component
  in: N/A
  out: entryList[] – array of logical connections to entry components

Entry component
  in: N/A – these components can always accept entities from the Arrivals component
  out: nextComponentList[] – distributes entities downstream to a mix of component types according to model routing logic

Queue component
  in: previousComponentList[] – these components can either be configured to always accept entities from upstream components of all types or refuse to accept entities subject to a defined capacity; in the latter case the Queue will have to be able to cycle through the incoming connections in turn to accept or retrieve new entities; see the propagation discussion in the description of the Process component directly below.
  out: nextComponentList[] – distributes entities downstream to a collection of similar components using plaza distribution logic

Process component
  in: previousComponent – links to single upstream component only; if the component is a path the path propagates the isOpen value; retrieves entity when clear
  out: nextComponentList[] – distributes entities downstream to a mix of component types according to model routing logic

Exit component
  in: N/A – these components can always accept entities
  out: N/A

Path component
  in: previousComponent – links to single upstream component only, propagates isOpen status and retrieval requests from downstream components
  out: nextComponent – links to single downstream component only, propagates isOpen status and retrieval requests from downstream components

The Path components should be implemented in a way that allow multiple units to be strung together in series and carry on the same propagation behavior. The propagation of statuses and requests should stop when the chain reaches an upstream component that is not a path. (There are several ways of implementing this that might save some of the propagation details.)

This list reminds me that we’re ultimately going to need some more component types. I can think of two for now. A Control governs the destinations to which an entity can be forwarded. A Bag is a container that can hold numerous entities that can be received and forwarded according to arbitrary, non-FIFO or non-LIFO logic. I guess this means we should also define a Stack component, doesn’t it? With these definitions in mind:

Control component
  in: previousComponentList[] – links to multiple upstream components
  out: nextComponentList[] – links to multiple downstream components; purpose is to control access or distribution to downstream components according to external rules

Bag component (think: parking lot)
  in: previousComponentList[] – links to multiple upstream components
  out: nextComponentList[] – links to multiple downstream components; distributes entities downstream to a mix of component types according to model routing logic

Stack component
  in: previousComponentList[] – links to multiple upstream components(?)
  out: nextComponentList[] – links to multiple downstream components(?); distributes entities downstream to a mix of component types according to model routing logic

I’m sure a use case for the stack component can be identified, but I haven’t come up with one yet that makes it clear in my mind what capabilities it should have. On the lean/TDD/YAGNI principle I’m not going to implement this until it is needed.

Next time I’ll work on implementing this. It occurred to me when I did an analysis of these ideas a couple of years ago that it might be a good idea to embed Queue capabilities into Process components, effectively merging the two types into one. There could still be a need for a separate queue object (to feed multiple processes that each have their own embedded small queue). Beyond the case of independent queues feeding queues that feed processes, it also occurs to me that queues are almost solely used to feed processes. The idea of general queues feeding process queues also suggests that the Queue component (or at least the queue-merged-with-process component) may need to implement an isOpen test based on having a limited capacity. This would involve duplicating all of the upstream permission and retrieval behaviors of the Process component.

In the not-too-distant future I’m going to look into making processes be able to handle multiple entities in parallel (independently and possibly in batches) and serial. Remember that we’re just using the Path components as logical connectors to make the process flow more visually clear, in reality the components could all be stitched together without using paths at all using the rules we’ve defined. Indeed, that’s where this exercise started.

Looking at how this has evolved, finally, I can’t help but wonder if I shouldn’t just include the ability to support multiple upstream (previousComponentList[]) links to the Process components as well. I’m going to sleep on that one.

This discussion adds a few more items to the to do list:

  • 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
Posted in Simulation | Tagged | Leave a comment