salabim  changelog

version 2.3.2  2018-07-21
=========================
New functionality
-----------------
The methods
  AnimateText
  AnimateRectangle
  AnimateLine
  AnimatePolygon
  AnimatePoints
  AnimateCircle
  AnimateImage
  AnimateQueue
  AnimateMonitor
  AnimateMonitorTimestamp
now have an additional parameter, parent.
When a process finishes, either by reaching the end or by a cancel, all animation objects with that
component as its parent will be automatically removed.


Bug fixes
---------
Fatal error when tracing standby components fixed.

After a reset of a timestamped monitor, the animation of that monitor did not start at the left hand side of
the graph. Fixed.

Some minor error handling problems with checking for types fixed.


Demonstration of animation features
-----------------------------------
In order to demonstrate the new style animation classes, the following files (with comments) are included
in the GitHub distribution:
Demo animation classes.py (requires the file Pas un pipe.py)
Demo queue animation.py
Demo animation dynamic.py
Demo animation dynamic lambda.py


version 2.3.1  2018-07-09
=========================
New functionality
-----------------
Monitors can now be weighted. Initializing a Monitor instance has therefore a new parameter, weighted.
If weighted is set to True, the tally method can be used to specify the weight.
Monitor.weight() returns the sum of all weights.
Monitor.value_weight() returns the sum of all weights equal to or in value
Monitor.bin_weight() returns the sum of all weights > lowerbound and <= upperbound.
The name of the weight (used in Print_histogram and print_statistics) can be specified by the user (default is weight).


sim.Animate(circle0=) now supports also ellipses and circle arcs. Please consult the documentation for the correct
parameter usage.
It is highly recommended to use the new style AnimateCircle, which has some more parameters now:
  radius1 is the height of the ellipse (if omitted, a circle will be drawn)
  arc_angle0 is the start angle of the arc (default 0)
  arc_angle1 is the end angle of the arc (default 360, thus a full circle)
  draw_arc indicates whether the arcs should be drawn (default False)
Note that all the parameters may be a scalar, a function with 0, 1 or 2 arguments or a method with one argument (t).
Note also that the text is always positioned relative to the full circle/ellipse, regardless of the arc_angles.
Example:
  sim.AnimateCircle(radius=100, radius1=50, arc_angle1=lambda t: t*10)


Bug fixes
---------
Bug in closing an animation under Spyder or Idle fixed.
Bug in Environment.snaphot() under Pythonista fixed.


Internal
--------
Major overhaul of monitor off values and handling of duration for MonitorTimestamped.
Timestamped monitors now share most of their functionality with weighted monitors.



version 2.3.0  2018-06-28
=========================
New functionality
-----------------
As from this version, animation is more powerful and easier to use. Although the old style
Animate class is still available, it is recommended to use the new style classes.

The documentation is not yet completely up-to-date. Please read these release notes carefully to get more information.

All the docstrings (and therefore the reference section of the manual) are however up-to-date.
It is planned to publish a number of tutorial videos or guides, both for basic and advanced animation.

To visualize rectangles, lines, points, polygon, texts, circles and images salabim offers the new classes
- AnimateCircle
- AnimateImage
- AnimateLine
- AnimatePoints
- AnimatePolygon
- AnimateRectangle
- AnimateText

The main difference with the Animate class is that no automatic linear interpolation over time is supported.
But, each of the characteristics may be still changed over time easily!
All visualizations (apart from AnimateText) have an attached text field that will be displayed relative to
the shape.
Thus, for instance, it possible to say:
    vis = sim.AnimateRectangle(spec=(100, 100, 300, 50), text='some text')
and then a rectangle with the text 'some text' in the middle will be displayed.
In contrast to Animate, updating any of the specifying fields does not require the update method, but can be
done directly.
In the above example you can just say
    vis.text='yet another text' or vis.x=100

One of the key features of this new visualization is that all the specifying fields can now be functions or methods.
This make is possible to automatically update fields, e.g.
   vis = sim.AnimateText(lambda:'mean of histogram = ' + str(hist1.mean()), x=100, y=100)
   which will show and update the current mean of the histogram
or
   vis = sim.AnimateRectangle(spec=(0, 0, 60, 20), x=100, y=lambda t:t+10)
   which results in a rectangle, moving from bottom to top.
The animation_objects method of Component now accepts any of the new visualization class instances as well as
Animate instances.

Animation of queues is now specified with the class AnimateQueue, although Queue.animate() is still supported.
One queue can now be animated in several ways, whereas previously one queue could be animated only once. See
Demo queue animation.py for an example.
It possible to restrict the number of components shown (max_length).
Is possible to change all the parameters of the queue animation and the shown components dynamically.
See for instance Elevator animated.py where the queue position moves up and down.
Or see Machine shop animated.py where the shape of the components changes dynamically.
Internally, the animation of queues uses a new, more efficient, algorithm.

Most examples have been updated to use this new visualization functionality.

Texts can now spawn multiple lines (lines separated by linefeeds). Also, a list or tuple of strings may
be used instead, in which case each element of the list/tuple will be treated as another line.
This is particularly useful to present (dynamic) monitor values.
With AnimateText, it is possible to restrict the number of lines (parameter max_lines) shown.


Class Animate has a new animation parameter, as_points that applies to lines, rectangles and polygons.
If as_points is False (the default), all lines will be drawn.
If as_points is True, only the end point will be drawn as a square with a width equal to the linewidth.
Technical remark: the advantage of using as_points this instead of a series of individual squares
is that there is only one bitmap to be placed on the canvas, which may lead to better performance in many cases.
Also this is used internally for AnimateMonitor() (see below).
Points are also available in the new AnimatePoints class.


Class AnimateMonitor() can be used to visualize the value of a timestamped monitor over time. It is
particularly useful for visualizing the length of a queue, the various monitors of a resource or
the value of a state.
It is possible to connect the lines (very useful for 'duration' monitors, like queue length) or just show
the individual points.
This class can also visualize the relationship between the index and the value of a non time stamped monitor.
The points can be just shown or connected with a line.
It is possible to use
    Monitor.animate() and
    MonitorTimestamp.animate()
as an alternative, although not recommended.

The MMc animated.py model demonstrates the use of the (timestamped) monitor animation.


Monitor and MonitorTimestamp can now be used to create a merged (timestamped) monitor.
This is done by providing a list of (timestamped) monitors (all have to have the same type), like
    mc = MonitorTimestamp(name='m1 and m2', merge=(m1, m2))
For monitors, just all of the tallied x-values are copied from the to be merged monitors.
For timestamped monitors, the x-values are summed, for all the periods where all the monitors were on.
Periods where one or more monitors were off, are excluded.
Note that the merge only takes place at creation of the (timestamped) monitor and not dynamically later.

Sample usage:
Suppose we have three types of products, that each have a queue for processing, so
a.processing, b.processing, c.processing.
If we want to print the histogram of the combined (=summed) length of these queues:
    MonitorTimestamp(name='combined processing length',
        merge=(a.processing.length, b.processing.length, c.processing.length)).print_histogram()
and to print the histogram of the length_of_stay for all entries:
    Monitor(name='combined processing length of stay', 
        merge=(a.processing.length_of_stay, b.processing.length_of_stay, c.processing.length_of_stay)).print_histogram()
        
 
CumPdf is a new distribution type that is similar to Pdf, but where cumulative probability values are used.
This is particularly useful for dichotomies, like failing probabilities:
    failrate = 0.1
    if CumPdf(True, failrate, False,1)
        print('failed!')


All methods 
  print_histogram()
  print_histograms()
  print_statistics()
  print_info()
now have an additional parameter as_str, that allows the output to be returned
as a string, rather than print the information (the default is False, so just print):
This is particularly useful for animation of that information (see demo queue animation.py) or to
write directly to a file.        
                        

sim.Random() is a new class that makes a randomstream. It is essentially the same as sim.random.Random().

        
Queue.name(value), Resource.name(value) and State.name(value) now also update the derived names.        

API changes
-----------
The API of Component has changed slightly. The parameter process now defaults to None, which means that
it tries to run the process generator method, if any.
If you don't want to start the process generator method, even if it exists, now set process='' (this was None).

The API of Environment had changed slightly. The parameter random_seed now defaults to None, which means that
1234567 will be used as the random seed value. If random_seed is '*', a system generated, non reproducable,
random seed will be used.

The API of Environment.random_seed has changed slightly. If the argument seed is '*', a system generated, non
reproducable random seed will be used.

State.animate() is phased out. Use the standard visualization classes, like AnimateRectangle,
    AnimateCircle and AnimateTex instead.


Future changes
--------------
Python 2.7 will not be supported in a future version. Please upgrade to Python 3.x as soon as possible .


Internal changes
----------------
Most default parameters are now None, instead of omitted, which is completely phased out.
This makes it easier to specify default arguments, like:
    myname = None
    sim.Component(name=myname)
This internal change required a couple of changes to the API (see above).
Apart from that, the user shouldn't notice this rather dramatic internal change (>500 replacements in the code!).

Animating lines and polygons without any points is now supported.


version 2.2.23  2018-05-28
==========================
New functionality
-----------------
Component.leave() can now be called without a queue, in which case, the component will leave all queues
it is in, apart from internal queues (Resource.claimers(), Resource.requesters and State.waiters()).
It is not necessary that the component is in any queue.
The best use case is to leave the one and only queue it is in without having to specify the
queue, like
    self.enter(q1)
    ...
    self.leave()

Also, Component.leave() now returns the component (self). This is useful for daisy chaining, like:
def process(self):
    while True:
        self.leave().enter(q1)
        yield self.hold(p1())
        self.leave().enter(q2)
        yield self.hold(p2())
        self.leave().enter(q3)
        yield self.hold(p3())
With this code, the component 'hops' from queue to queue, with minimal effort.


In line with this daisy chaining of leave, the methods
    Component.enter(),
    Component.enter_at_head()
    Component.enter_sorted()
    Component.enter_in_front_of()
    Component.enter_behind()
now return the component (self).

With this new functionality, it is possible to do things like
    self.enter(q1).enter(q2).enter(q3)
for a component to enter three queues on just one line.


Monitor.print_histograms() introduced as an alias for Monitor.print_histogram()
MonitorTimestamped.print_histograms() introduced as an alias for MonitorTimestamped.print_histogram()
Monitor.reset_monitors() introduced as an alias for Monitor.reset()
MonitorTimestamped.reset_monitors() introduced as an alias for MonitorTimestamped.reset()

These four new methods make it possible to intermix resources, states, queues, (timestamped) monitors when
printing histograms or resetting the monitors, like:
for obj in [my_queue, my_resource, my_monitor, my_timestamped_monitor]:
     obj.print_histograms()
     obj.reset_monitors()
     
     
Introduced methods register and deregister for classes:
    Component
    Monitor
    MonitorTimestamped
    Queue
    Resource
    State
This makes it easier to do collective actions on a number of component, queues, (timestamped)monitors, queues,
resources and/or states.
A registry is just a list of objects, which can for instance be used as:
    monitors = []
    m1 = sim.Monitor(name='m1').register(monitors)
    m2 = sim.Monitor(name='m2').register(monitors)
    queues = []
    q1 = sim.Queue(name='q1').register(queues)
    q2 = sim.Queue(name='q2').register(queues)
    ...
    for obj in monitors + queues:
        obj.print_histograms()
        obj.reset_histograms()
    
Another example:
    components = []
    while(...):
        MyComp().register(components)
    ...
    print('all components in system:')
    for component in components:
        print(component.name())
 
Make sure to deregister any objects that are not used anymore, otherwise these will not be garbage collected!

Note that it is possible to mix several types of class in a registry (list).


Documentation update
--------------------
In contrast to documentation so far, the priority parameter in Component.enter_sorted, Component.priority()
and Queue.add_sorted() does not have to be float.
It can be any type as long as it can be compared with the other priorities in the queue.
Example 1:
    q=sim.Queue('q')
    X().enter_sorted(q, (1,1))
    X().enter_sorted(q, (0,2))
    X().enter_sorted(q, (1,0))
    X().enter_sorted(q, (1,3))
    q.print_info()
will print
    Queue 0x11a0136d8
      name=q
      component(s):
        x.1                  enter_time     0.000 priority=(0, 2)
        x.2                  enter_time     0.000 priority=(1, 0)
        x.0                  enter_time     0.000 priority=(1, 1)
        x.3                  enter_time     0.000 priority=(1, 3)
        
Example 2:
    q=sim.Queue('q')
    X().enter_sorted(q, 'one')
    X().enter_sorted(q, 'two')
    X().enter_sorted(q, 'three')
    X().enter_sorted(q, 'four')
    q.print_info()
will print
    Queue 0x1279a82b0
      name=q
      component(s):
        x.3                  enter_time     0.000 priority=four
        x.0                  enter_time     0.000 priority=one
        x.2                  enter_time     0.000 priority=three
        x.1                  enter_time     0.000 priority=two
        
Note: Avoid mixing enter_sorted or add_sorted with enter, enter_at_head, add, append or add_at_head when using
non float priorities.


Bug fixes
---------
Bug in State introduced in version 2.2.22 fixed.


version 2.2.22  2018-05-21
==========================
New functionality
-----------------
Monitor.print_histogram() and MonitorTimestamp.print_histogram() now support auto scaling of
the bin_width, lowerbound and number_of_bins, when none of these parameters are specified.
The autoscaling algorithm method can be overridden if required (see Histogram.histogram_autoscale).
For example, the following code
    m = sim.Monitor('normal distribution')
    for i in range(100000):
        m.tally(sim.Normal(10,2)())
    m.print_histogram()

will print:

    Histogram of normal distribution
                            all    excl.zero         zero
    -------------- ------------ ------------ ------------
    entries           10000        10000            0    
    mean                  9.989        9.989
    std.deviation         1.989        1.989
    
    minimum               1.881        1.881
    median                9.978        9.978
    90% percentile       12.550       12.550
    95% percentile       13.245       13.245
    maximum              17.597       17.597
    
               <=       entries     %  cum%
            1             0       0     0   |                                                                              
            2             1       0.0   0.0 |                                                                              
            3             3       0.0   0.0 |                                                                              
            4            14       0.1   0.2 |                                                                              
            5            43       0.4   0.6 |                                                                              
            6           153       1.5   2.1 *|                                                                             
            7           439       4.4   6.5 ***  |                                                                         
            8           925       9.2  15.8 *******     |                                                                  
            9          1532      15.3  31.1 ************            |                                                      
           10          1938      19.4  50.5 ***************                         |                                      
           11          1895      18.9  69.4 ***************                                        |                       
           12          1475      14.8  84.2 ***********                                                        |           
           13           940       9.4  93.6 *******                                                                   |    
           14           424       4.2  97.8 ***                                                                           |
           15           165       1.7  99.5 *                                                                              |
           16            34       0.3  99.8                                                                                |
           17            15       0.1 100.0                                                                                |
           18             4       0.0 100.0                                                                                |
              inf         0       0   100.0                                                                                |

Monitor.print_histogram() and MonitorTimestamp.print_histogram() now supports the presentation of
individual values, by specifying values=True.
This is especially useful when collecting the status of a component over time, like:

    Histogram of Status
    duration            300    
    entries              57    
    
    value                     duration        entries
    idle                        88.558( 29.5%)      9( 15.8%) ***********************                                                         
    produce A                   37.459( 12.5%)      9( 15.8%) *********                                                                       
    produce B                    8.425(  2.8%)      2(  3.5%) **                                                                              
    produce C                   44.352( 14.8%)     10( 17.5%) ***********                                                                     
    produce D                   54.775( 18.3%)     12( 21.1%) **************                                                                  
    store                       38.591( 12.9%)      8( 14.0%) **********                                                                      
    transport                   27.841(  9.3%)      7( 12.3%) *******                                                                         
    
Monitor.value_number_of_entries() introduced. The method can be used to check how many entries have an x
equal to value or an x that is in value.

MonitorTimestamp.value_duration() introduced. The method can be used to check the duration of an x
equal to value or an x that is in value.

MonitorTimestamp.value_number_of_entries() introduced. The method can be used to check how many entries have an x
equal to value or an x that is in value.

Introduced Queue.print_histograms(). This method prints autoscaled histograms of the
- length timstamped monitor
- length_of_stay monitor

Introduced Resource.print_histograms(). This method prints autoscaled histograms of the
- requesters().length timstamped monitor
- requesters().length_of_stay monitor
- claimers().length timstamped monitor
- claimers().length_of_stay monitor
- capacity timestamped monitor
- available_quantity timestamped monitor
- claimed_quantity timestamped monitor

Introduced State.print_histograms(). This method prints autoscaled histograms of the
- waiters().length timestamped monitor
- waiters().length_of_stay monitor
- value timestamped monitor

MonitorTimestamp.number_of_entries() introduced, to be used to retrieve the number of entries.

Component.name(), Environment.name(), Monitor.name(), MonitorTimestamp.name(), Queue.name()
Resource.name() and State.name() now can be used to change the name of the object.
Note that the base_name and the sequence_number will not change upon a name change.

Function regular_polygon introduced.


Renamed
-------
MonitorTimestamp.bin_count() is now called MonitorTimestamp.bin_duration()
Monitor.bin_count() is now called Monitor.bin_number_entries()


Bug fix
-------
Problem when PIL was not installed (correctly).


version 2.2.21  2018-05-01
==========================
New functionality
-----------------
Component.interrupt() can now be called also when a component is interrupted. In that case, the 'interrupt_level'
will be incremented. This allows interrupts to be 'stacked'.
When resuming with Component.resume(), the interrupt_level will be decremented. If it reaches zero,
the component will return to the status at the moment of the first interrupt.
If c.resume(all=True) is issued, the component c will return to its original status, regardless of the
interrupt_level.
The trace shows the level in interrupt and resume for interrupt_levels >= 2.
The file 'demo interrupt resume.py' demonstrates the application of stacked interrupts for breakdowns of
several parts of a machine.

The new method Component.interrupt_level() can be used to query the current interrupt_level. It is zero
for non interrupted components.

Function Component.isinterrupted() can be used to check whether a component is interrupted. This is equivalent
to c.status() == sim.interrupted


The new method Environment.snapshot() can be used to write an animated frame (at time=now()) to a file.
The method accepts .png, .jpg, .bmp, .gif and .tiff files. For all extensions but .jpg, the image can
have a semi transparent background (i.e. an alpha < 255).
The animation does not have to be started to use snapshot().

Bug fixes
---------
Component.resume() did not handle mode correctly. Fixed.
It was not possible to use sim.spec_to_image() if the animation was not started. Fixed.

version 2.2.20  2018-04-28
==========================
New functionality
-----------------
New process interaction methods Component.interrupt() and Component.resume() introduced to interrupt a component.
This is particularly useful for simulating breakdowns.

When a component is interrupted, the component is removed from the event chain (if applicable) and
the status becomes interrupted. For scheduled, waiting and requesting component, the remaining
duration will be calculated.
Upon resume, the action depends on the original status:
- passive: the component gets passive
- standby: the component gets standby
- requesting: if the request can be honored, it will.
  If not, the fail_at time will be updated according to the remaining duration
- waiting: if the wait can be honored, it will.
  If not, the fail_at time will be updated according to the remaining duration
- scheduled: the scheduled time will be updated according to the remaining duration
Note that an interrupted component cannot be interrupted.
Also, only interrupted components can be resumed.
Interrupted components can leave the interrupted state with the all process activation methods:
  activate, hold, passivate, wait, request, standby or cancel.
  
The functionality of method Component.remaining_duration() has been extended.
Now the method has a value parameter which allows setting the remaining_duration.
The action depends on the status where the component is in:
- passive: the remaining duration is update according to the given value
- standby and current: not allowed
- scheduled: the component is rescheduled according to the given value
- waiting or requesting: the fail_at is set according to the given value
- interrupted: the remaining_duration is updated according to the given value
The method returns:
- passive: the remaining time (if applicable) at the moment passivate() was given, unless overridden
- scheduled, waiting or requesting: the scheduled time minus now
- interrupted: the remaining time (if applicable) at the the moment interrupt was given unless overridden
- otherwise: 0


Environment.run() now allows main to be scheduled urgent, by specifying urgent=True.

Improvement
-----------
When a process ends the trace now shows the line number of the last line in the process,
postpended with a plus symbol. Previously no line number was shown.
Also, any auto resource releases at the end of a process will show the same information now.

version 2.2.19  2018-04-13
==========================
New functionality
-----------------
Support for animated GIF production. If Environment.animation.parameters(video=...) of Environment.video() 
gets a filename with .gif as extension, an animated GIF is created.
Note that GIF production does not require numpy nor opencv, and therefore Environment.can_video() does not
have to be True to produce an animated GIF.
This feature is particularly useful on Pythonista platforms, where opencv is not supported.

For animated GIFs, Environment.animation_parameters() has two extra parameters:
  video_repeat   ==> how many times the animated GIF will be repeated (default 1)
  video_pingpong ==> whether all frames should be appended in reverse order at the end of the animated GIF
                   resulting in a smooth repeating video (default: False)

Two methods have been added to Environment to support GIF file production:
  Environment.video_repeat()
  Environment,video_pingpong()
               
                   
For ordinary video files (non GIF), it is now possible to specify a codec, by adding a plus sign and 
the name of the codec after the extension of the file, like
  video='myvideo.avi+DIVX'
  

Introduced Resource.occupancy timestamped monitor. The occupancy is defined as the claimed quantity
divided by the capacity. Note that when the capacity of r changes over time, r.occupancy.mean() may differ
from r.claimed_quantity.mean() / r.capacity.mean(). Also, in that case, the occupancy may be even greater than 1.
If the capacity is <=0, the occupancy is assumed to be 0.


Improvements
------------
The time in the upper right-hand corner is now displayed with the mono font, which is better legible and
not as 'nervous' as the narrow font that was used previously. Also, on Pythonista, the text is moved a bit
to the left in order not to coincide with the closing symbol X.


Clarification
-------------
When a process ends, all claimed resources will be automatically released.
If that functionality is not desired, the process should be prematurely cancelled, with
    yield self.cancel()
    
Compare these two components:
    class X(sim.Component):
        def process(self):
            yield self.request(r)
            yield self.hold(1)
            # automatically releases r at the end of the process

    class Y(sim.Component):
        def process(self):
            yield self.request(r)
            yield self.hold(1)
            yield self.cancel()  # process ends here and r is NOT released!
            
Also, all animation objects that have set the parent field to a component will be removed automatically
when the process of that component ends. Again, this can be prevented by yield self.cancel().            

This information will be included in the documentation.
    

Bug fixes
---------
Bugs in AnimateSlider fixed (thanks to John Hutchinson).

Bug when honoring a resource request of a component that was already claiming that resource fixed.

Bug in the line number of the trace when auto releasing claimed resources at end of a process fixed.

Bug in wait with a fail_at parameter fixed.


version 2.2.18  2018-03-31
==========================
New functionality
-----------------
Function reset() resets all global variables and closes a video recording, if any
It can be useful to start a script with sim.reset() when used in REPLs and under Pythonista (iPad).

Release notes 2.2.17 corrections
--------------------------------
Method Environment.scale() introduced, returning the scale of the animation, i.e. width / (x1 - x0)
  (not (x1 - x0) / width).

Function arrow_polygon added (not polygon_arrow).
Function centered_rectangle() added (not rectangle_centered).

Bug fixes
---------
Bug in AnimateSlider corrected.

version 2.2.17  2018-03-31
==========================
New functionality
-----------------
Normal distribution now supports specification of coefficient_of_variation as an alternative
  to standard_deviation.
Note that it is not allowed to specify both standard_deviation and cooeficient_of_variation.
The coefficient_of_variation is now also shown in Normal.print_info().
The coefficient_of_variation is defined as the standard deviation divided by the mean.

Method Environment.scale() introduced, returning the scale of the animation, i.e. (x1 - x0) / width

sim.Animate and sim.update now allows and prefers circle0 or circle1 to be specified as a scalar.
The functionality to the specify the radius as a one element tuple/list is still supported.
E.g. sim.Animate(circle0=(30,)) is equivalent to sim.Animate(circle0=30) now.
Note that Animate.circle may also return a one item tuple/list or a scalar.

sim.Animate() and sim.update() now allows the specification of
  line0, line1, rectangle0, rectangle1, poloygon0 and polygon1 to include None values
The None values will repeat the previous x or y value. E.g.
sim.Animate(line0=(10, 20, None, 30, 40, None)) is equivalent to sim.Animate(line0=(10, 20, 10, 30, 40, 30))

Function polygon_arrow() added.
Function rectangle_centered() added.

Video production now supports .MP4 and .AVI extensions. Other extensions are not accepted.

Environment.is_dark(colorspec) now returns the is_dark value of the background color
  if the alpha value of the colorspec is 0.

Changed API
-----------
The parameter lambda_ for the Poisson distribution is renamed to mean, in order to avoid problems
with the online documentation.

Bug fixes
---------
Bug in handling width/height of images when using a redefined coordinate system fixed.
Bug in method Queue.add_at_head() fixed.
Bug with default font handling on Pythonista fixed.
Bug in Environment.animation_parameters() and Environment.video() fixed.
Work around a PIL bug where rendering the first letter of some italic font texts chopped the lefthand serif.

Sample files
------------
Show colornames.py shows all available colors.
Demo using process interaction in method.py gives an example of how to use hold in a separate method.
Dining philsophers animated.py updated to use the new circle specification.

Documentation
-------------
Documentation updated and improved. Although still work in progress ...



version 2.2.16  2018--03-01
===========================
From this version, neither animation modules (PIL, tkinter) nor video modules (cv2, numpy) will
be imported unless these are required at runtime (with animation_parameters).

A user program can now check whether animation is supported with a call to sim.can_animate().
A user program can now check whether video is supported with a call to sim.can_video().

Bug fix
-------
Minor bug when ImageTk could not be imported corrected.

version 2.2.15  2018-02-28
==========================
Animation updates
-----------------
Overhaul of the way animation is organized. Now, the animation can be started and stopped during a run.
When animation is off, the simulation model runs full speed without any overhead.
It is possible to use different environmnent for the animation although not at the same time.

The API for animation has changed slightly:
center is now refered to as 'c'  (although 'center' is still accepted)
xy_anchor allows x0, x1, y0 and y1 in Animate and x and y in AnimateButton or AnimateSlider object, to be
relative to each of the wind directions 'n', 'nw', 'w', 'sw', 's', 'se', 'e' or 'ne' or 'c' (for center).
This makes it, for instance, possible to define a button relative to the top right hand corner of the 
animation frame:
b = sim.AnimateButton(text='My button', x=-100, y=-20, xy_anchor='ne')

All arguments of Environment.animation_parameters have now a corresponding function that
can be used to set or query one of the animation parameters:
  Environment.x0() to set/query x-coordinate of lower left corner of animation frame 
  Environment.x1() to set/query x-coordinate of upper right corner of animation frame
  Environment.y0() to set/query y-coordinate of lower left corner of animation frame
  Environment.y1() to query y-coordinate of upper right corner of animation frame
  Environment.width() to set/query width of animation frame
  Environment.height() to set/query height of animation frame
  Environment.fps() to set/query the number of frames per second
  Environment.show_time() to set/query whether time should be shown
  Environment.show_fps() to set/query whether fps should be shown
  Environment.modelname() to set/query the model name ('' to show nothing)
  Environment.animate() to start/stop the animation and to query the current status
  Environment.speed() to set/query the speed of the animation
  Environment.video() to set/query the name of the video ('' for no video)

New functionality
-----------------
The Poisson distribution is now supported.

Enhancements
------------
Text alignment in text Animate is significantly improved. Now the text is always aligned according to the 
(estimated) 'cap line', which is derived from a capital A.
So, when aligning south, the descender of the g is below the baseline.
When aligning north, top of the capline is the given y-position.
Finally, aligning w, c or e means given y-position is the middle of the cap line.

Functionality updates
---------------------
- linewidth0 defaults to 1 for lines, 0 for rectangles, polygons and circles.
- When a modelname is given, that is presented in a different way along with a salabim logo.

Updated animated sample files
-----------------------------
Please not that the animated sample models have been updated to use the new xy_anchor functionality.

Bug fix
-------
Collected tallies for monitors were not cached properly, resulting in non optimal performance of Monitor.x() and
querying the monitor, e.g. print_histogram.

version 2.2.14  2018-02-02         
==========================
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
                
    
     
version 2.2.13A  2018-01-25        
===========================
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.

version 2.2.13  2018-01-25        
==========================
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.

version 2.2.12  2018-01-18        
==========================
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 i 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.

version 2.2.11  2018-01-14         
==========================
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().

version 2.2.10  2018-01-03
==========================
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.

    
version 2.2.9  2017-12-20
=========================
From this version the following classes:
  Environment
  Monitor
  MonitorTimestamp
  Queue
  Resource
  State
support automatic naming according to the class where it is defined, like Component.
Also, all these classes now call a setup method as the last statement in __init__ .
By default, this setup method is dummy.

Classes Monitor and MonitorTimestamp now contain base_name() and sequence_number() methods.

The image method of the class Animate now just returns an image and not anymore a tuple of 
an image and a serial number.

The function spec_to_image now supports the null string, in which case a dummy picture will be
returned.

Animation of images is now correctly handled if width0 is omitted. When overriding Animate.width,
None can be used to disable scaling.

Improved error handling (no more asserts).

Bug in Resource.release fixed.


version 2.2.8  2017-12-06
=========================
New features / major changes:
Animation can now run synced (i.e. in real time, with a speed factor) or not synced. In the latter
case, the animation will step from event to event. In that case also single stepping is now supported.
Synced on/off can be set with animation_parameters and/or with the menu system.

The menu system is completely redesigned. It now shows only a 'Menu' button at start up. When this button
is pressed, several buttons are shown. Here, the user can select Synced on/off, Trace on/off and Stop. When Synced
is on, the user can increase or decrease the animation speed. When Synced is off, the user can single
step through the simulation (with Step). Finally, with Go the simulation will run again.
The animation speed is no longer shown in the right hand upper corner. And frames per second (fps) is disabled
by default now, in order to get a less cluttered top line and more space for user information.

Minor changes and bug fixes:
A major bug caused Pythonista to crash frequently and rapidly. This is now fixed.

The function show_speed of Environment.animation_parameters is no longer available.

The functions clocktext is are now a method of Environment, thus making it overridable.

Sample models are updated.

version 2.2.7  2017-11-28
=========================
New features:
Animation of queues is now a standard feature, which makes visualisation of queue contents much simpler.
In order to realize that, a component now has an animation_objects method,
which defines how a component is to be visualized.
The default method shows a black square of 40x40 with the sequence_number in white in this square.
But, it is possible and quite likely necessary to override the animation_objects method.
The method should return a list or tuple containing the x-size, y-size and one or more animation objects.
In order to animate a queue, the method Queue.animate should be called with the position of 
the first component and the direction for subsequent components.
Please have a look at the MMc model for a demonstration.

Animation of states is now a standard feature, which facilitates in visualization of a changing state.
In order to realize that, a state now has an animation_object method, which defines
how a state is displayed for each possible value.
The default method shows a black square of 40x40 with the value dispayed in white in this square. If
the value is a valid colour, an emmpty square with that colour is displayed.
But, it is possible and quite likely necessary to override the animation_objects method.
The method should return a list or tuple containing one or more animation objects.
In order to animate a state, the method State.animate should be called once with the position of
the animation object.

The animation now calls a method Environment.animation_pre_tick(t) just before starting
the animation objects display loop.
And Environment.animation_post_tick(t) just after the loop. Both methods are by default dummy
(they just return).
Overriding/monkey patching these methods (particularly animation_pre_tick) can be useful for advanced animations,
e.g. for a queue where the y position changes over time (cf. the Elevator animated model).

Reintroduced functionality to remove animation objects belonging to a component that becomes a data component.
The 'belonging to' has to be indicated with parent in the call to Animate.

Minor changes and bug fixes:
Default arguments are now handled with an omitted value rather than None (or '*' in some cases).

All error handling is now via SalabimError.

Internal handling of Monitor.x, MonitorTimestamped.xduration, MonitorTimestamped.xt and
MonitorTimestamped.tx improved.

Code optimized with several list comprehensions.

Bug fixes.

version 2.2.6  2017-10-07
=========================
Salabim now supports Python 2.7. The biggest advantage of this is, that models can
now be run under PyPy.

The module numpy is no longer required (although still required for video production).
This makes it easier to run under PyPy, where installing numpy can be complicated.
When PIL is installed, even animation is now supported under PyPy.

All animated examples were updated to support Python 2.7, particularly by changing
super().proc(...) into sim.Component.proc(self,...) and sim.Animate.proc(self, ...)

Internal: font searching and build up of font tables improved.
Now salabim also searches the current directory for any .ttf files.

Several bug fixes.

version 2.2.5  2017-09-27
=========================
Queue.reset() has been renamed to Queue.reset_monitors()
Resource.reset() has been renamed to Resource.reset_monitors()
New method: State.reset_monitors()

In Component.wait(), if the test value contains a $, the $ 
sign is now replaced by state.value() instead of str(state.value())
This means that you can now say
    self.wait('light','$ in ("green","yellow")')
    
Monitor can now store the tallied values in an array instead of a list. 
this results in less memory usage and faster execution speed.
The array may be either integer, unsigned integer or float.
Integer and unsigned integer is available in 1, 2, 4 or 8 byte versions.
When type='any' is given (default), the tallied values will be stored in a list.
Note that the monitor for Queue.length_of_stay is a float array now.
For list monitors the x-value in x() returns a numpy array
where the values are converted to a numeric (value 0 if not possible)
unless overridden with force_numeric=False.

MonitorTimestamp will now store the timestamps in a float array.
The tallied values can be stored in an array instead of a list. This results in less memory usage and
faster execution speed.
The array may be either integer, unsigned integer or float.
Integer and unsigned integer is available in 1, 2, 4 or 8 byte versions.
When type='any' is given, the tallied values will be stored in a list.
Monitor off is now tallied now with the attribute off of the timestamped monitor,
which is dependent on the type.
Note that the tallied values for Queue.length are in an uint32 array.
The tallied values for Resource.capacity, Resource.claimed_quantity and 
Resource.available_quantity are in a float array,
The tallied values for State.value are in a list, unless a type is specified at init time.
The MonitorTimestamp.x() method returns a numpy array for integer and float monitors.
For 'any' timestamped monitors the x-value in xduration() is a numpy array
where the values are converted to a numeric (value 0 if not possible)
unless overridden with force_numeric=False.

The Monitor.x() and MonitorTimestamped.xduration() methods now uses caching to impove performance.

The function type in Component.wait now uses three arguments instead of a tuple of value, 
component and state.

Redesigned font searching in order to support animation on Linux and to guarantee a consistent
appearance over different platforms.
Therefore, a small set of ttf fonts is included in the distribution. These should reside in 
the same directory where salabim.py is located (PyPI automatically takes care of that).
These fonts will be first searched. As of this moment, salabim is shipped with:
- calibri.ttf           The preferred proportional font. Also accessible with font='std' or font='' 
- arial.ttf 
- cour.ttf
- DejaVuSansMono.ttf    The preferred monospaced font. Also accessible with font='mono'
- mplus-1m-regular.ttf  The preferred narrow monospaced font. Also accessible with font='narrow'
If salabim is not able to find any matching font, the PIL.ImageFont.load_default() will be called, now.

Internal optimizations by using defaultdict instead of dict where useful.

Outphased:
  salabim.run()
  salabim.main()
  salabim.trace()
  salabim.now()
  salabim.animation_parameters()
  salabim.current_component()
Use the equivalent default environment method instead, like
  env.run()

version 2.2.4  2017-09-12 
=========================
Automatic naming of components, queues, etc. results in shorter names now.
E.g., instead of 'client............11' the name is now 'client.11'.
Also the name is not shortened anymore (was: 20 characters).

The methods Monitor.print_statistics(), MonitorTimestamp.print_statistics(), 
Queue.print_statistics, State.print_statistics and Resource.print_statistics()
have an improved layout.

The method Monitor.print_histogram() and MonitorTimestamp.print_histogram()
have an improved layout.

Monitor and MonitorTimestamp names are now serialized.

Please have a look at the much improved manual.

version 2.2.3  2017-09-05
=========================
PIL 4.2.1 (shipped with the latest WinPython distribution), has a bug when
trying to animate text with the null string.
Therefore, salabim now has special code to handle null strings correctly.

Minor bug with importing PIL under Pythonista fixed.

version 2.2.2  2017-09-02 
=========================
Component.wait() now allows to check for":
- a value
  yield self.wait((light,'red'))
- an expresssion to be evaluated. the value has to be $ which is replaced by
  str(state.value()), each time the condition is checked
  yield self.wait((light,'$in ("red","yellow")'))
  yield self.wait((level,'<30'))
  it is possible to use state for the state under test and self for the
  component under test
- a function to be called each time the condition is checked.
  the function is called with one argument, being
  a tuple of state.value(), component, state
  yield self.wait((light,lambda x: x[0] in ('red,ýellow'))
  yield self.wait((level,lambda x: x[0]<30))
  

Component.activate() has an additional parameter keep_wait, which controls whether
waits are to be kept upon an activate, thus allowing an update of a timeout.

When salabim detects that PIL or tkinter is not installed when trying to animate,
the error message now provided instructions on how to install the relevant package.

When salabim detects that cv2 is not installed when trying to produce a video,
the error message now provided instructions on how to install the relevant package.

version 2.2.1  2017-08-31
=========================
Bug in Component.request() corrected.
This prevented Machine shop animated to work properly.


version 2.2.0  2017-08-30 
=========================
Introduced a new process control method: wait.
This functionality is similar but not equal to the waitevent and queueevent
methods in SimPy2.
The method allows a process to wait for a any if all of (number of) certain
value(s) of a so called state.
A state has a value and each time this value change, all components waiting for
this state are checked.
The class State has a number of methods, which allow to control the state:
  set(value) sets the value. Normally used without argument, in which
          case True will be used.
  reset() resets the value to False=
  trigger(value) sets the value (default True), triggers any components waiting, 
    and then immediately resets to a given value (default False).
    optionally, the number of components to be honored with the trigger
    value may be limited (if used, most like 1).
The current value of a state can be retrieved with
  get() or by directly calling the state.
  So, e.g. dooropen.get() or dooropen()
On top of that, the queue of waiters may be accessed with
  State.waiters()
And there is a monitor to register the the value over time, called State.value .
.
The waiters queue and value will be monitored by default.

Components can wait for a certain value of a state (or states) by
  yield self.wait(dooropen)
or
  yield self.wait((dooropen,False))
And for several states at one time:
  yield self.wait(frontdooropen,backdooropen) to test for fontdooropen OR backdooropen
or
  yield self.wait(dooropen,lighton,all=True) to test for dooropen AND lighton
It is also possible to check for several values of one state:
  yield self.wait((light,'green'),(light,'yellow')) tests for lighth is green of yellow
  
The method wait can have an optional timeout parameter.
If they are timed out, Component.fail() is True.

If a component is in a wait state, the status waiting will be returned.
In order to test for this state, use either
  c.state() == waiting
or
  c.iswaiting()
See the example script demo wait.py for a demonstration of the trigger and time out functionality.

Deprecated functionality:
In method Component.request(), it is no longer allowed to specify
greedy behaviour. Also strict_order is not anymore supported.
The reason for this is its limited use and stability.

Technical note: The process of honouring requests is now optimized by keeping track of
the minimal requested quantity for each resource.

Method request_failed() changed to failed().
This method now also refers to fails of wait.

For Monitor and MonitorTimestamp, the tallied values are now converted to a numeric
equivalent, if not yet int/float. Values of type bool are converted to 0 for False and
1 for True (as usual).
For all other types a conversion to int/float is tried. If that's not possible,
0 is used.
So after
  m=sim.Monitor(name='m')
  m.tally(2)
  m.tally(True)
  m.tally('12')
  m.tally('red')
m.x() is array([2,1,12,0])
This automatic conversion is used in all monitor methods, apart from getting the
current value.
So, after the above code,
  m() will return 'red'
The unprocessed values are available in the lists
  Monitor._x
end
  MonitorTimestamp._x (along with the coresponding MonitorTimestamp._t)
So, after the above code m._x is (2,True,'12','red') .

The __repr__ methods of Environment, Queue, Component, Monitor, Resource and the
distributions, now return
    Environment(name), Queue(name), ...
E.g. now
    q=sim.Queue('visitors')
    print(q)
returns
    Queue(visitors)
Getting information about one of the above class instances is now provided by
the method print_info (formerly available via __repr__).
E.g. 
    q=sim.Queue('visitors')
    print(q)
prints something like
    Queue 0x26e8e78ada0
    name=visitors
    no components
  
The default random stream when initializing Environment is now 1234567. If a
purely, not reproducable, stream by by specifying Environment(random_seed=None)
or sim.random_seed(None).
If you don't want any action when calling Environment (thats usually for
subsequent run) (cf. Elevator animated.py specify the null string, so
Environment(random_seed='')
All sample models have been updated to reflect this change, i.e. no more
random_seed=1234567 in the call to Environment, there.

Convention change:
Instead of naming the default environment de, from now env is prefered.
All sample models have been updated accordingly.

Documentation change only:
Package numpy is required.
The order of components in Queue.union() and Queue.intersect() is now specified.

Packaging remarks:
Release notes.txt is now called changelog.txt, to be more in line with PyPI standards.

salabim is now on PyPI. So now you can install salabim also with pip install salabim!

version 2.1.3  2017-08-24
=========================
Upto now it was a requirement to build an __init__ method with a call
to super().__init__ if the component had to be initialized in some way.
This is a rather awkward construction and difficult to grasp for beginners.
Although this construction is still accepted, there is now a more elegant
method: setup.
If this method is present in the definition of a component, it will be called 
after salabim has done all its initialization and even after the activate 
statement, if applicable.
The method may have arguments. If so, whencreating the component, it is
required to use keyword arguments.

salabim any version                    salabim>=2.1.3
--------------------------------------------------------------------
class Car(sim.Component):              class Car(sim.Component):
    def __init__(self,name,color):         def setup(self,color):                 
        super().__init__(name=name)            self.color=color                    
        self.color=color               Car(name='BMW',color='red')
Car(name='BMW',color=red)     
                              
Note that the __init__ construction is still available.

All examples that used the __init__ construction have been updated
accordingly.     

Both salabim and all examples now conform to PEP8 (with the exception
of requirements on line length and visual indent).
    
Bug in print_statistics when monitoring was False fixed.


version 2.1.0
=========================
Not released

  
version 2.1.2  2017-08-21
=========================
New functionality:
When a Component, Queue or Reseource is created, and the name ends with a period to
signify auto serializing, the first created object with that name does not get serialized.
So after
  wait0=sim.Queue('wait.')
, the name of wait0 is 'wait' .
When a second object with that name is created, the first object is serialized as yet.
So after
  wait0=sim.Queue('wait.')
  wait1=sim.Queue('wait.')
, the name of wait0 is 'wait..............0'
This also holds for Components that are named after their class, like after
  class TrafficLight(sim.Component):
      pass
  t=TrafficLight()
, the name of t is 'trafficlight'
When more traffic lights are created, the name of t will become
'trafficlight.......0'
  

Name changes for a Component, Queue and Resource are now traced.

Creation of a Component, Queue and Resource is now traced.

Bug in Component.hold() fixed.

version 2.1.1  2017-08-19
=========================
Method Queue.print_statistics() now shows more information.
New: Resource.print_statistics()

If a component now terminates (no more events), all claimed resources are now
automatically released.
Note, that this does not hold for cancellation of a component.
 
version 2.1.0  2017-08-18
=========================
At creation of a component, it is now possible to specify a process other than self.process to start.
The new process parameter for the init of a component is a string containing the name of the 
(generation)function. 
Now, there also a check to see if process is a generator (i.e. contains at least one yield statement).

If there is a process attribute in a component, but you do not want that to be activated,
specify process=None. The parameter auto_start is phased out, as there is now process=None.

The process parameter of Component.activate() has been changed. It is now a string containing the
name of the process to be started. If None, no change.

With the function running_process, the name of the currently running process can be retrieved.
For data components, None will be returned.


New to salabim are monitors, which are very useful for collecting (statistical) data. 
It is possible to tally values based on occurence, like the length of a ship, each time one is
created. Or the length of stay for components leaving a queue.
Another feature is a timestamped value. This is useful when collecting data on a time axis,
like the length of a queue. Each time the queue length changes, the new length, together
with time is then collected. This is a much more accurate and usually more efficient way of 
collecting data than just sampling on a regular basis.

Queue now supports monitoring of key statistics:
  length *
  length_of_stay

Resource now supports monitoring of key statistics:
  requesters.length *
  claimers.length *
  requesters.length_of_stay
  claimers.length_of_stay
  claimed_quantity *
  available_quantity *
  capacity *
  
The timestamped monitors (marked with a *) can be also used to query the current value, like
  c=myresource.claimed_quantity() or
  l=myqueue.length() although len(myqueue) is preferred
  
Monitors can be disabled/enabled with monitor (on the level of a Resource, a Queue or an individual Monitor or
MonitorTimeStamp).

salabim <2.1.0                     salabim >= 2.1.0 
-------------------------------------------------------------------------------   
Queue.reset_statistics()           Queue.reset() / Queue.monitor()
Queue.minimum_length()             Queue.length.minimum()
Queue.maximum_length()             Queue.length.maximum()
Queue.number_passed()              Queue.length_of_stay.number_entries()
Queue.number_direct_passed()       Queue.length_of_stay.number_entries_zero()
Queue.mean_length()                Queue.length.mean()
Queue.mean_length_of_stay()        Queue.length_of_stay.mean()
Queue.minimum_length_of_stay()     Queue.length_of_stay.minimum()
Queue.maximum_length_of_stay()     Queue.length_of_stay.maximum()
Queue.length()                     Queue.length() / len()
Queue.print_statistics()           Queue.print_histogram()
                                   Queue.length.std()
                                   Queue.length.median()
                                   Queue.length.percentile()
                                   Queue.length.bin_count()
                                   Queue.length_of_stay.std()
                                   Queue.length_of_stay.median()
                                   Queue.length_of_stay.percentile()
                                   Queue.length_of_stay.bin_count()                                   
                                   Resource.availabe_quantity ==> MonitorTimeStamp
                                   Resource.claimed_quantity ==> MonitorTimeStamp
                                   Resource.capacity ==> MonitorTimeStamp
Resource.capacity(cap)             Resource.set_capacity(cap)
                                   Component.requested_resources()
                                   Component.requested_quantity(resource)

All monitors can be used with MatPlotLib. For Monitor, there is Monitor.x() to get an array of all
tallied values. For MonitorTimestamp, MonitorTimestamp.xduration() and MonitorTimestamp.xt() are available.
Note that for the time a MonitorTimestamp is disabled, x will be nan.

Defining a non timestamped monitor (class Monitor) is fairly straightforward.
Defining a timestamped monitor is a bit more complicated. The Lock with monitor script shows an example.
Furthermore, refer to the manual for details.

As a consequence of this, Resource.capacity() can no longer be used to change the capacity. 
A new method Resource.set_capacity() is provided, instead.

All examples have been updated to support or show the new functionality.

Thanks to Frans Sopers: Bug in Component.release() fixed.
Thanks to Jan Knoop: arialmt font is now included in getfont, which is required for iPad without additional fonts.

version 2.0.2  2017-08-08
=========================
Internal event handling changed, in order to be able to use all event methods (i.e.
activate, hold, request, standby, cancel and passivate regardless whether
the component is current or not). For the current component, always use yield ...
Also, now it is possible to activate, hold or passivate main.

Component.reschedule() and Component.reactivate had been phased out. Both are replaced
by the more versatile Component.activate() method.

Component.activate() has an additional parameter keep_request, which controls whether
pending requests are to be kept upon an activate.

Environment.stop_run() and stop_run() has been phased out. 
Use the much more logical Environment.main().activate() or env.main().activate() instead. 
This allows the user to specify the time (including inf) of the main reactivation.
The models 'Dining philosophers animated.py' and 'Elevator animated.py' have been
updated accordingly.

Component.request() has now an additional parameter fail_delay.

When a request is pending, the status of the component used to be scheduled, but is now requesting.
Also, a new method Component.isrequesting() is provided to test for this new status

The methods Component.get_priority and Component.set_priority are replaced by one method: Component.priority.

'salabim release notes.txt' is now called 'Release notes.txt'.

The github distribution now also contains the example scripts as used in the manual. 

version 2.0.1
=========================
In the specification of Distribution, it is now also possible to use:
c1       ==> Constant(c1)
c1,c2,   ==> Uniform(c1,c2)
c1,c2,c3 ==> Triangular (c1,c2,c3)

It is not required to use the exact name of the distribution anymore.
If you specify only the first letters of the distribution name, the correct distribution will be selected,
regardless of casing.

Examples of these new features
Uniform(13)  ==> Uniform(13)
Uni(12,15)   ==> Uniform(12,15)
UNIF(12,15)  ==> Uniform(12,15)
N(12,3)      ==> Normal(12,3)
Tri(10,20).  ==> Triangular(10,20,15)
10           ==> Constant(10)
12,15        ==> Uniform(12,15)
(12,15)      ==> Uniform(12,15)

Normal distribution now has a default value for standard_deviation : 0, so effectively constant
Uniform distribution now has a default value for upperbound : lowerbound, so effectively constant
Trianguar distribution now has a default value for high : low, so effectively constant
Trianguar distribution now has a default value for mode : (low+high)/2, so a symmetric distribution

version 2.0.0  2017-07-24
=========================
Major reorganization of the interface.

All properties has been phased out and made place for a method. This is
done in order to be more Pythonic and consistent. Also, overriding is now easier.

Version 2.0.0                       Version 2.0.0                  
---------------------------------------------------------------------------------------
Environment.peek                    Environment.peek()
Environment.main                    Environment.main()
Environment.now                     Environment.now()
Environment.trace                   Environment.trace(value)
Environment.current_component       Environment.current_component()
Environment.name                    Environment.name(txt)
Environment.base_name               Environment.base_name()
Environment.sequence_number         Environment.sequence_number()

Component.claimed_resources         Component.claimed_resources()
Component.request_failed            Component.request_failed()
Component.name                      Component.name(txt)
Component.base_name                 Component.base_name()
Component.sequence_number           Componnt.sequence_number()
Component.suppress_trace            Component.suppress_trace(value)   
Component.mode                      Component.mode(value)
Component.ispassive                 Component.ispassive()
Component.iscurrent                 Component.iscurrent()
Component.isscheduled               Component.isscheduled()
Component.isstandby                 Component.isstandby()
Component.isdata                    Component.isdate()
Component.creation_time             Component.creation_time()
Component.scheduled_time            Component.scheduled_time()
Component.mode_time                 Component.mode_time()
Component.status                    Component.status()
Component.now                       phased out, use Component.env.now() 
Component.main                      phased out, use Component.env.main()
Component.trace                     phased out, use Component.env.trace(value)
Component.current_component         phased out, use Component.env.current_component()

Resource.requesters                 Resource.requesters()
Resource.claimers                   Resource.claimers()
Resource.capacity                   Resource.capacity(cap)
Resource.claimed_quantity           Resource.claimed_quantity()
Resource.strict_order               Resource.strict_order(value)

Queue.name                          Queue.name(txt)
Queue.base_name                     Queue.base_name()
Queue.sequence_number               Queue.sequence_number()
Queue.head                          Queue.head()
Queue.tail                          Queue.tail()
Queue.pop                           Queue.pop()
Queue.length                        Queue.length(), len() recommended
Queue.minimum_length                Queue.minimum_length()
Queue.maximum_length                Queue.maximum_length()
Queue.minimum_length_of_stay        Queue.minimum_length_of_stay()
Queue.maximum_length_of_stay        Queue.maximum_length_of_stay()
Queue.number_passed                 Queue.number_passed()
Queue.mean_length_of_stay           Queue.mean_length_of_stay()
Queue.mean_length                   Queue.mean_length()
  
Uniform.mean                        Uniform.mean()
Triangular.mean                     Triangular.mean()
Constant.mean                       Constant.mean()
Exponential.mean                    Exponential.mean()
Normal.mean                         Normal.mean()
Cdf.mean                            Cdf.mean()
Pdf.mean                            Pdf.mean()
Distribution.mean                   Distribution.mean()

Uniform.sample                      Uniform.sample()
Triangular.sample                   Triangular.sample()
Constant.sample                     Constant.sample()
Exponential.sample                  Exponential.sample()
Normal.sample                       Normal.sample()
Cdf.sample                          Cdf.sample()
Pdf.sample                          Pdf.sample()
Distribution.sample                 Distribution.sample()

AnimateSlider.v                     AnimateSlider.v(value)
---------------------------------------------------------------------------------------
***ATTENTION***
Be very careful with adding the parentheses, particularly when using in
logical tests, like:
    if c.ispassive: #always True ! 
    if c.status==passive #always False !
    if trace: #always True 
and never assign to one of these methods,like 
    env.trace=True #overrides the trace method of env
    c.name='Machine' # overrides the name method of the component c
    
Nearly all existing models will need be updated. All sample files are now version 2 compatible.    

Nearly only internal change: the possible values of the status of a component were up to version 2.0.0
global variables, containing the name of the status. From this version the values of status are actually
references to methods that return the name of the status. This affects passive, data, current, standby,
scheduled and suspended. From an application point of view this does not change anything.
Testing of the status is still done with (e.g.)
    if c.status()=sim.passive:
or, better yet,
    if c.ispassive():    
Only when the status has to be printed, be sure to *call* the status() method, thus
print('current status of c=', c.status()())

If the distribution Pdf gets now a distribution as an x-value, not the 
distribution, but a sample of that this distribution will be returned.
Example:
  d=sim.Pdf((Uniform(10,20),10,Uniform(20,30),80,Uniform(30,40),10))
  d.sample() # 10% between 10 and 20, 80% between 20 and 30 and 10% between 30 and 40.
  d.mean() # is 25.

The argument list if Component.request() is redefined. See the manual or docstring
for details.
The argument list if Component.release() is redefined. See the manual or docstring
for details.

The method Queue.index_of() has been renamed Queue.index() to be more in line
with Python standards.

The script to install salalabim in site-packages is now called install.py

There are two new sample models, 'Lock with resources' and 'Lock with resources animated',
showing a different approach of the Lock model, involving resources.

Major improvements of the docstrings and manual (at www.salabim.org/manual).
Just a reminder: you can get help on all methods
of salabim (pages and pages of information) with
    import salabim as sim
    help(sim)
or just one method or class by (e.g.)
    import salabim as sim
    help(Animate)
    help(Component.enter)
    help(env.now)
    
Bug fixes.
        
version 1.1.3  2017-07-22
=========================
Pythonista could not handle the long one line statement defining the std_fonts.
Therefore the definition of the dictionary is now in several lines of maximal 80
characters. The table is now also sorted (only for cosmetic reasons).
The colornames dictionary is now sorted (only for cosmetic reasons).

version 1.1.2  2017-07-20
=========================
Under the hood restructuring of classes, thus enabling overriding.

In order to support packaging (i.e make salabim a site_package), the simulation 
environment is no longer automatically defined.
It is now necessary to make an environment in the application, by:
    Environment()
The Environment class has now an extra argument, is_default_env, which is True by 
default.
Also, the global variable random has been phased out. Instead, salabim uses now
the random class directly in all statistical sampling functions.
It is possible to set the seed of the random stream by means of
- random_seed()
- random.seed(), provided random is imported
- Environment(random_seed=...)
The standard random stream is now used in all distribution definitions, unless 
a randomstream is explicitly specified.

Other than in previous versions, reproducibility is only available if 
a random seed value is specified, usually when defining an Environment.

All sample programs are defined in such a way that they give reproducible results.

main is no longer a global variable. You can use either the main
property in Component or Environment classes or just main() from the
salabim module, e.g. with env.main()

The default environment can be queried with the function default_env(),
e.g. de=sim.default_env().

All sample filea are updated according to the new interface.

Font handling has been improved. It is now allowed to specify a font by the
file name or the descriptor, e.g.
'timesi' or 'Times New Roman Italic'.
The case is not important any more.
The function show_fonts() can be used to retrieve all currently available
font names (on this machine).

The salabim_install script now installs salabim in a more Pythonic way
in the site-packages folder.

Bug in slider function under Pythonista fixed.

version 1.1.1  2017-07-08
=========================
Bug in video production fixed.
Minor changes in the sample programs.

version 1.1.0  2017-07-08
=========================
The animation of all sample models is completely restructured in order to separate the simulation model
code from the animation code. This leads to much easier to read and debug models. Also the same code can now
be used for animation and production (non animated) applications.

Introduced an attribute 'mode' for components, which can be set either with an assignment or as a parameter of: 
    initialization of a component
    passivate
    activate 
    reactivate
    hold
    activate
    standby
    request
    cancel
This attribute can be very useful for animations which run more or less separate from the simulation code.
The mode parameter may be any type, although str is possibly the most useful.
Also, the mode is now shown in a trace.

The attribute passive_reason has been phased out, as mode offers similar functionality for passive components. Be aware that mode is not reset automatically!

When the mode is set, either by an assignment or one of the above methods, the property mode_time is
set to now. This is particularly useful for hold, in order to assess when the component started the 
hold, like in
  fraction=sim.interpolate(env.now,comp.mode_time,comp.scheduled_time,0,1)
This technique is used in the sample models 'Lock animated' and 'Elevator animated'.

A bug in PIL caused non black texts to have a kind of outline around the characters in Animate(text=...).
This was especially visible with white texts on a dark background.
Code has been added to correct this behaviour.

Introduced a parameter visible for Animate and Animate.update. The method visible of animation
objects can be overridden. This is especially useful in dashboard like animations.

AnimateButton and AnimateSlider no longer have a layer parameter, as these UI elements are now always
on top of the Animate objects.

The animation parameters of run() are all removed. Now, a new animation_parameters method (in class Environment)
is used to set all parameters.
The function animation_speed has been phased out. It is now in animation_parameters.

Pythonista animation performance is increased by building up the image completely with PIL,
before putting it into a scene. This also results in higher quality images
(essentially the same as under tkinter).

On Pythonista, the animation size is now automatically set to the dimension of the screen.
This can be overridden with a call to animation_parameters.

In the animation, the Quit button has been renamed to Stop.

The color of the text in Animate(text=) is now set with textcolor0 and textcolor1 instead of fillcolor0 and
fillcolor1.

If a specified font in Animate cannot be found, the system now searches for calibri and next for arial fonts.

Bug fix: after a yield self.request call, the status of the component was still current, instead of scheduled.

version 1.0.6  2017-06-16
=========================
Animation on CPython platform is now slightly smoother, because there was a bug in the timing routine, which
caused that the animation was doomed to be slower than 30 fps.

The upper right hand corner now shows, optionally, the number of frames per second fps).
The run command has three new parameters, which control what is shown in the upper right hand corner, in case of animation:
        show_fps : bool
            if True, show the number of frames per second (default)|n|
            if False, do not show the number of frames per second

        show_animation_speed: bool
            if True, show the animation speed (default)|n|
            if False, do not show the animation speed

        show_time: bool
            if True, show the time (default)|n|
            if False, do not show the time

The text of an AnimateButton is now set via function text(), which can be overridden.

The function str_or_function had been phased out, as this can be achieved now by overriding methods.

version 1.0.5  2017-06-14
=========================
Complete overhaul of the tkinter way objects are shown. Instead of deleting all canvas objects
for each animation tick, salabim now tries to minimize the number of create_image calls, 
by using itemconfig and coords and reusing canvas elements, if possible and necessary.
The result is a much smoother animation, particularly at higher animation speeds.
The above doesn't, unfortunately, apply to Pythonista.

Now all of the following methods of the class Animate may be overridden:
    def x(self,t=None)
    def y(self,t=None)
    def offsetx(self,t=None)
    def offsety(self,t=None)
    def angle(self,t=None)
    def linewidth(self,t=None)
    def linecolor(self,t=None)
    def fillcolor(self,t=None)
    def circle(self,t=None)
    def line(self,t=None)
    def polygon(self,t=None)
    def rectangle(self,t=None)
    def width(self,t=None)
    def fontsize(self,t=None)
    def text(self,t=None)
    def anchor(self,t=None)
    def image(self,t=None)
    def layer(self,t=None)
, thus giving the possibility to use non linear movement, special effects, etc.
 
The distribution now also contains a script called salabim_install, which will install salabim
in the appropriate site-packages folder. Once installed, salabim can be used from whatever location!
 
version 1.0.4  
=========================
Animation interpolation can now be overridden (monkey patched) to allow for
non linear interpolation or advanced animation techniques.
For this make a new class based on Animation and redefine the necessary functions,
like x,y, angle.

As illustration of the possibilities, have a look at demo_override.py

Duck typing implemented for more Pythonic behaviour.


version 1.0.3  2017-05-26
=========================
Minor bug with stop_run in animation mode fixed.


version 1.0.2  2017-05-07
=========================
The animation part of salabim has been redesigned, to make it more
reliable and easier to access.
Animation is not initialized with Animation() any more. Instead, the animation
(and creation of a tkinter canvas in case of CPython) is now started by the
run function.
Therefore, the run function has now a number of additional parameters to set
the size of the canvas, define scaling and transformation, etc.

An animation object is now a class. One of the attributes is the environment
where it belongs to. There are three classes defined:
  Animate()
  Animate_button()
  Animate_slider()
If you don't need animation, PIL does not need to be imported any more.
  
Also, the run function now supports the creation of an .mp4 video.
For video production, numpy and cv2 (opencv) are required.
This feature is not supported on Pythonista.

The animation_speed can now be get/set by calling animation_speed().

A number of function have been renamed to be more in line with Python naming
(like isinstance):
  is_passive    -> ispassive
  is_current    -> iscurrent
  is_scheduled  -> isscheduled
  is_standby    -> isstandby
  is_data       -> isdata
  
Bug when in a call to Animate() t0 was specified fixed.

version 1.0.1  2017-03-13
=========================
Iteration of components in a queue is completely reimplemented.
Instead of the function components, iteration is now done the Pythonic way, like
  for comp in myqueue:
Also, the algorithm now allows for very fast iteration even if components are leaving the queue 
during the iteration. If there is a change (enter or leave or change of order) during the iteration, the iteration is guaranteed to deliver all components in the queue after the change correctly.
Therefore, there is no need for specification of static and/or removals_possible as in the out phased
components function.

It is also possible to traverse a queue from tail to head, by using reversed as in:
    for comp in reversed(myqueue):
This is also a generator where updates are possible during the iteration.

If you want to get a specific element in a queue, this can be now achieved with
    comp=myqueue[1] to access the second element in the queue.
So, therefore
    myqueue[0] is equivalent to q.head
    myqueue[-1] is equivalent to q.tail
Nevertheless head and tail are still supported, to be more in line with Tomas/Must terminology.
The function Queue.component_with_index has been phased-out.    

Slicing of queues is now supported. So
  for c in myqueue[1:3]:
      print(c.name)
will print the names of the second and third element of the queue (provided they are available).
Also,
  for c in myqueue[::-1]:
      print(c.name)
will list the contents of myqueue, in reverse order. In contrast with the above mentioned reversed() this
is just a static snapshot.
 	  
If a static snapshot of the queue contents is required, use 
  myqueue[:]
now. In contrast to previous versions of salabim, this is not faster than the standard iteration.

The functions Queue.contains(c) and Component.is_in_queue(q) have been phased out. Instead salabim 
now support the much more legible and Pythonic in construction, for example
  if comp in myqueue:
or 
  if comp not in queue:
  
The length of a queue can be found with len(q). The old style Queue.length is still available.

Automatic numbering of components, queues, resources and environments now starts with 0 (in contrast to 1 in previous versions). This is done to be more in line with Python.

All sample models are updated to accommodate the above changes.

Bug fixed: Changing a priority with set_priority, did affect the queue statistics. Now works as intended.

Bug fixed: The parameter use_toplevel in Animation() works as intended.

version 1.0.0  2017-03-01
=========================
The following names have been changed:
SalabimComponent          Component
SalabimQueue              Queue
SalabimEnvironment        Environment
SalabimResource           Resource
salabim_random            random
reset_env (method)        reset
Distribution_from_string  Distribution

The global function reset_env() (not the method of Environment) has been
phased out. Use default_env.reset() instead.

The default process to be executed when creating a component is now called
process, instead of action.
The proc argument of activate has been changed to process.
The proc argument of reschedule has been changed to process.

It is highly recommended to use the pythonistic
  import salabim
or
  import salabim as sim
instead of 
  from salabim import *
In all examples, we now use
  import salabim as sim
If you use the latter form, all salabim items have to be preceeded by sim. ,
like sim.Component, sim.Resource, env.main, sim.passive, env.now(), sim.inf.
If you want to use a salabim item without prefixing, use something like
  from salabim import inf,main
along with
  import salabim as sim
  
In order to avoid having to specifiy sim.passive, sim.scheduled, etc.
when importing as recommended, a number of new properties are introduced:
  is_passive (equivalent to status=sim.passive)
  is_current (eqivalent to status==sim.current)
  is_scheduled (equivalent to status==sim.scheduled)
  is_standby (equivalent to status==sim.standby)
  is_data (equivalent to status==sim.data)
  
Technical note: The test routines, which were present in the salabim source,
are now in a separate module, called salabim_test.py.

Style note: the name salabim is now all lowercase, to be more Pythonistic.

The utility program salabim0to1.py translates existing version 0 models into
the new version 1 style.
The program translates *ALL* version 0 programs in the current directory,
adding a 1 to the name, e.g. Lock.py will be translated to Lock1.py
Please note, that the translation is not guaranteed to be 100% accurate,
and some fine tuning might be necessary.

All sample models are updated accordingly.

version 0.9.17 (not released)
=============================
Salabim animations can now work in parallel with other modules using tkinter,
like graphics.py. If so, set the parameter use_toplevel to True.
If a user would like to start its own tkinter window(s) next to salabim's
window (initialized with tkiniter.Tk(), just use root=tkinter.Toplevel()
instead of root=tkinter.Tk()
 
version 0.9.16 2017-02-15
=========================
Bug when using Salabim without animation fixed.

version 0.9.15 2017-01-14 
=========================
Improved way of animating circles. Also, now support for offset (most useful in combination with angle).
Better support for transparency(alpha blending) for fill and line colors.

Bugs fixed.

version 0.9.14 2017-02-02
=========================
The classes AnimateCircle, AnimateLine, AnimatePolygon, AnimateRectangle, AnimateImage and AnimateText are now all combined in one class: Animate.
All animations, including images now support scaling and rotation. Also, under Pythonista, convave polygons are now available.
All animation objects support semi-transparency (also called alpha blending or opacity).
Salabim now requires PIL (Pillow) for animations.

Bugs fixed.

version 0.9.13 2017-01-14
=========================
Animation on iPad / Pythonista now supported.
Button and slider animation objects now available without the need to use tkinter functions.
Button and slider animation objects are now also available under Pythonista.
All functions are now documented as docstrings.


version 0.9.12 2016-12-16
=========================
SalabimQueue, SalabimComponent, SalabimResource and SalabimEnvironment as well as distribution now feature __repr__, in order to print the contents of the object.
Thus,e.g., print(q1) now print information of the contents of q1

Now any environment may be reset to initial condition, with reset_env().
The function salabim_reset is renamed into reset_env, which is equivalent to default_env.reset_env()
Environments now have a (optionally serialized) name.

In order to make the usage of the default environment, a number of functions have been changed into global variables:
  default_env
  main

Please observe that these variables should *NEVER* be set by the user.
Tracing of the default environment is still controlled via the trace function or the setter/getter default_env.trace.
Also, now() and current_component() are still to be used to access now and current_component for the default_env.
Alternatively, now, current_component and trace can be accessed directly via the setter/getter of any SalabimComponent.

The function show() of a SalabimQueue has been renamed to print_statistics() and will no longer show the contents of a queue. In order to print the contents of a queue just use print(q).

Introduced a parameter 'reason' for passivate(). A program can now check why a component is passive by means of the property passive_reason. If a component is not passive, passive_reason is None.

Extensive support for animation with tkinter.

Bugs fixed.


version 0.9.11 2016-11-29
=========================
Bug in standby fixed.

When the name of a component is derived from the class name, the name is now serialized, e.g.
  s=Ship()
  print(s.name)
will print
  Ship...............1


version 0.9.10 2016-11-28
=========================
Overhaul of the way randomstreams are used with the Salabim distributions.
Now, instead of a seed, all distibutions can be given a randomstream. If this parameter is omitted, the default randomstream called salabim_random will be used.
This salabim_randomstream will be automatically started with a reproducable seed, i.e. -1.
The user may reseed this distribution with salabim_random.seed(seed) or salabim_random.seed() for a system time dependent (not reproducable) stream.
If the user does not want to use the salabim_random stream, all distributions may be called with something like randomstream=random.Random(11000) or randomstream=mystream.
Please note that the randomstream salabim_random may be (and is recommended to be) used by the native Random sampling routines, like random, shuffle, gauss and sample.

 
This version contains an extensive animation engine, that is not yet fully tested nor documented. This functionality will be soon available, along with several examples. The animation engine will be fully  available on CPython and Pythonista platforms with tkinter and PIL (Pillow) installed and and with limited functionality when PIL (Pillow) is not available like in PyPy.


version 0.9.8  2016-11-13  
=========================
Introduced property base_name and sequence_number for components, queues and resources

sorting_parameter renamed priority to be compatible with resource terminology.

SalabimComponents, SalabimQueue and SalabimResource now have a seqence_number and a base_name attribute (property). The base_name is the string given at initialization time. Even for components, queues and resources whose base name does not end with a period, the sequence_number is available.
When assigning a new name to a component, queue or resource, base_name and sequence_number will be set according to the new name.

Bug fix for method release.

version 0.9.7  2016-11-10  
=========================
The queue requests has been renamed to requesters.

Properties that do not return a value, are now functions (again):
  yield passivate  ==> yield passivate()
  yield cancel     ==> yield cancel()
  yield standby    ==> yield standby()
  step             ==> step()
  clear            ==> clear()
  reset_statistics ==> reset_statistics()
  run_stop         ==> run_stop()

Please be sure to update older applications, particularly with respect to
passivate and stop_run, as the old syntax is still valid Python code, but the
functions calls without parenthesis will have no action!

Added comments to resource functionality.


version 0.9.6  2016-11-06
=========================
Specification of a pdf now allows the x value to be a pair in the form of a list or tuple.
If so, uniform sampling between these will be used if 'selected'.
Example
d=Pdf((10,(5,10),80,(10,50),10,(50,100))
In this case 10% will be 5-10, 80% between 10 and 50 and 10% from 50 to 100.
There is not any restriction on the value pairs, so they may be overlapping or be completely separate. Also, scalars may be
used in the same pdf specification. So the following is allowed, although not very likely to be useful:
d=Pdf((10,0, 20,(-5,50), 30,(100,500), 1,2000)

The method mean() is now available for all distributions.

If no name is specified when initializing a SalabimComponent, the name is now derived from the
class name (lowercased), e.g.
  mycar=Car()
makes car the name of mycar.

Queue methods union, intersect and difference optimized for performance.

Introduced support for resources requesting/releasing resources. The functionality is similar to resources and levels in SimPy and semaphores in Tomas.
This is a concept, with which a component can claim a quantity from a resource. A component is able to request from more than one resource at a time ('and' clause).
Once all the requested quantities are available, the program continues with the next statement.
The requested quantities are then claimed.
Anyone (but most of the time it will be the requesting component) can then release (part of) the claimed quantities.
The resource can be also anonymous, which means that the claimed quantities are not connected to a component, but just treated as one heap. This is similar to levels in SimPy.
*to be described in more detail*

The following methods are now properties and are to be used without ():
SalabimQueue
  name *)
  head
  tail
  pop
  length
  minimum_length
  maximum_length
  minimum length_of_stay
  maximum_length_of_stay
  number_passed
  number_passed_direct
  mean_length_of_stay
  mean_length
  clear
  reset_statistics

SalabimEnvironment
  step
  peek
  main
  now
  trace *)
  current_component

SalabimComponent
  passivate
  cancel
  standby
  stop_run
  granted_resources
  request_failed
  name *)
  main
  now
  trace *)
  creation_time
  scheduled_time
  current_component
  status

Distributions_from_string
  mean
  sample

SalabimResource
  requests
  claimers
  claimed_quantity
  strict_order *)
  name *)

*) means that these are also setters, so for instance c.name='box'.

Finally, the following functions, which are not part of a class still require ():
  main()
  now()
  trace() or trace(val)
  step()
  peek()

version 0.9.5  2016-10-27
=========================
It is now possible to use a default environment.
In most cases there will be no need to use the concept of environments at all, which results in an
easier to understand and read program.
Therefore, upon startup, Salabim automatically creates an environment, which is available via
default_env() if required.
The default environment is an excellent placeholder for pseudo global variables.
A new default environment (e.g. for a new run or experiment), can be set via salabim_reset(). Note that
also the pseudo globals will be 'lost' then.

For the (few) methods/properties that required an environment as parameter, the following alternatives
are available:
  env.run()                                run()
  env.peek()                               peek()
  env.step()                               step()
  env.now()                                now()
  env.main()                               main()
Furthermore tracing control is implemented differently and may be set/retrieved now via
  env.trace()                              trace()
Both with SalabimEnvironent.__init__ as well as salabim_reset the trace parameter can be set (it is False
by default).
 
It is now possible to schedule a component from the initialization by including an action() method in
the class for this component. If so, it will be auto started, optionally at a later moment, specified by the at, delay and urgent parameters as in activate.

All properties have been removed to be more consistent (reversing the changes of one of the previous
versions). Therefore, now all values to be retrieved, like q.length() and c.name() need a pair of parentheses.

Retrieving and setting of the sorting_parameter of a component in a queue is now done with *one* function: sorting_parameter.

The trace now also shows the name of the action generator, in case it's not action()?

Distributions are now documented. Please observe that Table is renamed to Cdf and Discrete if renamed to Pdf.

version 0.9.4  2016-10-25
=========================
The method components to iterate over all components in a queue now has an additional parameter
  'removals_possible'.
  If it is guaranteed that no components will leave the queue during the iteration, this parameter
  may be set to False.
  Also in that case, components that do not enter the queue *at the tail*, might be excluded
  from the iteration. The result is a speed increase (particularly with large queues).

Internal:
Optimalisations for several queue methods, by using the result of the check for membership of a queue in
subsequent actions.

version 0.9.3  2016-10-24
=========================
The method stop_run has been added.

version 0.9.2  2016-10-23
=========================
Major bug in the activate, hold, reactivate and reschedule fixed

Now supports also older versions of Python, where NumPy does not feature nan and inf.

Now Python 2.7 compatible (not fully tested yet).

Optimized the method components, which is particularly useful if the queues is large. The method was O(n^2) and is now O(n).

Beautified the trace output.


version 0.9.0  2016-10-23
=========================
This version has a number of changes compared to previous versions.

Salabim does not rely on SimPy anymore.

The statuses now comply more with Must and Prosim than with Tomas, in order to achieve a more consistent interface.

State transition diagram

  
from\to  |        data|   current|       scheduled|        passive|      standby|
---------+------------+----------+----------------+---------------+-------------+
data     |      -     |  activate|        activate|              -|            -|
         |            |        1)|                |               |             |
---------+------------+----------+----------------+---------------+-------------+
current  |  action end|         -|      yield hold|yield passivate|yield standby|
         |yield cancel|          |yield reschedule|               |             |
---------+------------+----------+----------------+---------------+-------------+
scheduled|      cancel|next event|      reschedule|      passivate|            -|
         |            |          |                |               |             |
---------+------------+----------+----------------+---------------+-------------+
passive  |      cancel|reactivate|      reactivate|              -|            -|
         |            |        1)|      reschedule|               |             |
---------+------------+----------+----------------+---------------+-------------+
standby  |      cancel|next event|      reschedule|              -|            -|
         |            |          |                |               |             |
---------+------------+----------+----------------+---------------+-------------+
1) via scheduled

The method activate now has an optional parameter for the action. If omitted, action will be assumed. So if the action of the component
description is just called action, then the component can be started with component.activate(), which is functionally the
equivalent to component.activate(component.action()).

The method hold now supports 'duration' as well as 'till' parameters (even both are permitted)
activate, reactivate and reschedule now support 'at' as well 'delay' (even both are permitted)
All transitions to current are via scheduled now.

It is now possible to issue a new action in activate, reactivate and reschedule, even for the current component via reschedule. 

The methods reactivate, activate, reschedule and hold now have an 'urgent' parameter, which, if True, will schedule
this component before each component with the same scheduled time. When urgent=False (default), component are scheduled after all
components with the same scheduled time.

The method run now supports 'duration' as well as 'till' parameters (even both are permitted).

The scheduled time is now accessible for all component via scheduled_time. If the component is data or passive, inf will be returned.
The creation time is now available via creation_time.


Many functions without parameters are now a property.

New naming:
    q.components (was q.iterate)
    q.mean_length (was q.average_length)
    q.mean_length_of_stay (was q.average_length_of_stay)
    q.add_in_front_of (was q.add_before)
    q.add_behind (was q.add_after)
    c.enter_in_front_of (was c.enter_before)
    c.enter_behind (was c.enter_after)

Names for queues and components are serialized separately now, if the name end with a period.

Introduced statistical distribution sampling.
    Exponential
    Normal
    Uniform
    Triangular
    Constant
    Table
    Discrete
    Distribution_from_string

Note that these distributions are not yet fully documented.

Improved trace functionality.


All functions and classes are now fully documented in the source code. Use help(...) to obtain information.
