You are here: Home software stepsim

stepsim

A lightweight step-based simulation module written in Python.

About

StepSim is a lightweight step-based simulation module written in Python. It can do simple real-time simulations of discrete systems. StepSim supports step-by-step simulation or can run until a break condition occurs.

Simulations are made up of containers and converters. A container stores a discrete amount of units of a certain type. A converter draws units from one or more containers and delivers the result to another container.

StepSim does not even attempt to do any parallel processing. It processes converters round-robin in a fixed order.

Prerequisites

Python (tested on Python 3.1.2 and 2.6.5) http://www.python.org

Installation

Unzip the file, then at the command line run

python setup.py install

Running Tests

Open a shell / DOS window, navigate to the stepsim directory, and run

python -m doctest README

Documentation

To read the API documentation, open a shell / DOS window, navigate to the stepsim directory, and run

pydoc stepsim

You can create a HTML version using

pydoc -w stepsim

Example

First import the stepsim module:

>>> import stepsim

To get verbose output, activate logging to console:

>>> stepsim.log_to_stdout()
>>> stepsim.loglevel("debug")

Now create some containers:

>>> cashbox = stepsim.Container("cashbox", "EUR", 10)
>>> storage = stepsim.Container("storage", "parts")

Then create a converter and set up the draw-deliver-ratio:

>>> buyer = stepsim.Converter("buyer", 2, (cashbox, 3), (storage, 2))
buyer: Adding source 'cashbox', drawing 3 EUR per step.

From any list of converters, we can get a list of simulation milestones that lead to an end condition (without explicitly creating a simulation):

>>> stepsim.loglevel("info")
>>> stepsim.milestones("storage == 3", [buyer])
------------------------------
Milestones to achieve storage == 3:
<BLANKLINE>
Milestone:
6 EUR in cashbox (10 delivered, 166.67%)
total: 100.0%
<BLANKLINE>
Milestone:
3.0 parts in storage (0 delivered, 0.0%)
total: 0.0%
------------------------------
[<Milestone (cashbox: 6) 100.0%>, <Milestone (storage: 3.0) 0.0%>]

Let's create a simulation:

>>> stepsim.loglevel("debug")
>>> s = stepsim.Simulation(buyer)
Adding converter 'buyer' to simulation.
Current containers: ['cashbox', 'storage']
>>> s
<Simulation, converters: [<buyer: converting from ['cashbox'] to storage>], containers: [<cashbox: 10 EUR in stock>, <storage: 0 parts in stock>]>

The step() method is used to advance the simulation by one step:

>>> stepsim.loglevel("info")
>>> s.step()
buyer: Drawing 3 EUR from cashbox.

It is also possible to check conditions inbetween. The simulation instance offers a convenience method to do this using a string describing the condition:

>>> s.check("cashbox == 10")
False
>>> s.check("cashbox != 10")
True
>>> s.check("storage >= 0")
True

It is possible to evaluate how many steps it will take until a certain condition is met:

>>> stepsim.be_quiet()
>>> s.estimate_finish("storage == 2", 100)
4

Behind the scenes, this will run a copy of the simulation. A maximum step value will prevent hanging on impossible conditions:

>>> s.estimate_finish("cashbox < 1", 100)
100

When you remove a converter, its last step will be reverted. Note that this does not rewind the simulation step counter.

>>> stepsim.log_to_stdout()
>>> stepsim.loglevel("debug")
>>> s.step()
buyer: Conversion in progress, 2 steps left.
Active Container of buyer: None
>>> s.remove_converter("buyer")
reverting last draw from 'buyer'
buyer: returning 3 EUR to cashbox.
Removing converter 'buyer' from simulation.
Current containers: []

It is possible to limit the number of units that a converter will deliver.

>>> buyer.set_max_units(3)
buyer: setting max_units to 3

Note that this command will reset the counter of units delivered.

By stepping through the simulation, we can check when the converter stops.

>>> s.add_converter(buyer)
Adding converter 'buyer' to simulation.
Current containers: ['cashbox', 'storage']
>>> s.step()
buyer: Ready to draw resources
buyer: Drawing 3 EUR from cashbox.
cashbox has 7 EUR left now.
buyer: Setting processing countdown to 2 steps
Active Container of buyer: <cashbox: 7 EUR in stock>
>>> s.step()
buyer: Conversion in progress, 2 steps left.
Active Container of buyer: None
>>> s.step()
buyer: Conversion in progress, 1 steps left.
Active Container of buyer: None
>>> s.step()
buyer: Delivering 2 parts to storage.
storage stock is 2 parts now.
buyer has delivered 2 units since last reset.
Active Container of buyer: <storage: 2 parts in stock>
>>> s.step()
buyer: delivered 2 units and would deliver 2 next step, max units is 3, no action.
>>> s.step()
buyer: delivered 2 units and would deliver 2 next step, max units is 3, no action.

With the maximum number of units set to -1, the converter will deliver an unlimited number. This is the default.

>>> buyer.set_max_units(-1)
buyer: setting max_units to -1

It is possible to temporarily change the speed of the converter by giving the temporary steps value and a duration. This method will return True if the change was successful:

>>> buyer.set_temporary_steps(4, 4)
buyer: setting steps = 4 for 4 steps
buyer: setting remaining countdown to -1
True
>>> s.step()
buyer: Ready to draw resources
buyer: Drawing 3 EUR from cashbox.
cashbox has 4 EUR left now.
buyer: Setting processing countdown to 4 steps
Active Container of buyer: <cashbox: 4 EUR in stock>
>>> s.step()
buyer: Conversion in progress, 4 steps left.
Active Container of buyer: None
>>> s.step()
buyer: Conversion in progress, 3 steps left.
Active Container of buyer: None
>>> s.step()
buyer: Conversion in progress, 2 steps left.
Active Container of buyer: None
>>> s.step()
buyer: Conversion in progress, 1 steps left.
Active Container of buyer: None
>>> s.step()
buyer: Delivering 2 parts to storage.
storage stock is 4 parts now.
restoring buyer.steps to 2
buyer has delivered 2 units since last reset.
Active Container of buyer: <storage: 4 parts in stock>

We can run the simulation from the current state until an end condition is satisfied. In this case we let it run until the buyer can not buy any more parts:

>>> s.run(lambda: not buyer.last_step_successful)
Starting simulation.
--- Step 15: -----------------------------------------------
buyer: Ready to draw resources
buyer: Drawing 3 EUR from cashbox.
cashbox has 1 EUR left now.
buyer: Setting processing countdown to 2 steps
Active Container of buyer: <cashbox: 1 EUR in stock>
--- Step 16: -----------------------------------------------
buyer: Conversion in progress, 2 steps left.
Active Container of buyer: None
--- Step 17: -----------------------------------------------
buyer: Conversion in progress, 1 steps left.
Active Container of buyer: None
--- Step 18: -----------------------------------------------
buyer: Delivering 2 parts to storage.
storage stock is 6 parts now.
buyer has delivered 4 units since last reset.
Active Container of buyer: <storage: 6 parts in stock>
--- Step 19: -----------------------------------------------
buyer: Ready to draw resources
buyer: Cannot draw 3 EUR from cashbox, only 1 left.
Active Container of buyer: None
--- Break condition met, simulation finished. ---------------
Final state after 19 steps:
<cashbox: 1 EUR in stock>
<storage: 6 parts in stock>

You can export the simulation graph in the DOT graph language (see http://www.graphviz.org/):

>>> s.save_dot("part_buyer.dot")
Writing DOT file.
digraph {
    graph [size=5] ;
    node [fontsize=10, fontname="Bitstream Vera Sans"] ;
    "cashbox" [shape=box];
    "cashbox" -> "buyer" ;
    "storage" [shape=box];
    "buyer" -> "storage" ;
}
<BLANKLINE>

Clean up:

>>> import os
>>> os.remove("part_buyer.dot")

The file 'making_cakes.py' shows a more elaborate example. It is included in the ZIP archive and will be installed in 'share/doc/stepsim/examples'.

License

StepSim is licensed under the GPL. See the file COPYING for details.

Links

StepSim on Bitbucket

StepSim on ohloh

StepSim on Freecode

StepSim in the Python Package Index

Author

(c) Florian Berger

Releases

Releases are signed with my OpenPGP key.

0.5.7

Released on 15 June 2013.

Fixed several bugs in milestones(), and made logging more verbose. Converters can be compared for equality now. Converter.steps_cached now officially indicates whether a temporary step value is active. Added method Converter.end_temporary_steps() to unconditionally reset a temporary step value. Converter.revert() no longer uses the Container.deliver() method to return items in order for them not being counted as delivered. Converter.draw() no longer checks how many units have been delivered, but how many would be delivered in the next step, and will refuse to draw when this would exceed Converter.max_units. Simulation.save_dot() now groups equivalent converters to a single graph node. Updated doctests in README.

stepsim-0.5.7.zip (MD5 51d778a1ba79410aecdf0bb902e8dd52)

stepsim-0.5.7.zip.asc

Older Releases

Older releases are available upon request.

© Florian Berger — Powered by PloneCO2-freie Website