June 25, 2014

Swift, Objects, Arrays, and Simulation

Posted in iPhone development, mac development, simulation tagged , , , , at 9:24 pm by tetontech

One of the tasks I give myself when learning a new language is to write a traditionally designed discrete event simulation engine. This is due to my background in creating and supporting simulation software for the semi-conductor industry. Another reason is that it gives me a frame of reference I’m comfortable with and allows me to focus on how the different parts of the new language interact with each other.

To highlight certain Swift concepts and how they can interact I’ll go over some of my simulation engine’s code. The entire code set is available on gitHub in the SimSwift-Traditional repository. It includes 3 files – Engine.swift, Event.swift, and ViewController.swift.

The simplest file is Event.swift so let’s start there. It describes the Event class, its attributes, and its behaviors.

The Event class has two constant properties, an integer that represents the time that the event should occur, and a closure or function that is the action to be taken at that time. The trigger time is used by the engine to sort and group events that need to happen. I chose Int as the datatype to allow maximal flexibility for the engine. Time in the engine could be milliseconds since the unix epoch time. It could also be zero based and have each event trigger at some number of seconds, milliseconds, hours, days, or some other offset from the beginning of the simulation.

 24 import Foundation
 25 
 26 class Event{
 27     let triggerTime:Int
 28     let action:()->()
 29 
 30     init(aTriggerTime:Int, anAction:()->()){
 31         triggerTime = aTriggerTime
 32         action = anAction
 33     }
 34 }

The Event class includes an init method. Swift classes need to have init methods to set properties. If you don’t declare an init method Swift will not generate a default at compile time in most cases. In the init method  the parameters are assigned to their matching properties. You also see that the parameters are named parameters. This means that when init is called the parameter names are used to delimit the parameters. I’ll show you how to use the delimiters when we look at some of the code in the ViewController.swift file.

The simulation engine class, TraditionalEngine, has three variable properties. The time property represents the ‘current’ time of the simulation, futures are events that need to happen at some future time, and presents are events that have trigger times that match the ‘current’ time of the simulation.

class TraditionalEngine{
    
    var time:Int
    var futures:Array<Event>
    var presents:Array<Event>
    
    init(startTime:Int){
        time = startTime
        futures = Array<Event>()
        presents = Array<Event>()
    }

The init method for the TraditionalEngine class has one named parameter, startTime. startTime represents the initial time of the simulation. The futures and presents arrays are set to empty arrays so events can be added later.

I’ve given the engine an addEvent method. It has one named parameter, an. One purpose of the addEvent method is to determine if the event should be added to the presents or the futures array. Which it is added to depends on if the event’s triggerTime is after the current time of the simulation.

    func addEvent(an:Event){
        an.triggerTime > time ? insertEvent(an, isFuture: true)
                                     : insertEvent(an, isFuture: false)
    }

I chose to use Swift’s ternary operator ( ? : ) for reasons of succinctness. If the event’s trigger time is greater than the simulation’s current time the event is inserted into, not appended to, the futures array, otherwise it is inserted into the presents array. In either case a binary search insertion is performed.

Why do insertion in the presents list? From industry experience I know that events users setup to start simulations sometimes happened in the past. By using an insertion based approach, events in the past will be triggered before the current ones. Let’s look at the code that does the insertion later. First we’ll take a look at the simulation’s run loop found in the engine’s go method.

While there are events waiting in the future or events for the current time the simulation loop continues. In the loop any present events are triggered and then the next group of events are found, executed, and the loop continues. This is the heart of any traditionally designed simulation engine.

    func go(){
        while(self.futures.count > 0 || self.presents.count > 0){
            self.doAnyPresents()
            self.doNextGroup()
        }
    }
    
    func doAnyPresents(){
        while presents.count > 0 {
            presents.removeAtIndex(0).action()
        }
    }
    
    func doNextGroup(){
        if futures.count > 0 {
            let nextPresent = futures.removeAtIndex(0)
            self.time = nextPresent.triggerTime
            nextPresent.action()
            while futures.count > 0 
                  && futures[0].triggerTime == self.time{
                futures.removeAtIndex(0).action()
            }
        }
    }

The doNextGroup method pops the first event off the futures array and sets the simulation’s current time to the popped event’s triggerTime. This is what causes time to move forward in the simulation. Thankfully, it also means we don’t need to simulate the time between events when nothing is happening. The doNextGroup method executes all events that match the current time.

Why then does the simulation loop always call doAnyPresents before calling doNextGroup? In discrete event simulations it is common for events to create new events that have the same trigger time as the current time. Rather than make the programmer using the simulation’s API write if statements all over in their code they can use the addEvent method and not have to worry about which Array to add it to. If the event has a trigger time that matches the simulation’s current time it will end up in the currents Array and be executed before the simulation moves on to the next group of events.

Rather than put a code listing for the entire insertEvent method please go view it or download the source from the gitHub repository. It is a standard binary search for an insertion point. To minimize computation, a check is done before doing the binary search. If the trigger time of the event being added is less than the first event’s trigger time the event is prepended. If it is greater than the last event’s trigger time the event is appended. If it is somewhere in-between the binary search process is executed. See the source from gitHub to for the full implementation of the binary insertion algorithm.

One part of the implementation is interesting. To avoid the array copy problem explained in a previous post, the engine’s list properties are modified directly rather than trough a facade-like approach.

isFuture ? futures.insert(an, atIndex: midIndex) 
         : presents.insert(an, atIndex: midIndex)

This line of code is longer and less expressive than I would like it to be but it does avoid the copy problem.

There is some sample code in the ViewController class that shows the engine’s API being used. In it a TraditionalEngine is instantiated and stored as a parameter of the ViewController. 0 is used as the start time of the simulation so all event triggerTimes are considered to be time offsets. In viewDidLoad 50 random integers from 0 – 100 are created and if any of them are a multiple of 15 they are made negative. This will exercise the code handling the situation where the simulation has events to process from before the beginning of the simulation.

class ViewController: UIViewController {
    let theEngine = TraditionalEngine(startTime:0)
                            
    override func viewDidLoad() {
        super.viewDidLoad()
        
        for index in 0..50{
            var randNum = Int(arc4random() % 100)
            if randNum % 15 == 0 {
                randNum = -randNum
            }
            let capturedNum = Int(arc4random() % 50)
            theEngine.addEvent(Event(aTriggerTime: randNum, anAction: {
                println("triggered at: \(randNum) with 
                                   captured: \(capturedNum)")
                }))
        }
        theEngine.go()
    }
}

I’ve used a closure as the action for the events. I chose a closure to show how a constant or variable could be captured and used later when the event’s action is triggered.

All in all, Swift worked quite well for creating a traditionally designed simulation engine.

Advertisement

September 5, 2008

erlSim Beta Released

Posted in erlang development tagged , , , , , at 3:55 pm by tetontech

erlSim, a discrete event simulator written in erlang, has been released and is available at
sourceForge.
This simulation engine takes advantage of erlang’s high concurrency and speed of execution. It also includes several random distributions that are typically used in simulations such as the triangular and normal distributions.

Included in the downloadable package are test harnesses for the simulation engine as well as some of the distributions. These distributions are a work in progress. Many of them have not even been run let alone tested. Those that have test harnesses should be working.

The intriguing idea behind using erlang as a discrete simulation environment is that each tool, object, person, etc. in the simulation could be an individual process. Or, if you wanted, each process that acts on simulation entities could be an erlang process. The engine doesn’t care how you chose to create your simulation.

May 19, 2008

Erlang Simulation Testing Times

Posted in erlang development tagged , , at 7:54 pm by tetontech

The Erlang simulation engine, which I now call erlSim, is running. I have some test results that show the concurrency capabilities of the Erlang language and the erlSim simulator.

Num Processes Events per Process Total Events Seconds per Event Total Time
1 1 10 0.000079900000 0.000799
5 1 50 0.000009260000 0.000463
1 10 100 0.000016520000 0.001652
25 25 6250 0.000014700640 0.091879
100 100 100000 0.000014360140 1.436014
200 200 400000 0.000015691415 6.276566
50 1000 500000 0.000015591182 7.795591

Event Times by Concurrent Process Count

This information indicates that as the number of concurrent processes increases there is not a significant increase in the speed each process requires.
This data was generated on :
2.4 Ghz Intel Core 2 Duo
2 GB RAM
OS X MacBook
Erlang (BEAM) emulator version 5.6.1

This is looking very promising as a basis for discreet event simulations. I am working on a series of random number streams (triangular, normal, beta, etc.) to go with this basic engine. It is nearing completion for eight different random number stream types.

May 16, 2008

Erlang Simulator

Posted in erlang development tagged , , , at 5:04 pm by tetontech

Erlang is an interesting language.  It appears to be hugely concurrent without threads in the language.  It has its’ own strangeness such as the lack of variables, loops, etc. but overall very interesting.

I have created a modular discreet event simulation engine that takes advantage of the languages possibilities.  It has allowed me to make full use of both cores on my machine and have thousands of concurrent simulation events executing.  I have not noticed much of a per event execution penalty either.  Very interesting.

I am looking forward to creating a factory scheduling simulation package based on this work.

There are now testing times available in this follow up entry
Erlang Simulation Testing Times.

%d bloggers like this: