salabim 24.0.13__tar.gz → 24.0.14.post3__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {salabim-24.0.13 → salabim-24.0.14.post3}/PKG-INFO +1 -1
- {salabim-24.0.13 → salabim-24.0.14.post3}/pyproject.toml +1 -1
- {salabim-24.0.13 → salabim-24.0.14.post3}/salabim/salabim.py +352 -26
- {salabim-24.0.13 → salabim-24.0.14.post3}/salabim.egg-info/PKG-INFO +1 -1
- {salabim-24.0.13 → salabim-24.0.14.post3}/tests/test_distributions.py +43 -2
- {salabim-24.0.13 → salabim-24.0.14.post3}/README.md +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/salabim/DejaVuSansMono.ttf +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/salabim/LICENSE.txt +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/salabim/__init__.py +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/salabim/calibri.ttf +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/salabim/mplus-1m-regular.ttf +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/salabim.egg-info/SOURCES.txt +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/salabim.egg-info/dependency_links.txt +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/salabim.egg-info/top_level.txt +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/setup.cfg +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/tests/test salabim.py +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/tests/test_cap_now.py +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/tests/test_componentgenerator.py +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/tests/test_datetime.py +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/tests/test_misc.py +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/tests/test_monitor.py +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/tests/test_process.py +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/tests/test_queue.py +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/tests/test_state.py +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/tests/test_store.py +0 -0
- {salabim-24.0.13 → salabim-24.0.14.post3}/tests/test_timeunit.py +0 -0
@@ -8,7 +8,7 @@ authors = [
|
|
8
8
|
{name = "Ruud van der Ham", email = "rt.van.der.ham@gmail.com"}
|
9
9
|
]
|
10
10
|
description = "salabim - discrete event simulation in Python"
|
11
|
-
version = "24.0.
|
11
|
+
version = "24.0.14-3"
|
12
12
|
readme = "README.md"
|
13
13
|
requires-python = ">=3.7"
|
14
14
|
dependencies = [
|
@@ -1,13 +1,13 @@
|
|
1
|
-
# _ _ _ ____ _ _ ___ _
|
2
|
-
# ___ __ _ | | __ _ | |__ (_) _ __ ___ |___ \ | || | / _ \ / ||
|
3
|
-
# / __| / _` || | / _` || '_ \ | || '_ ` _ \ __) || || |_ | | | | | |
|
4
|
-
# \__ \| (_| || || (_| || |_) || || | | | | | / __/ |__ _| _ | |_| | _ | |
|
5
|
-
# |___/ \__,_||_| \__,_||_.__/ |_||_| |_| |_| |_____| |_| (_) \___/ (_)|_
|
1
|
+
# _ _ _ ____ _ _ ___ _ _ _
|
2
|
+
# ___ __ _ | | __ _ | |__ (_) _ __ ___ |___ \ | || | / _ \ / || || |
|
3
|
+
# / __| / _` || | / _` || '_ \ | || '_ ` _ \ __) || || |_ | | | | | || || |_
|
4
|
+
# \__ \| (_| || || (_| || |_) || || | | | | | / __/ |__ _| _ | |_| | _ | ||__ _|
|
5
|
+
# |___/ \__,_||_| \__,_||_.__/ |_||_| |_| |_| |_____| |_| (_) \___/ (_)|_| |_|
|
6
6
|
# discrete event simulation
|
7
7
|
#
|
8
8
|
# see www.salabim.org for more information, the documentation and license information
|
9
9
|
|
10
|
-
__version__ = "24.0.
|
10
|
+
__version__ = "24.0.14"
|
11
11
|
|
12
12
|
import heapq
|
13
13
|
import random
|
@@ -9055,7 +9055,6 @@ by adding:
|
|
9055
9055
|
else:
|
9056
9056
|
return
|
9057
9057
|
|
9058
|
-
|
9059
9058
|
def _trywait(self):
|
9060
9059
|
if self.status.value == interrupted:
|
9061
9060
|
return False
|
@@ -10207,7 +10206,7 @@ class Event(Component):
|
|
10207
10206
|
"""
|
10208
10207
|
return self._action_taken
|
10209
10208
|
|
10210
|
-
|
10209
|
+
|
10211
10210
|
class Environment:
|
10212
10211
|
"""
|
10213
10212
|
environment object
|
@@ -11349,13 +11348,13 @@ class Environment:
|
|
11349
11348
|
|
11350
11349
|
if width is not None:
|
11351
11350
|
if self._width != width:
|
11352
|
-
self._width = width
|
11351
|
+
self._width = int(width)
|
11353
11352
|
frame_changed = True
|
11354
11353
|
width_changed = True
|
11355
11354
|
|
11356
11355
|
if height is not None:
|
11357
11356
|
if self._height != height:
|
11358
|
-
self._height = height
|
11357
|
+
self._height = int(height)
|
11359
11358
|
frame_changed = True
|
11360
11359
|
height_changed = True
|
11361
11360
|
|
@@ -11804,7 +11803,8 @@ class Environment:
|
|
11804
11803
|
for ao in an_objects:
|
11805
11804
|
ao.make_pil_image(self.t())
|
11806
11805
|
if ao._image_visible and (include_topleft or not ao.getattr("in_topleft", False)):
|
11807
|
-
image.paste(ao._image, (int(ao._image_x), int(self._height - ao._image_y - ao._image.size[1])),
|
11806
|
+
image.paste(ao._image, (int(ao._image_x), int(self._height - ao._image_y - ao._image.size[1])),ao._image.convert("RGBA"),)
|
11807
|
+
|
11808
11808
|
|
11809
11809
|
return image.convert(mode)
|
11810
11810
|
|
@@ -13201,7 +13201,7 @@ class Environment:
|
|
13201
13201
|
if co is None:
|
13202
13202
|
if len(g.canvas_objects) >= self._maximum_number_of_bitmaps:
|
13203
13203
|
if overflow_image is None:
|
13204
|
-
overflow_image = Image.new("RGBA", (self._width, self._height), (0, 0, 0, 0))
|
13204
|
+
overflow_image = Image.new("RGBA", (int(self._width), int(self._height)), (0, 0, 0, 0))
|
13205
13205
|
overflow_image.paste(ao._image, (int(ao._image_x), int(self._height - ao._image_y - ao._image.size[1])), ao._image)
|
13206
13206
|
ao.canvas_object = None
|
13207
13207
|
else:
|
@@ -15426,10 +15426,20 @@ class Animate2dBase(DynamicClass):
|
|
15426
15426
|
spec = self.image(t)
|
15427
15427
|
image_container = ImageContainer(spec)
|
15428
15428
|
width = self.width(t)
|
15429
|
+
height = self.height(t)
|
15430
|
+
|
15429
15431
|
if width is None:
|
15430
|
-
|
15432
|
+
if height is None:
|
15433
|
+
width = image_container.images[0].size[0]
|
15434
|
+
height = image_container.images[0].size[1]
|
15435
|
+
else:
|
15436
|
+
width = height * image_container.images[0].size[0] / image_container.images[0].size[1]
|
15437
|
+
else:
|
15438
|
+
if height is None:
|
15439
|
+
height = width * image_container.images[0].size[1] / image_container.images[0].size[0]
|
15440
|
+
else:
|
15441
|
+
...
|
15431
15442
|
|
15432
|
-
height = width * image_container.images[0].size[1] / image_container.images[0].size[0]
|
15433
15443
|
if not self.screen_coordinates:
|
15434
15444
|
width *= self.env._scale
|
15435
15445
|
height *= self.env._scale
|
@@ -15448,7 +15458,6 @@ class Animate2dBase(DynamicClass):
|
|
15448
15458
|
offsety = offsety * self.env._scale
|
15449
15459
|
|
15450
15460
|
alpha = int(self.alpha(t))
|
15451
|
-
|
15452
15461
|
image, id = image_container.get_image(
|
15453
15462
|
(t - self.animation_start(t)) * self.animation_speed(t),
|
15454
15463
|
repeat=self.animation_repeat(t),
|
@@ -15456,6 +15465,7 @@ class Animate2dBase(DynamicClass):
|
|
15456
15465
|
t_from=self.animation_from(t),
|
15457
15466
|
t_to=self.animation_to(t),
|
15458
15467
|
)
|
15468
|
+
|
15459
15469
|
self._image_ident = (spec, id, width, height, angle, alpha, flip_horizontal, flip_vertical)
|
15460
15470
|
|
15461
15471
|
if self._image_ident != self._image_ident_prev:
|
@@ -15736,6 +15746,9 @@ class AnimateClassic(Animate2dBase):
|
|
15736
15746
|
def width(self, t):
|
15737
15747
|
return self.master.width(t)
|
15738
15748
|
|
15749
|
+
def height(self, t):
|
15750
|
+
return self.master.height(t)
|
15751
|
+
|
15739
15752
|
def anchor(self, t):
|
15740
15753
|
return self.master.anchor(t)
|
15741
15754
|
|
@@ -15963,6 +15976,11 @@ class Animate:
|
|
15963
15976
|
|
15964
15977
|
if omitted or None, no scaling
|
15965
15978
|
|
15979
|
+
height0 : float
|
15980
|
+
width of the image to be displayed at time t0
|
15981
|
+
|
15982
|
+
if omitted or None, no scaling
|
15983
|
+
|
15966
15984
|
t1 : float
|
15967
15985
|
time of end of the animation (default inf)
|
15968
15986
|
|
@@ -16031,6 +16049,9 @@ class Animate:
|
|
16031
16049
|
width1 : float
|
16032
16050
|
width of the image to be displayed at time t1 (default: width0)
|
16033
16051
|
|
16052
|
+
height1 : float
|
16053
|
+
width of the image to be displayed at time t1 (default: height0)
|
16054
|
+
|
16034
16055
|
over3d : bool
|
16035
16056
|
if True, this object will be rendered to the OpenGL window
|
16036
16057
|
|
@@ -16099,6 +16120,7 @@ class Animate:
|
|
16099
16120
|
font -
|
16100
16121
|
fontsize0,fontsize1 -
|
16101
16122
|
width0,width1 -
|
16123
|
+
height0,height1 -
|
16102
16124
|
====================== ========= ========= ========= ========= ========= =========
|
16103
16125
|
"""
|
16104
16126
|
|
@@ -16134,6 +16156,7 @@ class Animate:
|
|
16134
16156
|
alpha0: float = 255,
|
16135
16157
|
fontsize0: float = 20,
|
16136
16158
|
width0: float = None,
|
16159
|
+
height0: float = None,
|
16137
16160
|
t1: float = None,
|
16138
16161
|
x1: float = None,
|
16139
16162
|
y1: float = None,
|
@@ -16152,6 +16175,7 @@ class Animate:
|
|
16152
16175
|
alpha1: float = None,
|
16153
16176
|
fontsize1: float = None,
|
16154
16177
|
width1: float = None,
|
16178
|
+
height1: float = None,
|
16155
16179
|
xy_anchor: str = "",
|
16156
16180
|
over3d: bool = None,
|
16157
16181
|
flip_horizontal: bool = False,
|
@@ -16198,10 +16222,12 @@ class Animate:
|
|
16198
16222
|
self.text0 = text
|
16199
16223
|
|
16200
16224
|
if image is None:
|
16201
|
-
self.width0 = 0 # just to be able to
|
16225
|
+
self.width0 = 0 # just to be able to interpolat
|
16226
|
+
self.height0 = 0
|
16202
16227
|
else:
|
16203
16228
|
self.image0 = image
|
16204
16229
|
self.width0 = width0 # None means original size
|
16230
|
+
self.height0 = height0
|
16205
16231
|
|
16206
16232
|
self.as_points0 = as_points
|
16207
16233
|
self.font0 = font
|
@@ -16263,7 +16289,7 @@ class Animate:
|
|
16263
16289
|
self.alpha1 = self.alpha0 if alpha1 is None else alpha1
|
16264
16290
|
self.fontsize1 = self.fontsize0 if fontsize1 is None else fontsize1
|
16265
16291
|
self.width1 = self.width0 if width1 is None else width1
|
16266
|
-
|
16292
|
+
self.height1 = self.height0 if height1 is None else height1
|
16267
16293
|
self.t1 = inf if t1 is None else t1
|
16268
16294
|
if self.env._animate_debug:
|
16269
16295
|
self.caller = self.env._frame_to_lineno(_get_caller_frame(), add_filename=True)
|
@@ -16322,6 +16348,7 @@ class Animate:
|
|
16322
16348
|
alpha0=None,
|
16323
16349
|
fontsize0=None,
|
16324
16350
|
width0=None,
|
16351
|
+
height0=None,
|
16325
16352
|
xy_anchor1=None,
|
16326
16353
|
as_points=None,
|
16327
16354
|
t1=None,
|
@@ -16342,6 +16369,7 @@ class Animate:
|
|
16342
16369
|
alpha1=None,
|
16343
16370
|
fontsize1=None,
|
16344
16371
|
width1=None,
|
16372
|
+
height1=None,
|
16345
16373
|
flip_horizontal=None,
|
16346
16374
|
flip_vertical=None,
|
16347
16375
|
animation_start=None,
|
@@ -16494,6 +16522,11 @@ class Animate:
|
|
16494
16522
|
|
16495
16523
|
if None, the original width of the image will be used
|
16496
16524
|
|
16525
|
+
height0 : float
|
16526
|
+
height of the image to be displayed at time t0 (default see below)
|
16527
|
+
|
16528
|
+
if None, the original height of the image will be used
|
16529
|
+
|
16497
16530
|
t1 : float
|
16498
16531
|
time of end of the animation (default: inf)
|
16499
16532
|
|
@@ -16560,6 +16593,8 @@ class Animate:
|
|
16560
16593
|
width1 : float
|
16561
16594
|
width of the image to be displayed at time t1 (default: width0)
|
16562
16595
|
|
16596
|
+
height1 : float
|
16597
|
+
height of the image to be displayed at time t1 (default: height0)
|
16563
16598
|
|
16564
16599
|
Note
|
16565
16600
|
----
|
@@ -16595,6 +16630,8 @@ class Animate:
|
|
16595
16630
|
self.max_lines0 = max_lines
|
16596
16631
|
|
16597
16632
|
self.width0 = self.width() if width0 is None else width0
|
16633
|
+
self.height0 = self.height() if height0 is None else height0
|
16634
|
+
|
16598
16635
|
if image is not None:
|
16599
16636
|
self.image0 = image
|
16600
16637
|
|
@@ -16641,6 +16678,7 @@ class Animate:
|
|
16641
16678
|
self.alpha1 = self.alpha0 if alpha1 is None else alpha1
|
16642
16679
|
self.fontsize1 = self.fontsize0 if fontsize1 is None else fontsize1
|
16643
16680
|
self.width1 = self.width0 if width1 is None else width1
|
16681
|
+
self.height1 = self.height0 if height1 is None else height1
|
16644
16682
|
self.xy_anchor1 = self.xy_anchor0 if xy_anchor1 is None else xy_anchor1
|
16645
16683
|
|
16646
16684
|
self.t1 = inf if t1 is None else t1
|
@@ -16938,7 +16976,7 @@ class Animate:
|
|
16938
16976
|
|
16939
16977
|
def width(self, t=None):
|
16940
16978
|
"""
|
16941
|
-
width
|
16979
|
+
width of an animated image object. May be overridden.
|
16942
16980
|
|
16943
16981
|
Parameters
|
16944
16982
|
----------
|
@@ -16963,6 +17001,33 @@ class Animate:
|
|
16963
17001
|
|
16964
17002
|
return interpolate((self.env._now if t is None else t), self.t0, self.t1, width0, width1)
|
16965
17003
|
|
17004
|
+
def height(self, t=None):
|
17005
|
+
"""
|
17006
|
+
height of an animated image object. May be overridden.
|
17007
|
+
|
17008
|
+
Parameters
|
17009
|
+
----------
|
17010
|
+
t : float
|
17011
|
+
current time
|
17012
|
+
|
17013
|
+
Returns
|
17014
|
+
-------
|
17015
|
+
height : float
|
17016
|
+
default behaviour: linear interpolation between self.height0 and self.height1
|
17017
|
+
|
17018
|
+
if None, the original height of the image will be used
|
17019
|
+
"""
|
17020
|
+
height0 = self.height0
|
17021
|
+
height1 = self.height1
|
17022
|
+
if height0 is None and height1 is None:
|
17023
|
+
return None
|
17024
|
+
if height0 is None:
|
17025
|
+
height0 = ImageContainer(self.image0).images[0].size[0]
|
17026
|
+
if height1 is None:
|
17027
|
+
height1 = ImageContainer(self.image1).images[0].size[0]
|
17028
|
+
|
17029
|
+
return interpolate((self.env._now if t is None else t), self.t0, self.t1, height0, height1)
|
17030
|
+
|
16966
17031
|
def fontsize(self, t=None):
|
16967
17032
|
"""
|
16968
17033
|
fontsize of an animate object. May be overridden.
|
@@ -19656,6 +19721,8 @@ class AnimateImage(Animate2dBase):
|
|
19656
19721
|
width : float
|
19657
19722
|
width of the image (default: None = no scaling)
|
19658
19723
|
|
19724
|
+
heighth : float
|
19725
|
+
height of the image (default: None = no scaling)
|
19659
19726
|
|
19660
19727
|
text : str, tuple or list
|
19661
19728
|
the text to be displayed
|
@@ -19791,6 +19858,7 @@ class AnimateImage(Animate2dBase):
|
|
19791
19858
|
x: Union[float, Callable] = None,
|
19792
19859
|
y: Union[float, Callable] = None,
|
19793
19860
|
width: Union[float, Callable] = None,
|
19861
|
+
height: Union[float, Callable] = None,
|
19794
19862
|
text: Union[str, Callable] = None,
|
19795
19863
|
fontsize: Union[float, Callable] = None,
|
19796
19864
|
textcolor: Union[ColorType, Callable] = None,
|
@@ -19833,6 +19901,7 @@ class AnimateImage(Animate2dBase):
|
|
19833
19901
|
x=0,
|
19834
19902
|
y=0,
|
19835
19903
|
width=None,
|
19904
|
+
height=None,
|
19836
19905
|
text="",
|
19837
19906
|
fontsize=15,
|
19838
19907
|
textcolor="bg",
|
@@ -19915,10 +19984,10 @@ class ComponentGenerator(Component):
|
|
19915
19984
|
|
19916
19985
|
Parameters
|
19917
19986
|
----------
|
19918
|
-
component_class : callable, usually a subclass of Component or Pdf or Cdf distribution
|
19987
|
+
component_class : callable, usually a subclass of Component or Pdf/Pmf or Cdf distribution
|
19919
19988
|
the type of components to be generated
|
19920
19989
|
|
19921
|
-
in case of a distribution, the Pdf or Cdf should return a callable
|
19990
|
+
in case of a distribution, the Pdf/Pmf or Cdf should return a callable
|
19922
19991
|
|
19923
19992
|
generator_name : str
|
19924
19993
|
name of the component generator.
|
@@ -20478,7 +20547,7 @@ class _Distribution:
|
|
20478
20547
|
If, after number_of_tries retries, the sampled value is still not within the given bounds,
|
20479
20548
|
fail_value will be returned
|
20480
20549
|
|
20481
|
-
Samples that cannot be converted (only possible with
|
20550
|
+
Samples that cannot be converted (only possible with /Pmf and CumPdf/CumPmf) to float
|
20482
20551
|
are assumed to be within the bounds.
|
20483
20552
|
"""
|
20484
20553
|
return Bounded(self, lowerbound, upperbound, fail_value, number_of_retries, include_lowerbound, include_upperbound).sample()
|
@@ -20718,7 +20787,7 @@ class Bounded(_Distribution):
|
|
20718
20787
|
If, after number_of_tries retries, the sampled value is still not within the given bounds,
|
20719
20788
|
fail_value will be returned
|
20720
20789
|
|
20721
|
-
Samples that cannot be converted to float (only possible with Pdf and CumPdf)
|
20790
|
+
Samples that cannot be converted to float (only possible with Pdf/Pmf and CumPdf)
|
20722
20791
|
are assumed to be within the bounds.
|
20723
20792
|
"""
|
20724
20793
|
|
@@ -22214,6 +22283,9 @@ class Pdf(_Distribution):
|
|
22214
22283
|
|
22215
22284
|
If it is a salabim distribution, not the distribution,
|
22216
22285
|
but a sample will be returned when calling sample.
|
22286
|
+
|
22287
|
+
|
22288
|
+
This method is also available under the name Pmf
|
22217
22289
|
"""
|
22218
22290
|
|
22219
22291
|
def __init__(self, spec: Union[Iterable, Dict], probabilities=None, time_unit: str = None, randomstream: Any = None, env: "Environment" = None):
|
@@ -22358,9 +22430,151 @@ class Pdf(_Distribution):
|
|
22358
22430
|
return self._mean
|
22359
22431
|
|
22360
22432
|
|
22433
|
+
class Pmf(Pdf):
|
22434
|
+
"""
|
22435
|
+
Probability mass function
|
22436
|
+
|
22437
|
+
Parameters
|
22438
|
+
----------
|
22439
|
+
spec : list, tuple or dict
|
22440
|
+
either
|
22441
|
+
|
22442
|
+
- if no probabilities specified:
|
22443
|
+
|
22444
|
+
list/tuple with x-values and corresponding probability
|
22445
|
+
dict where the keys are re x-values and the values are probabilities
|
22446
|
+
(x0, p0, x1, p1, ...xn,pn)
|
22447
|
+
|
22448
|
+
- if probabilities is specified:
|
22449
|
+
|
22450
|
+
list with x-values
|
22451
|
+
|
22452
|
+
probabilities : iterable or float
|
22453
|
+
if omitted, spec contains the probabilities
|
22454
|
+
|
22455
|
+
the iterable (p0, p1, ...pn) contains the probabilities of the corresponding
|
22456
|
+
x-values from spec.
|
22457
|
+
|
22458
|
+
alternatively, if a float is given (e.g. 1), all x-values
|
22459
|
+
have equal probability. The value is not important.
|
22460
|
+
|
22461
|
+
time_unit : str
|
22462
|
+
specifies the time unit
|
22463
|
+
|
22464
|
+
must be one of "years", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds"
|
22465
|
+
|
22466
|
+
default : no conversion
|
22467
|
+
|
22468
|
+
|
22469
|
+
randomstream : randomstream
|
22470
|
+
if omitted, random will be used
|
22471
|
+
|
22472
|
+
if used as random.Random(12299)
|
22473
|
+
it assigns a new stream with the specified seed
|
22474
|
+
|
22475
|
+
env : Environment
|
22476
|
+
environment where the distribution is defined
|
22477
|
+
|
22478
|
+
if omitted, default_env will be used
|
22479
|
+
|
22480
|
+
Note
|
22481
|
+
----
|
22482
|
+
p0+p1=...+pn>0
|
22483
|
+
|
22484
|
+
all densities are auto scaled according to the sum of p0 to pn,
|
22485
|
+
so no need to have p0 to pn add up to 1 or 100.
|
22486
|
+
|
22487
|
+
The x-values can be any type.
|
22488
|
+
|
22489
|
+
If it is a salabim distribution, not the distribution,
|
22490
|
+
but a sample will be returned when calling sample.
|
22491
|
+
|
22492
|
+
This method is also available under the name Pdf
|
22493
|
+
|
22494
|
+
"""
|
22495
|
+
|
22496
|
+
def __repr__(self):
|
22497
|
+
return "Pmf"
|
22498
|
+
|
22499
|
+
def print_info(self, as_str: bool = False, file: TextIO = None) -> str:
|
22500
|
+
"""
|
22501
|
+
prints information about the distribution
|
22502
|
+
|
22503
|
+
Parameters
|
22504
|
+
----------
|
22505
|
+
as_str: bool
|
22506
|
+
if False (default), print the info
|
22507
|
+
if True, return a string containing the info
|
22508
|
+
|
22509
|
+
file: file
|
22510
|
+
if None(default), all output is directed to stdout
|
22511
|
+
|
22512
|
+
otherwise, the output is directed to the file
|
22513
|
+
|
22514
|
+
Returns
|
22515
|
+
-------
|
22516
|
+
info (if as_str is True) : str
|
22517
|
+
"""
|
22518
|
+
result = []
|
22519
|
+
result.append("Pmf distribution " + hex(id(self)))
|
22520
|
+
result.append(" randomstream=" + hex(id(self.randomstream)))
|
22521
|
+
return return_or_print(result, as_str, file)
|
22522
|
+
|
22523
|
+
def sample(self, n: int = None) -> Any:
|
22524
|
+
"""
|
22525
|
+
Parameters
|
22526
|
+
----------
|
22527
|
+
n : number of samples : int
|
22528
|
+
if not specified, specifies just return one sample, as usual
|
22529
|
+
|
22530
|
+
if specified, return a list of n sampled values from the distribution without replacement.
|
22531
|
+
This requires that all probabilities are equal.
|
22532
|
+
|
22533
|
+
If n > number of values in the Pmf distribution, n is assumed to be the number of values
|
22534
|
+
in the distribution.
|
22535
|
+
|
22536
|
+
If a sampled value is a distribution, a sample from that distribution will be returned.
|
22537
|
+
|
22538
|
+
Returns
|
22539
|
+
-------
|
22540
|
+
Sample of the distribution : any (usually float) or list
|
22541
|
+
In case n is specified, returns a list of n values
|
22542
|
+
|
22543
|
+
"""
|
22544
|
+
if self.supports_n:
|
22545
|
+
if n is None:
|
22546
|
+
return self.randomstream.sample(self._x, 1)[0]
|
22547
|
+
else:
|
22548
|
+
if n < 0:
|
22549
|
+
raise ValueError("n < 0")
|
22550
|
+
n = min(n, len(self._x))
|
22551
|
+
xs = self.randomstream.sample(self._x, n)
|
22552
|
+
return [x.sample() if isinstance(x, _Distribution) else x for x in xs]
|
22553
|
+
else:
|
22554
|
+
if n is None:
|
22555
|
+
r = self.randomstream.random()
|
22556
|
+
for cum, x in zip([0] + self._cum, [0] + self._x):
|
22557
|
+
if r <= cum:
|
22558
|
+
if isinstance(x, _Distribution):
|
22559
|
+
return x.sample()
|
22560
|
+
return x
|
22561
|
+
else:
|
22562
|
+
raise ValueError("not all probabilities are the same")
|
22563
|
+
|
22564
|
+
def mean(self) -> float:
|
22565
|
+
"""
|
22566
|
+
Returns
|
22567
|
+
-------
|
22568
|
+
mean of the distribution : float
|
22569
|
+
if the mean can't be calculated (if not all x-values are scalars or distributions),
|
22570
|
+
nan will be returned.
|
22571
|
+
"""
|
22572
|
+
return self._mean
|
22573
|
+
|
22574
|
+
|
22361
22575
|
class CumPdf(_Distribution):
|
22362
22576
|
"""
|
22363
|
-
Cumulative Probability
|
22577
|
+
Cumulative Probability mass function
|
22364
22578
|
|
22365
22579
|
Parameters
|
22366
22580
|
----------
|
@@ -22413,6 +22627,8 @@ class CumPdf(_Distribution):
|
|
22413
22627
|
|
22414
22628
|
If it is a salabim distribution, not the distribution,
|
22415
22629
|
but a sample will be returned when calling sample.
|
22630
|
+
|
22631
|
+
This method is also available under the name CumPmf
|
22416
22632
|
"""
|
22417
22633
|
|
22418
22634
|
def __init__(
|
@@ -22528,6 +22744,116 @@ class CumPdf(_Distribution):
|
|
22528
22744
|
return self._mean
|
22529
22745
|
|
22530
22746
|
|
22747
|
+
class CumPmf(CumPdf):
|
22748
|
+
"""
|
22749
|
+
Cumulative Probability mass function
|
22750
|
+
|
22751
|
+
Parameters
|
22752
|
+
----------
|
22753
|
+
spec : list or tuple
|
22754
|
+
either
|
22755
|
+
|
22756
|
+
- if no cumprobabilities specified:
|
22757
|
+
|
22758
|
+
list with x-values and corresponding cumulative probability
|
22759
|
+
(x0, p0, x1, p1, ...xn,pn)
|
22760
|
+
|
22761
|
+
- if cumprobabilities is specified:
|
22762
|
+
|
22763
|
+
list with x-values
|
22764
|
+
|
22765
|
+
cumprobabilities : list, tuple or float
|
22766
|
+
if omitted, spec contains the probabilities
|
22767
|
+
|
22768
|
+
the list (p0, p1, ...pn) contains the cumulative probabilities of the corresponding
|
22769
|
+
x-values from spec.
|
22770
|
+
|
22771
|
+
|
22772
|
+
time_unit : str
|
22773
|
+
specifies the time unit
|
22774
|
+
|
22775
|
+
must be one of "years", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds"
|
22776
|
+
|
22777
|
+
default : no conversion
|
22778
|
+
|
22779
|
+
|
22780
|
+
randomstream : randomstream
|
22781
|
+
if omitted, random will be used
|
22782
|
+
|
22783
|
+
if used as random.Random(12299)
|
22784
|
+
it assigns a new stream with the specified seed
|
22785
|
+
|
22786
|
+
env : Environment
|
22787
|
+
environment where the distribution is defined
|
22788
|
+
|
22789
|
+
if omitted, default_env will be used
|
22790
|
+
|
22791
|
+
Note
|
22792
|
+
----
|
22793
|
+
p0<=p1<=..pn>0
|
22794
|
+
|
22795
|
+
all densities are auto scaled according to pn,
|
22796
|
+
so no need to have pn be 1 or 100.
|
22797
|
+
|
22798
|
+
The x-values can be any type.
|
22799
|
+
|
22800
|
+
If it is a salabim distribution, not the distribution,
|
22801
|
+
but a sample will be returned when calling sample.
|
22802
|
+
|
22803
|
+
This method is also available under the name CumPdf
|
22804
|
+
"""
|
22805
|
+
|
22806
|
+
def __repr__(self):
|
22807
|
+
return "CumPmf"
|
22808
|
+
|
22809
|
+
def print_info(self, as_str: bool = False, file: TextIO = None) -> str:
|
22810
|
+
"""
|
22811
|
+
prints information about the distribution
|
22812
|
+
|
22813
|
+
Parameters
|
22814
|
+
----------
|
22815
|
+
as_str: bool
|
22816
|
+
if False (default), print the info
|
22817
|
+
if True, return a string containing the info
|
22818
|
+
|
22819
|
+
file: file
|
22820
|
+
if None(default), all output is directed to stdout
|
22821
|
+
|
22822
|
+
otherwise, the output is directed to the file
|
22823
|
+
|
22824
|
+
Returns
|
22825
|
+
-------
|
22826
|
+
info (if as_str is True) : str
|
22827
|
+
"""
|
22828
|
+
result = []
|
22829
|
+
result.append("CumPmf distribution " + hex(id(self)))
|
22830
|
+
result.append(" randomstream=" + hex(id(self.randomstream)))
|
22831
|
+
return return_or_print(result, as_str, file)
|
22832
|
+
|
22833
|
+
def sample(self) -> Any:
|
22834
|
+
"""
|
22835
|
+
Returns
|
22836
|
+
-------
|
22837
|
+
Sample of the distribution : any (usually float)
|
22838
|
+
"""
|
22839
|
+
r = self.randomstream.random()
|
22840
|
+
for cum, x in zip([0] + self._cum, [0] + self._x):
|
22841
|
+
if r <= cum:
|
22842
|
+
if isinstance(x, _Distribution):
|
22843
|
+
return x.sample()
|
22844
|
+
return x
|
22845
|
+
|
22846
|
+
def mean(self) -> float:
|
22847
|
+
"""
|
22848
|
+
Returns
|
22849
|
+
-------
|
22850
|
+
mean of the distribution : float
|
22851
|
+
if the mean can't be calculated (if not all x-values are scalars or distributions),
|
22852
|
+
nan will be returned.
|
22853
|
+
"""
|
22854
|
+
return self._mean
|
22855
|
+
|
22856
|
+
|
22531
22857
|
class External(_Distribution):
|
22532
22858
|
"""
|
22533
22859
|
External distribution function
|
@@ -24127,7 +24453,7 @@ class _APNG:
|
|
24127
24453
|
|
24128
24454
|
def to_bytes(self):
|
24129
24455
|
CHUNK_BEFORE_IDAT = {"cHRM", "gAMA", "iCCP", "sBIT", "sRGB", "bKGD", "hIST", "tRNS", "pHYs", "sPLT", "tIME", "PLTE"}
|
24130
|
-
PNG_SIGN = b"\x89\x50\
|
24456
|
+
PNG_SIGN = b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
|
24131
24457
|
out = [PNG_SIGN]
|
24132
24458
|
other_chunks = []
|
24133
24459
|
seq = 0
|
@@ -26601,8 +26927,8 @@ def getfont(fontname, fontsize):
|
|
26601
26927
|
return getfont.lookup[(fontname, fontsize)]
|
26602
26928
|
else:
|
26603
26929
|
getfont.lookup = {}
|
26604
|
-
if fontname=="":
|
26605
|
-
a=1
|
26930
|
+
if fontname == "":
|
26931
|
+
a = 1
|
26606
26932
|
if isinstance(fontname, str):
|
26607
26933
|
fontlist1 = [fontname]
|
26608
26934
|
else:
|
@@ -1,7 +1,16 @@
|
|
1
|
-
import salabim as sim
|
2
1
|
import pytest
|
3
2
|
import collections
|
3
|
+
from pathlib import Path
|
4
|
+
import os
|
5
|
+
import sys
|
4
6
|
|
7
|
+
if __name__ == "__main__":
|
8
|
+
file_folder = Path(__file__).parent
|
9
|
+
top_folder = (file_folder / "..").resolve()
|
10
|
+
sys.path.insert(0, str(top_folder))
|
11
|
+
os.chdir(file_folder)
|
12
|
+
|
13
|
+
import salabim as sim
|
5
14
|
|
6
15
|
def collect(dis, n=10000):
|
7
16
|
m = sim.Monitor()
|
@@ -85,11 +94,13 @@ def test_int_uniform():
|
|
85
94
|
assert set(m.x()) == {1, 2, 3, 4, 5, 6}
|
86
95
|
count = collections.Counter(m.x())
|
87
96
|
for v, n in count.items():
|
88
|
-
assert n == pytest.approx(10000 / 6, rel=
|
97
|
+
assert n == pytest.approx(10000 / 6, rel=10)
|
89
98
|
|
90
99
|
|
91
100
|
def test_pdf():
|
92
101
|
env = sim.Environment()
|
102
|
+
d=sim.Pdf((1,10,2,70,3,20))
|
103
|
+
assert str(d)=="Pdf"
|
93
104
|
m = collect(sim.Pdf((1,10,2,70,3,20)))
|
94
105
|
assert m.mean() == pytest.approx(2.1, rel=1e-2)
|
95
106
|
m = collect(sim.Pdf((1,2,3),(10,70,20)))
|
@@ -100,6 +111,36 @@ def test_pdf():
|
|
100
111
|
m = collect(sim.Pdf(d))
|
101
112
|
assert m.mean() == pytest.approx(2.1, rel=1e-2)
|
102
113
|
|
114
|
+
|
115
|
+
def test_pmf():
|
116
|
+
env = sim.Environment()
|
117
|
+
d=sim.Pmf((1,10,2,70,3,20))
|
118
|
+
assert str(d)=="Pmf"
|
119
|
+
m = collect(sim.Pmf((1,10,2,70,3,20)))
|
120
|
+
assert m.mean() == pytest.approx(2.1, rel=1e-2)
|
121
|
+
m = collect(sim.Pmf((1,2,3),(10,70,20)))
|
122
|
+
assert m.mean() == pytest.approx(2.1, rel=1e-2)
|
123
|
+
d = {1:10, 2:70, 3:20}
|
124
|
+
m = collect(sim.Pmf(d.keys(),d.values()))
|
125
|
+
assert m.mean() == pytest.approx(2.1, rel=1e-2)
|
126
|
+
m = collect(sim.Pmf(d))
|
127
|
+
assert m.mean() == pytest.approx(2.1, rel=1e-2)
|
128
|
+
|
129
|
+
def test_cumpdf():
|
130
|
+
env = sim.Environment()
|
131
|
+
d=sim.CumPdf((1, 10, 2, 80, 3,100))
|
132
|
+
assert str(d)=="CumPdf"
|
133
|
+
m = collect(d)
|
134
|
+
assert m.mean() == pytest.approx(2, rel=1e-1)
|
135
|
+
|
136
|
+
def test_cumpmf():
|
137
|
+
env = sim.Environment()
|
138
|
+
d=sim.CumPmf((1, 10, 2, 80, 3,100))
|
139
|
+
assert str(d)=="CumPmf"
|
140
|
+
m = collect(d)
|
141
|
+
assert m.mean() == pytest.approx(2, rel=1e-1)
|
142
|
+
|
143
|
+
|
103
144
|
def test_scipy_distribution():
|
104
145
|
try:
|
105
146
|
import scipy.stats as st
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|