salabim 24.0.13__py3-none-any.whl → 24.0.14.post4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- salabim/salabim.py +404 -35
- {salabim-24.0.13.dist-info → salabim-24.0.14.post4.dist-info}/METADATA +2 -2
- salabim-24.0.14.post4.dist-info/RECORD +10 -0
- {salabim-24.0.13.dist-info → salabim-24.0.14.post4.dist-info}/WHEEL +1 -1
- salabim-24.0.13.dist-info/RECORD +0 -10
- {salabim-24.0.13.dist-info → salabim-24.0.14.post4.dist-info}/top_level.txt +0 -0
salabim/salabim.py
CHANGED
@@ -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,7 @@ 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])), ao._image)
|
11806
|
+
image.paste(ao._image, (int(ao._image_x), int(self._height - ao._image_y - ao._image.size[1])), ao._image.convert("RGBA"))
|
11808
11807
|
|
11809
11808
|
return image.convert(mode)
|
11810
11809
|
|
@@ -12779,6 +12778,31 @@ class Environment:
|
|
12779
12778
|
self.animation_parameters(synced=value, animate=None)
|
12780
12779
|
return self._synced
|
12781
12780
|
|
12781
|
+
def minimized(self, value: bool=None)-> bool:
|
12782
|
+
"""
|
12783
|
+
minimized
|
12784
|
+
|
12785
|
+
Parameters
|
12786
|
+
----------
|
12787
|
+
value : bool
|
12788
|
+
if True, minimize the curent animation window
|
12789
|
+
|
12790
|
+
if False, (re)show the current animation window
|
12791
|
+
|
12792
|
+
if None (default): no action
|
12793
|
+
|
12794
|
+
Returns
|
12795
|
+
-------
|
12796
|
+
current state of the animation window : bool
|
12797
|
+
True if current animation windows is minimized, False otherwise
|
12798
|
+
"""
|
12799
|
+
if value is not None:
|
12800
|
+
if value:
|
12801
|
+
self.root.withdraw()
|
12802
|
+
else:
|
12803
|
+
self.root.deiconify()
|
12804
|
+
return not bool(self.root.winfo_viewable())
|
12805
|
+
|
12782
12806
|
def speed(self, value: float = None) -> float:
|
12783
12807
|
"""
|
12784
12808
|
speed
|
@@ -13201,7 +13225,7 @@ class Environment:
|
|
13201
13225
|
if co is None:
|
13202
13226
|
if len(g.canvas_objects) >= self._maximum_number_of_bitmaps:
|
13203
13227
|
if overflow_image is None:
|
13204
|
-
overflow_image = Image.new("RGBA", (self._width, self._height), (0, 0, 0, 0))
|
13228
|
+
overflow_image = Image.new("RGBA", (int(self._width), int(self._height)), (0, 0, 0, 0))
|
13205
13229
|
overflow_image.paste(ao._image, (int(ao._image_x), int(self._height - ao._image_y - ao._image.size[1])), ao._image)
|
13206
13230
|
ao.canvas_object = None
|
13207
13231
|
else:
|
@@ -15426,10 +15450,20 @@ class Animate2dBase(DynamicClass):
|
|
15426
15450
|
spec = self.image(t)
|
15427
15451
|
image_container = ImageContainer(spec)
|
15428
15452
|
width = self.width(t)
|
15453
|
+
height = self.height(t)
|
15454
|
+
|
15429
15455
|
if width is None:
|
15430
|
-
|
15456
|
+
if height is None:
|
15457
|
+
width = image_container.images[0].size[0]
|
15458
|
+
height = image_container.images[0].size[1]
|
15459
|
+
else:
|
15460
|
+
width = height * image_container.images[0].size[0] / image_container.images[0].size[1]
|
15461
|
+
else:
|
15462
|
+
if height is None:
|
15463
|
+
height = width * image_container.images[0].size[1] / image_container.images[0].size[0]
|
15464
|
+
else:
|
15465
|
+
...
|
15431
15466
|
|
15432
|
-
height = width * image_container.images[0].size[1] / image_container.images[0].size[0]
|
15433
15467
|
if not self.screen_coordinates:
|
15434
15468
|
width *= self.env._scale
|
15435
15469
|
height *= self.env._scale
|
@@ -15448,7 +15482,6 @@ class Animate2dBase(DynamicClass):
|
|
15448
15482
|
offsety = offsety * self.env._scale
|
15449
15483
|
|
15450
15484
|
alpha = int(self.alpha(t))
|
15451
|
-
|
15452
15485
|
image, id = image_container.get_image(
|
15453
15486
|
(t - self.animation_start(t)) * self.animation_speed(t),
|
15454
15487
|
repeat=self.animation_repeat(t),
|
@@ -15456,6 +15489,7 @@ class Animate2dBase(DynamicClass):
|
|
15456
15489
|
t_from=self.animation_from(t),
|
15457
15490
|
t_to=self.animation_to(t),
|
15458
15491
|
)
|
15492
|
+
|
15459
15493
|
self._image_ident = (spec, id, width, height, angle, alpha, flip_horizontal, flip_vertical)
|
15460
15494
|
|
15461
15495
|
if self._image_ident != self._image_ident_prev:
|
@@ -15736,6 +15770,9 @@ class AnimateClassic(Animate2dBase):
|
|
15736
15770
|
def width(self, t):
|
15737
15771
|
return self.master.width(t)
|
15738
15772
|
|
15773
|
+
def height(self, t):
|
15774
|
+
return self.master.height(t)
|
15775
|
+
|
15739
15776
|
def anchor(self, t):
|
15740
15777
|
return self.master.anchor(t)
|
15741
15778
|
|
@@ -15963,6 +16000,11 @@ class Animate:
|
|
15963
16000
|
|
15964
16001
|
if omitted or None, no scaling
|
15965
16002
|
|
16003
|
+
height0 : float
|
16004
|
+
width of the image to be displayed at time t0
|
16005
|
+
|
16006
|
+
if omitted or None, no scaling
|
16007
|
+
|
15966
16008
|
t1 : float
|
15967
16009
|
time of end of the animation (default inf)
|
15968
16010
|
|
@@ -16031,6 +16073,9 @@ class Animate:
|
|
16031
16073
|
width1 : float
|
16032
16074
|
width of the image to be displayed at time t1 (default: width0)
|
16033
16075
|
|
16076
|
+
height1 : float
|
16077
|
+
width of the image to be displayed at time t1 (default: height0)
|
16078
|
+
|
16034
16079
|
over3d : bool
|
16035
16080
|
if True, this object will be rendered to the OpenGL window
|
16036
16081
|
|
@@ -16099,6 +16144,7 @@ class Animate:
|
|
16099
16144
|
font -
|
16100
16145
|
fontsize0,fontsize1 -
|
16101
16146
|
width0,width1 -
|
16147
|
+
height0,height1 -
|
16102
16148
|
====================== ========= ========= ========= ========= ========= =========
|
16103
16149
|
"""
|
16104
16150
|
|
@@ -16134,6 +16180,7 @@ class Animate:
|
|
16134
16180
|
alpha0: float = 255,
|
16135
16181
|
fontsize0: float = 20,
|
16136
16182
|
width0: float = None,
|
16183
|
+
height0: float = None,
|
16137
16184
|
t1: float = None,
|
16138
16185
|
x1: float = None,
|
16139
16186
|
y1: float = None,
|
@@ -16152,6 +16199,7 @@ class Animate:
|
|
16152
16199
|
alpha1: float = None,
|
16153
16200
|
fontsize1: float = None,
|
16154
16201
|
width1: float = None,
|
16202
|
+
height1: float = None,
|
16155
16203
|
xy_anchor: str = "",
|
16156
16204
|
over3d: bool = None,
|
16157
16205
|
flip_horizontal: bool = False,
|
@@ -16198,10 +16246,12 @@ class Animate:
|
|
16198
16246
|
self.text0 = text
|
16199
16247
|
|
16200
16248
|
if image is None:
|
16201
|
-
self.width0 = 0 # just to be able to
|
16249
|
+
self.width0 = 0 # just to be able to interpolat
|
16250
|
+
self.height0 = 0
|
16202
16251
|
else:
|
16203
16252
|
self.image0 = image
|
16204
16253
|
self.width0 = width0 # None means original size
|
16254
|
+
self.height0 = height0
|
16205
16255
|
|
16206
16256
|
self.as_points0 = as_points
|
16207
16257
|
self.font0 = font
|
@@ -16263,7 +16313,7 @@ class Animate:
|
|
16263
16313
|
self.alpha1 = self.alpha0 if alpha1 is None else alpha1
|
16264
16314
|
self.fontsize1 = self.fontsize0 if fontsize1 is None else fontsize1
|
16265
16315
|
self.width1 = self.width0 if width1 is None else width1
|
16266
|
-
|
16316
|
+
self.height1 = self.height0 if height1 is None else height1
|
16267
16317
|
self.t1 = inf if t1 is None else t1
|
16268
16318
|
if self.env._animate_debug:
|
16269
16319
|
self.caller = self.env._frame_to_lineno(_get_caller_frame(), add_filename=True)
|
@@ -16322,6 +16372,7 @@ class Animate:
|
|
16322
16372
|
alpha0=None,
|
16323
16373
|
fontsize0=None,
|
16324
16374
|
width0=None,
|
16375
|
+
height0=None,
|
16325
16376
|
xy_anchor1=None,
|
16326
16377
|
as_points=None,
|
16327
16378
|
t1=None,
|
@@ -16342,6 +16393,7 @@ class Animate:
|
|
16342
16393
|
alpha1=None,
|
16343
16394
|
fontsize1=None,
|
16344
16395
|
width1=None,
|
16396
|
+
height1=None,
|
16345
16397
|
flip_horizontal=None,
|
16346
16398
|
flip_vertical=None,
|
16347
16399
|
animation_start=None,
|
@@ -16494,6 +16546,11 @@ class Animate:
|
|
16494
16546
|
|
16495
16547
|
if None, the original width of the image will be used
|
16496
16548
|
|
16549
|
+
height0 : float
|
16550
|
+
height of the image to be displayed at time t0 (default see below)
|
16551
|
+
|
16552
|
+
if None, the original height of the image will be used
|
16553
|
+
|
16497
16554
|
t1 : float
|
16498
16555
|
time of end of the animation (default: inf)
|
16499
16556
|
|
@@ -16560,6 +16617,8 @@ class Animate:
|
|
16560
16617
|
width1 : float
|
16561
16618
|
width of the image to be displayed at time t1 (default: width0)
|
16562
16619
|
|
16620
|
+
height1 : float
|
16621
|
+
height of the image to be displayed at time t1 (default: height0)
|
16563
16622
|
|
16564
16623
|
Note
|
16565
16624
|
----
|
@@ -16595,6 +16654,8 @@ class Animate:
|
|
16595
16654
|
self.max_lines0 = max_lines
|
16596
16655
|
|
16597
16656
|
self.width0 = self.width() if width0 is None else width0
|
16657
|
+
self.height0 = self.height() if height0 is None else height0
|
16658
|
+
|
16598
16659
|
if image is not None:
|
16599
16660
|
self.image0 = image
|
16600
16661
|
|
@@ -16641,6 +16702,7 @@ class Animate:
|
|
16641
16702
|
self.alpha1 = self.alpha0 if alpha1 is None else alpha1
|
16642
16703
|
self.fontsize1 = self.fontsize0 if fontsize1 is None else fontsize1
|
16643
16704
|
self.width1 = self.width0 if width1 is None else width1
|
16705
|
+
self.height1 = self.height0 if height1 is None else height1
|
16644
16706
|
self.xy_anchor1 = self.xy_anchor0 if xy_anchor1 is None else xy_anchor1
|
16645
16707
|
|
16646
16708
|
self.t1 = inf if t1 is None else t1
|
@@ -16938,7 +17000,7 @@ class Animate:
|
|
16938
17000
|
|
16939
17001
|
def width(self, t=None):
|
16940
17002
|
"""
|
16941
|
-
width
|
17003
|
+
width of an animated image object. May be overridden.
|
16942
17004
|
|
16943
17005
|
Parameters
|
16944
17006
|
----------
|
@@ -16963,6 +17025,33 @@ class Animate:
|
|
16963
17025
|
|
16964
17026
|
return interpolate((self.env._now if t is None else t), self.t0, self.t1, width0, width1)
|
16965
17027
|
|
17028
|
+
def height(self, t=None):
|
17029
|
+
"""
|
17030
|
+
height of an animated image object. May be overridden.
|
17031
|
+
|
17032
|
+
Parameters
|
17033
|
+
----------
|
17034
|
+
t : float
|
17035
|
+
current time
|
17036
|
+
|
17037
|
+
Returns
|
17038
|
+
-------
|
17039
|
+
height : float
|
17040
|
+
default behaviour: linear interpolation between self.height0 and self.height1
|
17041
|
+
|
17042
|
+
if None, the original height of the image will be used
|
17043
|
+
"""
|
17044
|
+
height0 = self.height0
|
17045
|
+
height1 = self.height1
|
17046
|
+
if height0 is None and height1 is None:
|
17047
|
+
return None
|
17048
|
+
if height0 is None:
|
17049
|
+
height0 = ImageContainer(self.image0).images[0].size[0]
|
17050
|
+
if height1 is None:
|
17051
|
+
height1 = ImageContainer(self.image1).images[0].size[0]
|
17052
|
+
|
17053
|
+
return interpolate((self.env._now if t is None else t), self.t0, self.t1, height0, height1)
|
17054
|
+
|
16966
17055
|
def fontsize(self, t=None):
|
16967
17056
|
"""
|
16968
17057
|
fontsize of an animate object. May be overridden.
|
@@ -19656,6 +19745,8 @@ class AnimateImage(Animate2dBase):
|
|
19656
19745
|
width : float
|
19657
19746
|
width of the image (default: None = no scaling)
|
19658
19747
|
|
19748
|
+
heighth : float
|
19749
|
+
height of the image (default: None = no scaling)
|
19659
19750
|
|
19660
19751
|
text : str, tuple or list
|
19661
19752
|
the text to be displayed
|
@@ -19791,6 +19882,7 @@ class AnimateImage(Animate2dBase):
|
|
19791
19882
|
x: Union[float, Callable] = None,
|
19792
19883
|
y: Union[float, Callable] = None,
|
19793
19884
|
width: Union[float, Callable] = None,
|
19885
|
+
height: Union[float, Callable] = None,
|
19794
19886
|
text: Union[str, Callable] = None,
|
19795
19887
|
fontsize: Union[float, Callable] = None,
|
19796
19888
|
textcolor: Union[ColorType, Callable] = None,
|
@@ -19833,6 +19925,7 @@ class AnimateImage(Animate2dBase):
|
|
19833
19925
|
x=0,
|
19834
19926
|
y=0,
|
19835
19927
|
width=None,
|
19928
|
+
height=None,
|
19836
19929
|
text="",
|
19837
19930
|
fontsize=15,
|
19838
19931
|
textcolor="bg",
|
@@ -19915,10 +20008,10 @@ class ComponentGenerator(Component):
|
|
19915
20008
|
|
19916
20009
|
Parameters
|
19917
20010
|
----------
|
19918
|
-
component_class : callable, usually a subclass of Component or Pdf or Cdf distribution
|
20011
|
+
component_class : callable, usually a subclass of Component or Pdf/Pmf or Cdf distribution
|
19919
20012
|
the type of components to be generated
|
19920
20013
|
|
19921
|
-
in case of a distribution, the Pdf or Cdf should return a callable
|
20014
|
+
in case of a distribution, the Pdf/Pmf or Cdf should return a callable
|
19922
20015
|
|
19923
20016
|
generator_name : str
|
19924
20017
|
name of the component generator.
|
@@ -20478,7 +20571,7 @@ class _Distribution:
|
|
20478
20571
|
If, after number_of_tries retries, the sampled value is still not within the given bounds,
|
20479
20572
|
fail_value will be returned
|
20480
20573
|
|
20481
|
-
Samples that cannot be converted (only possible with
|
20574
|
+
Samples that cannot be converted (only possible with /Pmf and CumPdf/CumPmf) to float
|
20482
20575
|
are assumed to be within the bounds.
|
20483
20576
|
"""
|
20484
20577
|
return Bounded(self, lowerbound, upperbound, fail_value, number_of_retries, include_lowerbound, include_upperbound).sample()
|
@@ -20718,7 +20811,7 @@ class Bounded(_Distribution):
|
|
20718
20811
|
If, after number_of_tries retries, the sampled value is still not within the given bounds,
|
20719
20812
|
fail_value will be returned
|
20720
20813
|
|
20721
|
-
Samples that cannot be converted to float (only possible with Pdf and CumPdf)
|
20814
|
+
Samples that cannot be converted to float (only possible with Pdf/Pmf and CumPdf)
|
20722
20815
|
are assumed to be within the bounds.
|
20723
20816
|
"""
|
20724
20817
|
|
@@ -22214,6 +22307,9 @@ class Pdf(_Distribution):
|
|
22214
22307
|
|
22215
22308
|
If it is a salabim distribution, not the distribution,
|
22216
22309
|
but a sample will be returned when calling sample.
|
22310
|
+
|
22311
|
+
|
22312
|
+
This method is also available under the name Pmf
|
22217
22313
|
"""
|
22218
22314
|
|
22219
22315
|
def __init__(self, spec: Union[Iterable, Dict], probabilities=None, time_unit: str = None, randomstream: Any = None, env: "Environment" = None):
|
@@ -22358,9 +22454,151 @@ class Pdf(_Distribution):
|
|
22358
22454
|
return self._mean
|
22359
22455
|
|
22360
22456
|
|
22457
|
+
class Pmf(Pdf):
|
22458
|
+
"""
|
22459
|
+
Probability mass function
|
22460
|
+
|
22461
|
+
Parameters
|
22462
|
+
----------
|
22463
|
+
spec : list, tuple or dict
|
22464
|
+
either
|
22465
|
+
|
22466
|
+
- if no probabilities specified:
|
22467
|
+
|
22468
|
+
list/tuple with x-values and corresponding probability
|
22469
|
+
dict where the keys are re x-values and the values are probabilities
|
22470
|
+
(x0, p0, x1, p1, ...xn,pn)
|
22471
|
+
|
22472
|
+
- if probabilities is specified:
|
22473
|
+
|
22474
|
+
list with x-values
|
22475
|
+
|
22476
|
+
probabilities : iterable or float
|
22477
|
+
if omitted, spec contains the probabilities
|
22478
|
+
|
22479
|
+
the iterable (p0, p1, ...pn) contains the probabilities of the corresponding
|
22480
|
+
x-values from spec.
|
22481
|
+
|
22482
|
+
alternatively, if a float is given (e.g. 1), all x-values
|
22483
|
+
have equal probability. The value is not important.
|
22484
|
+
|
22485
|
+
time_unit : str
|
22486
|
+
specifies the time unit
|
22487
|
+
|
22488
|
+
must be one of "years", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds"
|
22489
|
+
|
22490
|
+
default : no conversion
|
22491
|
+
|
22492
|
+
|
22493
|
+
randomstream : randomstream
|
22494
|
+
if omitted, random will be used
|
22495
|
+
|
22496
|
+
if used as random.Random(12299)
|
22497
|
+
it assigns a new stream with the specified seed
|
22498
|
+
|
22499
|
+
env : Environment
|
22500
|
+
environment where the distribution is defined
|
22501
|
+
|
22502
|
+
if omitted, default_env will be used
|
22503
|
+
|
22504
|
+
Note
|
22505
|
+
----
|
22506
|
+
p0+p1=...+pn>0
|
22507
|
+
|
22508
|
+
all densities are auto scaled according to the sum of p0 to pn,
|
22509
|
+
so no need to have p0 to pn add up to 1 or 100.
|
22510
|
+
|
22511
|
+
The x-values can be any type.
|
22512
|
+
|
22513
|
+
If it is a salabim distribution, not the distribution,
|
22514
|
+
but a sample will be returned when calling sample.
|
22515
|
+
|
22516
|
+
This method is also available under the name Pdf
|
22517
|
+
|
22518
|
+
"""
|
22519
|
+
|
22520
|
+
def __repr__(self):
|
22521
|
+
return "Pmf"
|
22522
|
+
|
22523
|
+
def print_info(self, as_str: bool = False, file: TextIO = None) -> str:
|
22524
|
+
"""
|
22525
|
+
prints information about the distribution
|
22526
|
+
|
22527
|
+
Parameters
|
22528
|
+
----------
|
22529
|
+
as_str: bool
|
22530
|
+
if False (default), print the info
|
22531
|
+
if True, return a string containing the info
|
22532
|
+
|
22533
|
+
file: file
|
22534
|
+
if None(default), all output is directed to stdout
|
22535
|
+
|
22536
|
+
otherwise, the output is directed to the file
|
22537
|
+
|
22538
|
+
Returns
|
22539
|
+
-------
|
22540
|
+
info (if as_str is True) : str
|
22541
|
+
"""
|
22542
|
+
result = []
|
22543
|
+
result.append("Pmf distribution " + hex(id(self)))
|
22544
|
+
result.append(" randomstream=" + hex(id(self.randomstream)))
|
22545
|
+
return return_or_print(result, as_str, file)
|
22546
|
+
|
22547
|
+
def sample(self, n: int = None) -> Any:
|
22548
|
+
"""
|
22549
|
+
Parameters
|
22550
|
+
----------
|
22551
|
+
n : number of samples : int
|
22552
|
+
if not specified, specifies just return one sample, as usual
|
22553
|
+
|
22554
|
+
if specified, return a list of n sampled values from the distribution without replacement.
|
22555
|
+
This requires that all probabilities are equal.
|
22556
|
+
|
22557
|
+
If n > number of values in the Pmf distribution, n is assumed to be the number of values
|
22558
|
+
in the distribution.
|
22559
|
+
|
22560
|
+
If a sampled value is a distribution, a sample from that distribution will be returned.
|
22561
|
+
|
22562
|
+
Returns
|
22563
|
+
-------
|
22564
|
+
Sample of the distribution : any (usually float) or list
|
22565
|
+
In case n is specified, returns a list of n values
|
22566
|
+
|
22567
|
+
"""
|
22568
|
+
if self.supports_n:
|
22569
|
+
if n is None:
|
22570
|
+
return self.randomstream.sample(self._x, 1)[0]
|
22571
|
+
else:
|
22572
|
+
if n < 0:
|
22573
|
+
raise ValueError("n < 0")
|
22574
|
+
n = min(n, len(self._x))
|
22575
|
+
xs = self.randomstream.sample(self._x, n)
|
22576
|
+
return [x.sample() if isinstance(x, _Distribution) else x for x in xs]
|
22577
|
+
else:
|
22578
|
+
if n is None:
|
22579
|
+
r = self.randomstream.random()
|
22580
|
+
for cum, x in zip([0] + self._cum, [0] + self._x):
|
22581
|
+
if r <= cum:
|
22582
|
+
if isinstance(x, _Distribution):
|
22583
|
+
return x.sample()
|
22584
|
+
return x
|
22585
|
+
else:
|
22586
|
+
raise ValueError("not all probabilities are the same")
|
22587
|
+
|
22588
|
+
def mean(self) -> float:
|
22589
|
+
"""
|
22590
|
+
Returns
|
22591
|
+
-------
|
22592
|
+
mean of the distribution : float
|
22593
|
+
if the mean can't be calculated (if not all x-values are scalars or distributions),
|
22594
|
+
nan will be returned.
|
22595
|
+
"""
|
22596
|
+
return self._mean
|
22597
|
+
|
22598
|
+
|
22361
22599
|
class CumPdf(_Distribution):
|
22362
22600
|
"""
|
22363
|
-
Cumulative Probability
|
22601
|
+
Cumulative Probability mass function
|
22364
22602
|
|
22365
22603
|
Parameters
|
22366
22604
|
----------
|
@@ -22413,6 +22651,8 @@ class CumPdf(_Distribution):
|
|
22413
22651
|
|
22414
22652
|
If it is a salabim distribution, not the distribution,
|
22415
22653
|
but a sample will be returned when calling sample.
|
22654
|
+
|
22655
|
+
This method is also available under the name CumPmf
|
22416
22656
|
"""
|
22417
22657
|
|
22418
22658
|
def __init__(
|
@@ -22528,6 +22768,116 @@ class CumPdf(_Distribution):
|
|
22528
22768
|
return self._mean
|
22529
22769
|
|
22530
22770
|
|
22771
|
+
class CumPmf(CumPdf):
|
22772
|
+
"""
|
22773
|
+
Cumulative Probability mass function
|
22774
|
+
|
22775
|
+
Parameters
|
22776
|
+
----------
|
22777
|
+
spec : list or tuple
|
22778
|
+
either
|
22779
|
+
|
22780
|
+
- if no cumprobabilities specified:
|
22781
|
+
|
22782
|
+
list with x-values and corresponding cumulative probability
|
22783
|
+
(x0, p0, x1, p1, ...xn,pn)
|
22784
|
+
|
22785
|
+
- if cumprobabilities is specified:
|
22786
|
+
|
22787
|
+
list with x-values
|
22788
|
+
|
22789
|
+
cumprobabilities : list, tuple or float
|
22790
|
+
if omitted, spec contains the probabilities
|
22791
|
+
|
22792
|
+
the list (p0, p1, ...pn) contains the cumulative probabilities of the corresponding
|
22793
|
+
x-values from spec.
|
22794
|
+
|
22795
|
+
|
22796
|
+
time_unit : str
|
22797
|
+
specifies the time unit
|
22798
|
+
|
22799
|
+
must be one of "years", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds"
|
22800
|
+
|
22801
|
+
default : no conversion
|
22802
|
+
|
22803
|
+
|
22804
|
+
randomstream : randomstream
|
22805
|
+
if omitted, random will be used
|
22806
|
+
|
22807
|
+
if used as random.Random(12299)
|
22808
|
+
it assigns a new stream with the specified seed
|
22809
|
+
|
22810
|
+
env : Environment
|
22811
|
+
environment where the distribution is defined
|
22812
|
+
|
22813
|
+
if omitted, default_env will be used
|
22814
|
+
|
22815
|
+
Note
|
22816
|
+
----
|
22817
|
+
p0<=p1<=..pn>0
|
22818
|
+
|
22819
|
+
all densities are auto scaled according to pn,
|
22820
|
+
so no need to have pn be 1 or 100.
|
22821
|
+
|
22822
|
+
The x-values can be any type.
|
22823
|
+
|
22824
|
+
If it is a salabim distribution, not the distribution,
|
22825
|
+
but a sample will be returned when calling sample.
|
22826
|
+
|
22827
|
+
This method is also available under the name CumPdf
|
22828
|
+
"""
|
22829
|
+
|
22830
|
+
def __repr__(self):
|
22831
|
+
return "CumPmf"
|
22832
|
+
|
22833
|
+
def print_info(self, as_str: bool = False, file: TextIO = None) -> str:
|
22834
|
+
"""
|
22835
|
+
prints information about the distribution
|
22836
|
+
|
22837
|
+
Parameters
|
22838
|
+
----------
|
22839
|
+
as_str: bool
|
22840
|
+
if False (default), print the info
|
22841
|
+
if True, return a string containing the info
|
22842
|
+
|
22843
|
+
file: file
|
22844
|
+
if None(default), all output is directed to stdout
|
22845
|
+
|
22846
|
+
otherwise, the output is directed to the file
|
22847
|
+
|
22848
|
+
Returns
|
22849
|
+
-------
|
22850
|
+
info (if as_str is True) : str
|
22851
|
+
"""
|
22852
|
+
result = []
|
22853
|
+
result.append("CumPmf distribution " + hex(id(self)))
|
22854
|
+
result.append(" randomstream=" + hex(id(self.randomstream)))
|
22855
|
+
return return_or_print(result, as_str, file)
|
22856
|
+
|
22857
|
+
def sample(self) -> Any:
|
22858
|
+
"""
|
22859
|
+
Returns
|
22860
|
+
-------
|
22861
|
+
Sample of the distribution : any (usually float)
|
22862
|
+
"""
|
22863
|
+
r = self.randomstream.random()
|
22864
|
+
for cum, x in zip([0] + self._cum, [0] + self._x):
|
22865
|
+
if r <= cum:
|
22866
|
+
if isinstance(x, _Distribution):
|
22867
|
+
return x.sample()
|
22868
|
+
return x
|
22869
|
+
|
22870
|
+
def mean(self) -> float:
|
22871
|
+
"""
|
22872
|
+
Returns
|
22873
|
+
-------
|
22874
|
+
mean of the distribution : float
|
22875
|
+
if the mean can't be calculated (if not all x-values are scalars or distributions),
|
22876
|
+
nan will be returned.
|
22877
|
+
"""
|
22878
|
+
return self._mean
|
22879
|
+
|
22880
|
+
|
22531
22881
|
class External(_Distribution):
|
22532
22882
|
"""
|
22533
22883
|
External distribution function
|
@@ -24127,7 +24477,7 @@ class _APNG:
|
|
24127
24477
|
|
24128
24478
|
def to_bytes(self):
|
24129
24479
|
CHUNK_BEFORE_IDAT = {"cHRM", "gAMA", "iCCP", "sBIT", "sRGB", "bKGD", "hIST", "tRNS", "pHYs", "sPLT", "tIME", "PLTE"}
|
24130
|
-
PNG_SIGN = b"\x89\x50\
|
24480
|
+
PNG_SIGN = b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
|
24131
24481
|
out = [PNG_SIGN]
|
24132
24482
|
other_chunks = []
|
24133
24483
|
seq = 0
|
@@ -25060,6 +25410,11 @@ class Animate3dObj(Animate3dBase):
|
|
25060
25410
|
):
|
25061
25411
|
super().__init__(visible=visible, arg=arg, layer=layer, parent=parent, env=env, **kwargs)
|
25062
25412
|
|
25413
|
+
global pywavefront
|
25414
|
+
global visualization
|
25415
|
+
global pyglet
|
25416
|
+
|
25417
|
+
|
25063
25418
|
self.x = x
|
25064
25419
|
self.y = y
|
25065
25420
|
self.z = z
|
@@ -25081,18 +25436,26 @@ class Animate3dObj(Animate3dBase):
|
|
25081
25436
|
self.y_offset = 0
|
25082
25437
|
self.z_offset = 0
|
25083
25438
|
|
25084
|
-
|
25085
|
-
|
25086
|
-
|
25087
|
-
|
25088
|
-
|
25089
|
-
|
25090
|
-
|
25091
|
-
|
25439
|
+
try:
|
25440
|
+
import pywavefront
|
25441
|
+
except ImportError:
|
25442
|
+
pywavefront=None
|
25443
|
+
|
25444
|
+
try:
|
25445
|
+
import pyglet # this is a requirement for visualization!
|
25446
|
+
except ImportError:
|
25447
|
+
pyglet=None
|
25448
|
+
|
25449
|
+
from pywavefront import visualization
|
25092
25450
|
|
25093
25451
|
def draw(self, t):
|
25452
|
+
global pywavefront
|
25453
|
+
global visualization
|
25454
|
+
global pyglet
|
25094
25455
|
if pywavefront is None:
|
25095
25456
|
raise ImportError("Animate3dObj requires pywavefront. Not found")
|
25457
|
+
if pyglet is None:
|
25458
|
+
raise ImportError("Animate3dObj requires pyglet. Not found")
|
25096
25459
|
|
25097
25460
|
obj_filename = Path(self.filename(t))
|
25098
25461
|
if not obj_filename.suffix:
|
@@ -26601,8 +26964,8 @@ def getfont(fontname, fontsize):
|
|
26601
26964
|
return getfont.lookup[(fontname, fontsize)]
|
26602
26965
|
else:
|
26603
26966
|
getfont.lookup = {}
|
26604
|
-
if fontname=="":
|
26605
|
-
a=1
|
26967
|
+
if fontname == "":
|
26968
|
+
a = 1
|
26606
26969
|
if isinstance(fontname, str):
|
26607
26970
|
fontlist1 = [fontname]
|
26608
26971
|
else:
|
@@ -26837,17 +27200,23 @@ def can_animate3d(try_only: bool = True) -> bool:
|
|
26837
27200
|
import OpenGL.GL as gl
|
26838
27201
|
import OpenGL.GLU as glu
|
26839
27202
|
import OpenGL.GLUT as glut
|
27203
|
+
import OpenGL
|
26840
27204
|
except ImportError:
|
26841
27205
|
if try_only:
|
26842
27206
|
return False
|
26843
27207
|
else:
|
26844
27208
|
raise ImportError("OpenGL is required for animation3d. Install with pip install PyOpenGL or see salabim manual")
|
27209
|
+
try:
|
27210
|
+
glut.glutInit()
|
27211
|
+
except OpenGL.error.NullFunctionError:
|
27212
|
+
raise ImportError("Installed OpenGL does not support glut. Try 'pip install OpenGL-glut' or see the salabim documentation")
|
27213
|
+
|
26845
27214
|
return True
|
26846
27215
|
else:
|
26847
27216
|
if try_only:
|
26848
27217
|
return False
|
26849
27218
|
else:
|
26850
|
-
raise ImportError("cannot
|
27219
|
+
raise ImportError("cannot animate, let alone animate3d")
|
26851
27220
|
|
26852
27221
|
|
26853
27222
|
def can_video(try_only: bool = True) -> bool:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: salabim
|
3
|
-
Version: 24.0.
|
3
|
+
Version: 24.0.14.post4
|
4
4
|
Summary: salabim - discrete event simulation in Python
|
5
5
|
Author-email: Ruud van der Ham <rt.van.der.ham@gmail.com>
|
6
6
|
Project-URL: Homepage, https://salabim.org
|
@@ -46,7 +46,7 @@ In contrast to some other Python DES packages, salabim does not require the use
|
|
46
46
|
### Features and documentation
|
47
47
|
|
48
48
|
- Cross-platform support: salabim runs on Windows, macOS, Linux, iOS/iPadOS (Pythonista), and can even be used with "Python In Excel".
|
49
|
-
- Comprehensive documentation: Visit [www.salabim.org/manual](www.salabim.org/manual) for detailed documentation.
|
49
|
+
- Comprehensive documentation: Visit [www.salabim.org/manual](https://www.salabim.org/manual) for detailed documentation.
|
50
50
|
|
51
51
|
### Resources
|
52
52
|
|
@@ -0,0 +1,10 @@
|
|
1
|
+
salabim/DejaVuSansMono.ttf,sha256=Z_oIXp5yp1Zaw2y2p3vaxwHhjHpG0MFbmwhxSh4aIEI,335068
|
2
|
+
salabim/LICENSE.txt,sha256=qHlBa-POyexatCxDTjSKMlYtkBFQDn9lu-YV_1L6V0U,1106
|
3
|
+
salabim/__init__.py,sha256=r7qPLvlmX0dkZDyjuTo8Jo3ex3sD1L4pmK6K5ib9vyw,56
|
4
|
+
salabim/calibri.ttf,sha256=RWpf8Uo31RfvGGNaSt9-2sXSuN87AVE_NFMRsV3LhBk,1330156
|
5
|
+
salabim/mplus-1m-regular.ttf,sha256=EuFHr90BJjuAn_r5MleJFN-WfkeWJ4tf7DweI5zr8tU,289812
|
6
|
+
salabim/salabim.py,sha256=g2f1Dxf-6GkrS2AvM6EJhV7dta33KFqvsrdUKVUQYNI,1114883
|
7
|
+
salabim-24.0.14.post4.dist-info/METADATA,sha256=atwt9cNwaB9q37H5sqAzSRavt-KnAUuCRozQyUPRIXE,3464
|
8
|
+
salabim-24.0.14.post4.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
9
|
+
salabim-24.0.14.post4.dist-info/top_level.txt,sha256=UE6zVlbi3F6T5ma1a_5TrojMaF21GYKDt9svvm0U4cQ,8
|
10
|
+
salabim-24.0.14.post4.dist-info/RECORD,,
|
salabim-24.0.13.dist-info/RECORD
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
salabim/DejaVuSansMono.ttf,sha256=Z_oIXp5yp1Zaw2y2p3vaxwHhjHpG0MFbmwhxSh4aIEI,335068
|
2
|
-
salabim/LICENSE.txt,sha256=qHlBa-POyexatCxDTjSKMlYtkBFQDn9lu-YV_1L6V0U,1106
|
3
|
-
salabim/__init__.py,sha256=r7qPLvlmX0dkZDyjuTo8Jo3ex3sD1L4pmK6K5ib9vyw,56
|
4
|
-
salabim/calibri.ttf,sha256=RWpf8Uo31RfvGGNaSt9-2sXSuN87AVE_NFMRsV3LhBk,1330156
|
5
|
-
salabim/mplus-1m-regular.ttf,sha256=EuFHr90BJjuAn_r5MleJFN-WfkeWJ4tf7DweI5zr8tU,289812
|
6
|
-
salabim/salabim.py,sha256=NzhLkqRi8niqF9eQQPZRxJueQBROP0084q6qHrY6Qzc,1103953
|
7
|
-
salabim-24.0.13.dist-info/METADATA,sha256=-xWemNdEOZ-EbstXw49IqGKhr97mg85QxyuDLa2LtGA,3450
|
8
|
-
salabim-24.0.13.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
9
|
-
salabim-24.0.13.dist-info/top_level.txt,sha256=UE6zVlbi3F6T5ma1a_5TrojMaF21GYKDt9svvm0U4cQ,8
|
10
|
-
salabim-24.0.13.dist-info/RECORD,,
|
File without changes
|