Salabim

Latest version: v25.0.8

Safety actively analyzes 723400 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 20 of 28

2.2.14

==========================
New functionality
-----------------
Standby components just getting current and go into standby again can now be excluded from the trace.
This can be controlled with the method Environment.suppress_trace_standby().
By default, standby is excluded from the trace.


Added functionality to read item based input files (inspired by TomasRead).
Therefore, the class ItemFile is added to salabim.

Example usage:
with sim.ItemFile(filename) as f:
run_length = f.read_item_float()
run_name = f.read_item()

Or (not recommended):
f = sim.InputFile(filename)
run_length = f.read_item_float()
run_name = f.read_item()
f.close()

The input file is read per item, where blanks, linefeeds, tabs are treated as separators.
Any text on a line after a character is ignored.
Any text within curly brackets ( {} ) is ignored (and treated as an item separator).
Note that this strictly on a per line basis.
If a blank is to be included in a string, use single or double quotes.
The recommended way to end a list of values is //

So, a typical input file is:

Typical experiment file for a salabim model
1000 run length
'Experiment 2.0' run name

Model speed color
-------------- ----- ------

'Peugeot 208' 150 red
'Peugeot 3008' 175 orange
'Citroen C5' 160 blue
'Renault "Twingo"' 165 green
//

France {country} Europe {continent}

end of file

Instead of the filename as a parameter to ItemFile, also a string with the content can be given. In that
case, at least one linefeed has to be in the content string. Usually, the content string will be triple
quoted. This can be very useful during testing as the input is part of the source file and not external, e.g.

test_input = '''
one two
three four
five
'''
with sim.ItemFile(test_input) as f:
while True:
try:
print(f.read_item())
except EOFError:
break



2.2.13

==========================
New functionality
-----------------
It is now possible to use arguments for the process generator of a component. Only keyword arguments are supported.
Parameters can either be set at initialization of a component or the call to activate. E.g.:

import salabim as sim
class Car(sim.Component):
def setup(self, color):
self.color=color

def process(self, duration):
print(self.color, duration)
yield self.hold(duration)
yield self.activate(process='process', duration=50) this restarts the process

env=sim.Environment(trace=True)
Car(color='red', duration=12)
env.run(100)

Note that the keywords used by the process generator are not passed to setup(), at initialization of a component.
That means that setup() can't have the same parameters as the process called at initialization (usually process()).
Furthermore, neither the process generator nor setup() can use
at, delay, urgent, process, keep_request, keep_wait when called from activate()
name, suppress_trace, suppress_pause_at_step, mode, env, at, delay, urgent, process at initialization of a component
as parameters.

Bug fix
-------
Corrected bug when tracing a standby component.

Optimization
------------
Optimized animation perfomance by improving the interpolate function.

2.2.13a

===========================
Bug fix
-------
The just introduced functionality to use parameters for processes did not work under Python prior to version 3.4, so
also not under Python 2.7|.

This intermediate version fixes that.

2.2.12

==========================
In the trace the line numbers are now prefixed by a letter to indicate
in which file the line is in.
The file from which the environment is created is not prefixed.
The trace will issue a line when a not yet used source file is referenced.

New method Environment.print_trace_header() will print a header.
If an Environment is initialized, the trace_header is also printed provided trace=True.

Now MonitorTimestamped.xt() and MonitorTimestampled.tx() add the last tallied value along with
the current time as the last x- and t-value. This can be turned off by specifying add_now=False.

Defining MonitorTimestamp is now much simpler as it is no longer required to use a getter function.
Instead, the caller has now to provide the value to be tallied directly to the tally() method.
When initializing a timestamped monitor, an initial_tally can be provided (by default 0).

Added IntUniform distribution to sample integer values in a given range, for example:
die = sim.IntUniform(1,6)

Added method bounded_sample to all distributions, to force sampling of a distribution within given bounds.
This is, for instance, useful when sampling from a normal distribution, where the sample has be positive:
s = Normal(8,5).bounded_sample(lowerbound=0)

Added Component.queues() which returns a set of all queues where the component is in.
Added Component.count() which returns the number of queues the component is in or 1 if the component is in the queue, 0 otherwise

Added a method Environment.beep() which can be useful to attract attention, etc. Note that this works only under Windows or iOS (Pythonista).
For all other platforms, this is just a dummy function.

Component.index_in_queue() renamed to Component.index() to be consistent with Queue.index()

Significant updates to the documentation (structure).

Optimizations by checking _trace flag before calling print_trace.

2.2.11

==========================
Enhanced trace output
---------------------
The trace output now also shows the line number in the source code. This can be extremely
useful when debugging or learning.

E.g. the following code

1|import salabim as sim
2|
3|class X(sim.Component):
4| def process(self):
5| yield self.hold(10,mode='one')
6| if self == x1:
7| yield self.passivate()
8| yield self.hold(10,urgent=True, mode='two')
9|
10|class Y(sim.Component):
11| def process(self):
12| yield self.request((res, 4), fail_at=15)
13| x1.activate()
14|
15|env=sim.Environment(trace=True)
16|res = sim.Resource()
17|
18|x0=X()
19|x1=X()
20|Y()
21|
22|env.run(50)

prints:

line time current component action information
----- ---------- -------------------- ----------------------------------- ------------------------------------------------
15 main create
15 0.000 main current
16 resource.0 create capacity=1
18 x.0 create
18 x.0 activate scheduled for 0.000 4 process=process
19 x.1 create
19 x.1 activate scheduled for 0.000 4 process=process
20 y.0 create
20 y.0 activate scheduled for 0.000 11 process=process
22 main run scheduled for 50.000 22+
4 0.000 x.0 current
5 x.0 hold scheduled for 10.000 5+ mode=one
4 0.000 x.1 current
5 x.1 hold scheduled for 10.000 5+ mode=one
11 0.000 y.0 current
12 y.0 request for 4 from resource.0
12 y.0 request scheduled for 15.000 12+
5+ 10.000 x.0 current
8 x.0 hold scheduled for 20.000! 8+ mode=two
5+ 10.000 x.1 current
7 x.1 passivate mode=one
12+ 15.000 y.0 current
22 y.0 request failed
13 x.1 activate scheduled for 15.000 7+ mode=one
y.0 ended
7+ 15.000 x.1 current
8 x.1 hold scheduled for 25.000! 8+ mode=two
8+ 20.000 x.0 current
x.0 ended
8+ 25.000 x.1 current
x.1 ended
22+ 50.000 main current

Note that output line now starts with the line number in the source.
If a + is behind the line number, that means the statement following that line.
Also, for components to be scheduled the line number where the component will start execution
is shown following the sign.
Urgent scheduling is now indicated with an ! sign behind the time.

Distributions
-------------
New distributions:
Beta
Erlang
Gamma
Weibull

Exponential distributions can now be specified with a mean (beta) or a rate (lambda).

Normal distributions can now be specified to use the alternative random.gauss method.


New parameter for class Component
---------------------------------
suppress_pause_at_trace


New methods
-----------
Component.suppress_pause_at_trace

Sampling from a distribution is now also possible by just calling the distribution, like:
yield self.hold(inter_arrival_time())
, which is equivalent to
yield self.hold(inter_arrival_time.sample())

Documentation update
--------------------
The online documentation is now better structured and more accessible.
Also, a lot of content added, although still not complete. As always, volunteers are welcome
to help in improving the manual!

The documentation makes clear now that the time stamps as used in timestamped monitors are
not adjusted for reset_now().

2.2.10

==========================
New methods:
Component.remaining_duration()
This method returns the duration left of a hold, request or wait at the time a passivate
was given.
For components that are scheduled, the remaining time to the scheduled time is returned.
This is very handy to interrupt a component's hold for a, like in
class Machine(sim.Component):
def process(self):
while True:
yield self.hold(produce_one_part)
number_of_parts += 1

class Disturber(sim.Component):
def process(self):
while True:
yield self.hold(time_to_failure)
machine.passivate() interrupt the production
yield self.hold(time_to_repair)
machine.hold(machine.remaining_duration()) resume production

Environment.reset_now()
This method can be used to reset now, by default to 0.
All times communicated to/from the application will be according to the new time.
Be sure to adjust any user defined times as these will not be updated automatically!

Internally, the reset is realized by keeping track of the offset of the time.

Naming of object changed:
In previous versions when initializing an object (Environment, Component, Queue, Resource, State,
Monitor or MonitorTimestamped) where the name ended with a period , the sequence number (0) was
suppressed for the first object.
When a second object with the same name was initialized, that first object was renamed and got
a 0 as sequence number. Now, an object with a name ending with a period is always serialized.
If the name ends with a comma, the sequence starts at 1 (and the , is replaced by a .).
E.g.
for i in range(2):
a = Airplane(name='airplane')
b = Boat()
c = Car(name='car,')
print(a.name())
print(b.name())
print(c.name())

Result:
airplane
boat.0
car.1
airplane
boat.1
car.2

The name() method no longer supports renaming an object, i.e. can only be used to get the name.

Change of name:
Queue.intersect has been renamed to Queue.intersection.

New queue functionality:
The intersection of two queues can now be assessed also with the & operator, e.g. q1 & q2.
The union of two queues can now be assessed also with | operator, e.g. q1 | q2.
The difference of two queues can now be assessed also with the - operator, e.g. q1 - q2.
The symmetric_difference of two queues (new method) can be assessed also with the ^ operator, e.g. q1 ^ q2.

Queues have a couple of new methods, to be more in line with list and set functionality:
append() is equivalent to add
pop now also supports an index
del q[] can now be used to delete one component, e.g. q[4] or a component by slice, e.g. q[3:5]
remove without an argument now clears a queue completely
extend can be used to add component at the tail of a queue from a queue or list
initialization of queues with a queue, list and tuple

as_set() can be used to get all components in a queue as a set.
as_list() can be used to get all components in a queue as a list.
q[:] can be used to get all components in a queue a list.

The Queue methods union, difference, intersection, copy and move now support default (meaningful) names.

New color functionality:
The method Environment.animation_parameters now has an additional parameter, foregroundcolor.
If not specified, salabim automatically chooses the most contrasting color (white or black).
This foreground color is used to show the system button, the time, modelname.
Besides, several colors in Animate, AmimateButton and AnimateSliders now defaults to
this foreground_color.

Also, it is now possible to specify 'fg' for the foreground color and 'bg' for the background color when
a color is required.

Internal:
Several optimizations.
Better checks for validity of colors.

Page 20 of 28

© 2025 Safety CLI Cybersecurity Inc. All Rights Reserved.