Salabim

Latest version: v24.0.13

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

Scan your dependencies

Page 6 of 26

23.1.2

==========================

Added functionality(0)
----------------------

When animating a queue, with a trajectory, it is now possible to specify the
x and y coordinates, which may even be dynamic.
And the trajectory may be dynamic now as well.

It is now documented that for usage in Queue.animate() or AnimateQueue,
t0 should be set to 0 for at least the first segment of a trajectory.

Changed functionality (0)
-------------------------

It is more logical to use urgent=True in calls to Component.from_store and
Component.to_store. Therefore the default value for urgent in these methods
is now True.

Improved type hint handling (0)
-------------------------------

The recently introduced functionality to use env. prefix where sim. prefix
was required (like env.Component instead of sim.Component) did not show the
type hints in IDEs.
From this version type hints and the docstring will show these correctly.

The consequence of this change is an increase in the size of the source code,
but that shouldn't cause any problems.

Alternative way to initialize a simulation (0)
----------------------------------------------

It is quite common to start an app(lication) with ::

app = App()

This is now also possible with salabim as sim.App is now just an alias of
sim.Environment. So ::

app = sim.App(trace=True)
app.ComponentGenerator(X, iat=app.Exponential(10))
app.run(app.Uniform(10,20))

is now valid code.

Note that the env parameter in several class definitions has not been changed, though.
This might not cause too many problems as env= is hardly ever used in practice
(as far as I know).

Bug fix (0)
-----------

If Trajectory.length() was called without a time (t), an exception was raised. Fixed.

Bug fix (1)
-----------

When using sim.ComponentGenerator the default environment was not propagated correctly. Fixed.

Documentation updates (0)
-------------------------

The documentation now makes clear that t0 should be 0 in case a trajectory is
to be used as a trajectory for queue animation.

Documentation updates (1)
-------------------------

The HTML documentation now uses the better legible rtd (Read The Docs) theme.
Also, many additions and changes have been done.

23.1.1

==========================

New functionality (0)
---------------------

The t- and x-values of a monitor (level or non level) can now be saved as
a pandas dataframe, which can be useful for further data analysis.

All you have to do is:
df = mon.as_dataframe()

When dealing with level monitors, this might not be very useful as
most analyses assume a uniform (equidistant) t-scale.
Therefore, salabim also offers the possibility to resample the
monitor into a dataframe, like
df = mon.as_resampled_dataframe(delta_t=1)
Like this, the monitor will be resampled with a frequency of 1 time unit.
The lower delta_t, the more accurately the dataframe follows the real values,
albeit at the cost of a larger dataframe.

It is possible to resample multiple monitors into one pandas dataframe.

See the documentation (Monitor and Reference chapter) for details.

Changed functionality (0)
-------------------------

Considerable change in the implementation and API of stores.

From now a store doesn't *have* a contents queue: It *is* a queue!
This has a lot of advantages. For instance, all normal queue operations
are now also available for stores.

And you can now enter components or take them out, possibly honouring
any pending from_store or to_store.

Note that if the capacity of the store is not inf, the store becomes a
limited capacity queue. That implies that when a component tries to enter
the queue when it is already at its capacity, a ``sim.QueueFullError`` will be raised.

Changing the filter function will now automatically rescan for from_store
honors.
Changing the capacity of a store (with set_capacity will now automatically
rescan for to_store honors), if required.

It is still possible to rescan a store with Store.rescan().

The manual has been updated to reflect the changes.

Changed functionality (1)
-------------------------

The Component.from_store method now supports a very handy way to get the
item (component).
Instead of
yield self.from_store(store)
item = self.from_store_item()
you can now say
item = yield self.from_store(store)

Note that you have to do an assignment! So, something like
yield self.from_store(store).activate()
or
print(yield self.from_store(store).name())
is not possible (it is actually a syntax error)

Even with the item = yield self.from_store(store) syntax, you can
query the item with self.from_store_item()

And it is still allowed to use just
yield self.from_store(store)

The manual has been updated accordingly.

New functionality (0)
---------------------

ComponentGenerator has a new parameter: equidistant.
If equidistant is True, the components will not be randomly distributed over the
given duration, but evenly spread. For instance:
env.ComponentGenerator(X, at=100, till=200, number=3, equidistant=True)
, will generate instances of X at t=100, t=150 and t=200.

If equidistant is True, iat may not be specified.

Optimization (0)
----------------

The method Component.enter_sorted and Queue.add_sorted now search backwards instead of forward,
which is more efficient in case all components have the same priority, which is not uncommon.

Note (0)
--------

Version 23.1.0 introduced the possibility to use env. instead of sim. in almost all cases.
As mentioned you can't use this construction when defining an inherited class, like
class Car(env.Component)
This is simply not accepted.

But there is one case, which is not detected and does not work as expected:

class Car(sim.Component)
def __init__(self, *args, **kwargs):
...
env.Component.__init__(self,*args, **kwargs) instead of sim.Component.__init__(self, *args, **kwargs)

The recommended way is:

class Car(sim.Component)
def __init__(self, *args, **kwargs):
...
super().__init__(*args, **kwargs) instead of sim.Component.__init__(self, *args, **kwargs)

23.1.0

==========================

New functionality (0)
---------------------

This version contains a completely new concept that can make modelling
simpler, particularly for job shops, flow, etc.: stores

A store is essentially a queue (sometimes with limited capacity) that can
hold components.

And we can then request components from the store. If there's a component
in the store, it is returned. But if it is not the requesting component
goes into the requesting state, until something is available in the store.

The same holds for processes putting components in the store: if it
is full, the component that wants to add something to the store goes into
the requesting state. Here we have an unlimited waiting room, though.

Here's the well-known 3 clerk bank sample model with a store:

Bank, 3 clerks (store).py
import salabim as sim


class CustomerGenerator(sim.Component):
def process(self):
while True:
yield self.to_store(waiting_room, Customer())
yield self.hold(sim.Uniform(5, 15).sample())


class Clerk(sim.Component):
def process(self):
while True:
yield self.from_store(waiting_room)
customer = self.from_store_item()
yield self.hold(30)


class Customer(sim.Component):
...


env = sim.Environment(trace=False)
CustomerGenerator()
for _ in range(3):
Clerk()
waiting_room = sim.Store("waiting_room")


env.run(till=50000)

waiting_room.contents().print_statistics()
waiting_room.contents().print_info()

It is possible to specify several stores to get an item from. And likewise,
several stores to put an item.
It is also possible to filter components so to make the requester only get
a certain type of item.

The manual contains a new section on stores, with several examples. See also the
chapter on Modelling.

New functionality (1)
---------------------

From now on every class or function that used to be prefixed with sim.
can also be prefixed with env.

So, for instance:
q = env.Queue("q")
or
store = env.Store("store")
or
env.run(env.inf)

The only place where that is not allowed is for subclassing,
particularly sim.Component. So you still need to say
class Car(sim.Component):
...

Note that explicit setting of env is still possible:
env.Queue("q", env=env0)
is equivalent to
sim.Queue("q", env=env0)

Implicit setting of env is handled like
env0.Queue("q")
is equivalent to
sim.Queue("q", env=env0)

Support functions, like arange can now also be prefixed with env.
So env.arange(0, 10, 0.5) and sim.arange(0, 10, 0.5) are equivalent.

Also prefixable with env are env.inf and env.nan and the exceptions.

New functionality (2)
---------------------

Introduced a context manager Environment.suppress_trace that can
be used to temporarily disable trace. After the context manager block,
the trace status returns to the value before. Usage:
with env.suppress_trace():
car = sim.Component()
This will never print the trace output for component creation.

Changed functionality (0)
-------------------------

In TrajectoryPolygon, the spline may now also be "" (the null string),
denoting no splining.

Added functionality (0)
-----------------------

In the various print_histogram() print_histograms() a new parameter is
introduced: graph_scale, which represents the number of characters to
show 100% in the graphical representation of % and cum%.
This is particularly useful for (this) documentation.

So, ``m.print_histogram()`` might print:

...
<= duration % cum%
0 22.216 22.2 22.2 *****************|
1 32.485 32.5 54.7 ************************* |
2 26.441 26.4 81.1 ********************* |
3 18.858 18.9 100 *************** |
inf 0 0 100 |

, whereas ``m.print_histogram(graph_scale=30)`` will result in:

...
<= duration % cum%
0 22.216 22.2 22.2 ******|
1 32.485 32.5 54.7 ********* |
2 26.441 26.4 81.1 ******* |
3 18.858 18.9 100 ***** |
inf 0 0 100 |


Bug fix (0)
-----------

Trajectories did not always work correctly. Fixed.

Bug fix (1)
-----------

If a queue is animated the title should be the name of the queue by default.
In a recent update, the default was set to the null string, though.
Fixed.

Bug fix (2)
-----------

When saving an animated gif, the duration of the video was not always correct.
Particularly at 30 fps (the default), the duration was actually 90% shorter,
because frame durations are always a multiple of 10 ms.
That means that a 30 fps animated gif will be now actually recorded at 33.33 fps
and have the proper duration.
Fixed.

Documentation (0)
-----------------

The changelog is now part of both the online and pdf documentation.
The pdf version is now kept up-to-date (synced with the online docs).

23.0.1

==========================

Annotation (0)
--------------

Salabim has now type hints on all API classes, methods and functions.
This might help users when using IDEs and other tooling.

Warning (0)
-----------

As this change involved quite a lot of modifications (and some bug fixes),
it is possible that errors were introduced.
Please report any bugs as soon as possible.

Changed functionality / bug fix (0)
-----------------------------------

Due to an error in the sampling of a Poisson distribution, large means
(around 750 and up), always returned 2.
Now, if this happens, salabim falls back to another algorithm,
that works for any mean. But, this is slower than the 'base'
algorithm.

Salabim now offers the possibility to use the numpy Poisson sampling
functionality, which is indeed much faster. For reproducibility
reasons, this feature is disabled by default.
In order to enable numpy Poisson distribution sampling, specify
prefer_numpy = True when defining the Poisson distribution, like
d = sim.Poisson(mean=1000, prefer_numpy=True)
If numpy is not installed, salabim uses the 'normal' algorithm.

Bug fix (0)
-----------

AnimateSlider could not be removed properly. Fixed.

Bug fix (1)
-----------

A bug in AnimateSlider sometimes caused an error in getting the current value (v). Fixed.

Bug fix (2)
-----------

The way caching xweight was built, sometimes resulted in -although statistically correct-
unexpected results for monitor. The fix applied is also more performant.

23.0.0

==========================

Added functionality (0)
-----------------------

The labels parameter of AnimateMonitor may now be also a dict, where
the keys indicate where to put the label (via vertical_map), and the
values are the texts to be shown there.
It is still possible to use an iterable, in which case the text to
be shown the string representation of the label itself.

Added functionality (1) [thanks to a suggestion by tcdejong]
-----------------------

A new monitor has been added to Queue: available_quantity, which can be
used to get the remaining capacity, e.g.
q = sim.Queue("q", capacity=10)
c.enter(q)
print(q.available_quantity()
This monitor can't be tallied by the user.

Also introduced is a new method of Queue: set_capacity:
q = sim.Queue("q", capacity=10)
q.set_capacity(20)
print(q.capacity(), q.available_quantity()

Added test (0)
--------------

If blind_animation == True, the test for the existence of PIL was not done, so
a less obvious error message was issued if PIL was not present. Fixed.

Bug fix (0)
-----------

Bug in AnimateQueue where direction="e" and textoffsetx is specified
and textoffsety is not specified fixed.

Bug fix (1) [thanks to citrusvanilla]
-----------

AnimatePolygon did not properly close the polygon.
Fixed.

Bug fix (2)
-----------

Bug in 3D blind animation. Fixed.

Documentation fix (0)
---------------------

TrajectoryMerged was not documented. Fixed.

Usage recommendation (0)
------------------------

Hugo Hughes reports that it is possible to run 3D animated model on a headless server.
This can be done with a module that creates a virtual screen "pyvirtualdisplay", like
from pyvirtualdisplay import Display
virtual_display = Display(visible=0, size=(1920, 1080))
virtual_display.start()

(Both the tkinter and OpenGL windows are properly emulated).
Is blind_animation still required?

22.0.8

==========================

New functionality (0)
-----------------------

Salabim has a new feature: trajectories.
These can be used as:

- a trajectory an animated object should follow in time,
including getting the required duration
- placing components of a queue along a trajectory

A trajectory can consist of a number of subtrajectories,
where each can be a polygon (optionally splined) or a circle (segment)

The position on the trajectory in relation to the time is
optionally described a uniform acceleration/deceleration
with a given initial speed, final speed as well a maximum speed.

The various classes and their methods are in the reference section
of the documentation.
A manual update covering this subject is in the works.

See also sample models "Demo trajectory.py".

New functionality (1)
-----------------------

AnimateQueue and Queue.animate can now place the animation objects on a given
trajectory, by specifying
direction="t", trajectory=...
The trajectory x, y and angle method are called with the cumulated 'length' of the
animation objects dimx parameter (dimy is ignored).

See also sample models "Demo trajectory animate queue.py"

New functionality (2)
---------------------

AnimateImage now supports .heic (Apple's propriety High Efficiency Image File Format) files.
In order to read these files, pillow-heif has to be installed, e.g. with
pip install pillow-heif
This functionality is not available under Pythonista.

Changed functionality (0)
-------------------------

The AnimateSlider parameters are changed considerably as the previous version
was not consistent and missed useful functionality.

New parameters are:
foreground_color : colorspec
color of the foreground (default "fg")

background_color : colorspec
color of the backgroundground (default "bg")

trough_color : colorspec
color of the trough (default "lightgrey")

show_value : boolean
if True (default), show values; if False don't show values (thus only showing the label)

The following parameters were available, but actually not used at all:
linecolor
labelcolor
layer
They will remain accepted for compatibility reasons.

Added the method AnimateSlider.label:
Parameters
----------
text : str
new label
if omitted, no change

Returns
-------
Current label : str

With the new label method, it's easy to make dynamic labels, like:

import salabim as sim
import datetime

def action(v):
v_as_datetime = datetime.datetime(2022, 1, 1) + datetime.timedelta(days=int(v))
an0.label(f"{v_as_datetime:%Y-%m-%d}")

env = sim.Environment()
an0 = sim.AnimateSlider(x=100, y=100, action=action, width=500, height=30, v=30, vmin=0, vmax=365, resolution=1, fontsize=12, show_value=False)
env.animate(True)
env.run(sim.inf)

See also sample model "Demo slider.py"

Note that the Pythonista implementation does not use all given parameters.

Changed functionality (1)
-------------------------

In order to let AnimateCombined dynamic attributes work the same way as ordinary
Animatexxx objects, getting an attribute for an AnimateCombined object now returns
that attribute of the first animation object that has such an attribute, rather
than the 'shared' value.
If an attribute can't be found at all, now an AttributeError is raised, rather than
a ValueError.

As the animation_objects in AnimateCombined are now a list, rather than a set,
AnimateCombined.add is replaced by AnimateCombined.append.


Bugfix (0)
----------

Fixed a bug in resource requesting (thanks to Cameron Powell)

Bugfix (1)
----------

Bug in Monitor.xt() re adding now (introduced in version 22.0.6) fixed.

Documentation bugfix (0)
------------------------

A minor mistake in the docstring of animation_paramters re show_menu_buttons corrected

Page 6 of 26

© 2024 Safety CLI Cybersecurity Inc. All Rights Reserved.