most-queue 1.63__py3-none-any.whl → 2.2__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.
Potentially problematic release.
This version of most-queue might be problematic. Click here for more details.
- most_queue/distr_utils/__init__.py +0 -0
- most_queue/{general/interfaces.py → distr_utils/base_distribution.py} +2 -2
- most_queue/{general → distr_utils}/distribution_fitting.py +28 -41
- most_queue/{rand_distribution.py → distributions.py} +52 -47
- most_queue/general/plots.py +1 -1
- most_queue/general/results_structs.py +163 -0
- most_queue/general/tables.py +7 -21
- most_queue/misc/approx_cdf_make.py +4 -8
- most_queue/misc/calc_v_pls.py +27 -17
- most_queue/misc/compare_fj_calc.py +3 -1
- most_queue/misc/flow_sum.py +13 -16
- most_queue/misc/run_mgn_with_h2_delay_cold_warm.py +81 -81
- most_queue/misc/test_fj_delta.py +10 -12
- most_queue/misc/test_network_opt_approx.py +8 -7
- most_queue/misc/test_network_opt_plus.py +7 -7
- most_queue/misc/vacations_paper_utils.py +5 -5
- most_queue/sim/base.py +24 -31
- most_queue/sim/batch.py +3 -1
- most_queue/sim/finite_source.py +1 -1
- most_queue/sim/flow_sum.py +15 -10
- most_queue/sim/fork_join.py +1 -1
- most_queue/sim/fork_join_delta.py +4 -6
- most_queue/sim/negative.py +21 -17
- most_queue/sim/networks/base_network_sim.py +103 -0
- most_queue/sim/networks/network.py +86 -51
- most_queue/sim/networks/priority_network.py +125 -89
- most_queue/sim/priority.py +83 -76
- most_queue/sim/utils/distribution_utils.py +17 -15
- most_queue/sim/utils/servers.py +11 -12
- most_queue/sim/utils/tasks.py +5 -7
- most_queue/sim/vacations.py +27 -8
- most_queue/theory/base_queue.py +75 -0
- most_queue/theory/batch/mm1.py +94 -47
- most_queue/theory/calc_params.py +5 -6
- most_queue/theory/closed/engset.py +86 -34
- most_queue/theory/fifo/ek_d_n.py +80 -48
- most_queue/theory/fifo/gi_m_1.py +92 -35
- most_queue/theory/fifo/gi_m_n.py +92 -40
- most_queue/theory/fifo/m_d_n.py +45 -13
- most_queue/theory/fifo/mg1.py +77 -35
- most_queue/theory/fifo/mgn_takahasi.py +102 -50
- most_queue/theory/fifo/mmnr.py +61 -11
- most_queue/theory/fork_join/m_m_n.py +98 -19
- most_queue/theory/fork_join/split_join.py +67 -246
- most_queue/theory/impatience/mm1.py +62 -15
- most_queue/theory/negative/mg1_disasters.py +78 -26
- most_queue/theory/negative/mg1_rcs.py +62 -35
- most_queue/theory/negative/mgn_disaster.py +221 -185
- most_queue/theory/negative/mgn_rcs.py +144 -107
- most_queue/theory/negative/structs.py +0 -89
- most_queue/theory/networks/base_network_calc.py +123 -0
- most_queue/theory/networks/network_viewer.py +2 -6
- most_queue/theory/networks/open_network.py +69 -30
- most_queue/theory/networks/open_network_prty.py +69 -31
- most_queue/theory/networks/opt/transition.py +28 -34
- most_queue/theory/networks/opt/transition_approx.py +18 -18
- most_queue/theory/networks/opt/transition_plus.py +12 -12
- most_queue/theory/priority/mgn_invar_approx.py +84 -35
- most_queue/theory/priority/non_preemptive/mg1.py +60 -7
- most_queue/theory/priority/preemptive/m_ph_n_busy_approx.py +131 -60
- most_queue/theory/priority/preemptive/mg1.py +48 -29
- most_queue/theory/priority/preemptive/{mmn_3cls_busy_approx.py → mm2_3cls_busy_approx.py} +226 -157
- most_queue/theory/priority/preemptive/mmn_2cls_pr_busy_approx.py +183 -115
- most_queue/theory/utils/busy_periods.py +3 -7
- most_queue/theory/utils/conditional.py +5 -12
- most_queue/theory/utils/diff5dots.py +3 -9
- most_queue/theory/utils/flow_sum.py +8 -16
- most_queue/theory/utils/max_dist.py +196 -0
- most_queue/theory/utils/passage_time.py +29 -41
- most_queue/theory/utils/q_poisson_arrival_calc.py +4 -16
- most_queue/theory/utils/student_stat.py +1 -5
- most_queue/theory/utils/transforms.py +2 -4
- most_queue/theory/utils/utilization_approx.py +4 -1
- most_queue/theory/vacations/m_h2_h2warm.py +185 -140
- most_queue/theory/vacations/mg1_warm_calc.py +72 -19
- most_queue/theory/vacations/mgn_with_h2_delay_cold_warm.py +160 -122
- most_queue/theory/vacations/mmn_with_h2_cold_and_h2_warmup.py +258 -192
- {most_queue-1.63.dist-info → most_queue-2.2.dist-info}/METADATA +66 -10
- most_queue-2.2.dist-info/RECORD +110 -0
- most_queue-1.63.dist-info/RECORD +0 -104
- /most_queue/{general → distr_utils}/distribution_params.py +0 -0
- {most_queue-1.63.dist-info → most_queue-2.2.dist-info}/WHEEL +0 -0
- {most_queue-1.63.dist-info → most_queue-2.2.dist-info}/licenses/LICENSE +0 -0
|
File without changes
|
|
@@ -55,10 +55,10 @@ class Distribution(ABC):
|
|
|
55
55
|
|
|
56
56
|
@staticmethod
|
|
57
57
|
@abstractmethod
|
|
58
|
-
def
|
|
58
|
+
def get_params_by_mean_and_cv(f1: float, cv: float):
|
|
59
59
|
"""
|
|
60
60
|
:param f1: mean of the distribution.
|
|
61
|
-
:param
|
|
61
|
+
:param cv: coefficient of variation (std_dev / mean).
|
|
62
62
|
:return: Parameters for the distribution that correspond
|
|
63
63
|
to the given mean and coefficient of variation.
|
|
64
64
|
"""
|
|
@@ -8,10 +8,14 @@ from dataclasses import dataclass
|
|
|
8
8
|
|
|
9
9
|
import numpy as np
|
|
10
10
|
|
|
11
|
-
from most_queue.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
from most_queue.distr_utils.distribution_params import (
|
|
12
|
+
Cox2Params,
|
|
13
|
+
ErlangParams,
|
|
14
|
+
GammaParams,
|
|
15
|
+
H2Params,
|
|
16
|
+
ParetoParams,
|
|
17
|
+
WeibullParams,
|
|
18
|
+
)
|
|
15
19
|
|
|
16
20
|
|
|
17
21
|
@dataclass
|
|
@@ -98,28 +102,22 @@ def fit_h2_clx(moments: list[float], fitting_params: FittingParams | None = None
|
|
|
98
102
|
|
|
99
103
|
if fitting_params.is_fitting:
|
|
100
104
|
# проверка на близость распределения к экспоненциальному
|
|
101
|
-
|
|
102
|
-
if math.fabs(
|
|
105
|
+
cv = cmath.sqrt(moments[1] - moments[0] ** 2) / moments[0]
|
|
106
|
+
if math.fabs(cv.real - 1.0) < fitting_params.ee:
|
|
103
107
|
if fitting_params.verbose:
|
|
104
|
-
print(
|
|
105
|
-
f"H2 is close to Exp. Multiply moments to (1+je)"
|
|
106
|
-
f"coev = {coev:5.3f}, e = {fitting_params.e:5.3f}."
|
|
107
|
-
)
|
|
108
|
+
print(f"H2 is close to Exp. Multiply moments to (1+je)" f"cv = {cv:5.3f}, e = {fitting_params.e:5.3f}.")
|
|
108
109
|
f = []
|
|
109
110
|
for i, mom in enumerate(moments):
|
|
110
111
|
f.append(mom * complex(1, (i + 1) * fitting_params.e))
|
|
111
112
|
|
|
112
113
|
return fit_h2_clx(f, fitting_params=fitting_params)
|
|
113
114
|
|
|
114
|
-
|
|
115
|
+
cv = cmath.sqrt(moments[1] - moments[0] ** 2) / moments[0]
|
|
115
116
|
|
|
116
117
|
# проверка на близость распределения к Эрланга 2-го порядка
|
|
117
|
-
if math.fabs(
|
|
118
|
+
if math.fabs(cv.real - 1.0 / math.sqrt(2.0)) < fitting_params.ee:
|
|
118
119
|
if fitting_params.verbose:
|
|
119
|
-
print(
|
|
120
|
-
f"H2 is close to E2. Multiply moments to (1+je)"
|
|
121
|
-
f"coev = {coev:5.3f}, e = {fitting_params.e:5.3f}."
|
|
122
|
-
)
|
|
120
|
+
print(f"H2 is close to E2. Multiply moments to (1+je)" f"cv = {cv:5.3f}, e = {fitting_params.e:5.3f}.")
|
|
123
121
|
f = []
|
|
124
122
|
for i, mom in enumerate(moments):
|
|
125
123
|
f.append(mom * complex(1, (i + 1) * fitting_params.e))
|
|
@@ -148,26 +146,23 @@ def fit_cox(moments: list[float], fitting_params: FittingParams | None = None) -
|
|
|
148
146
|
|
|
149
147
|
if fitting_params.is_fitting:
|
|
150
148
|
# проверка на близость распределения к экспоненциальному
|
|
151
|
-
|
|
149
|
+
cv = cmath.sqrt(moments[1] - moments[0] ** 2) / moments[0]
|
|
152
150
|
if abs(moments[1] - moments[0] * moments[0]) < fitting_params.ee:
|
|
153
151
|
if fitting_params.verbose:
|
|
154
|
-
print(
|
|
155
|
-
f"Cox special 1. Multiply moments to (1+je)"
|
|
156
|
-
f"coev = {coev:5.3f} e = {fitting_params.e:5.3f}."
|
|
157
|
-
)
|
|
152
|
+
print(f"Cox special 1. Multiply moments to (1+je)" f"cv = {cv:5.3f} e = {fitting_params.e:5.3f}.")
|
|
158
153
|
f = []
|
|
159
154
|
for i, mom in enumerate(moments):
|
|
160
155
|
f.append(mom * complex(1, (i + 1) * fitting_params.e))
|
|
161
156
|
|
|
162
157
|
return fit_cox(f, fitting_params=fitting_params)
|
|
163
158
|
|
|
164
|
-
|
|
159
|
+
cv = cmath.sqrt(moments[1] - moments[0] ** 2) / moments[0]
|
|
165
160
|
|
|
166
161
|
# проверка на близость распределения к Эрланга 2-го порядка
|
|
167
162
|
if abs(moments[1] - (3.0 / 4) * moments[0] * moments[0]) < fitting_params.ee:
|
|
168
163
|
if fitting_params.verbose:
|
|
169
164
|
print("Cox special 2. Multiply moments to (1+je)")
|
|
170
|
-
print(f"\
|
|
165
|
+
print(f"\tcv = {cv:5.3f}, e = {fitting_params.e:5.3f}")
|
|
171
166
|
f = []
|
|
172
167
|
for i, mom in enumerate(moments):
|
|
173
168
|
f.append(mom * complex(1, (i + 1) * fitting_params.e))
|
|
@@ -176,9 +171,7 @@ def fit_cox(moments: list[float], fitting_params: FittingParams | None = None) -
|
|
|
176
171
|
for i in range(3):
|
|
177
172
|
f[i] = moments[i] / math.factorial(i + 1)
|
|
178
173
|
|
|
179
|
-
d = np.power(f[2] - f[0] * f[1], 2) - 4.0 * (f[1] - np.power(f[0], 2)) * (
|
|
180
|
-
f[0] * f[2] - np.power(f[1], 2)
|
|
181
|
-
)
|
|
174
|
+
d = np.power(f[2] - f[0] * f[1], 2) - 4.0 * (f[1] - np.power(f[0], 2)) * (f[0] * f[2] - np.power(f[1], 2))
|
|
182
175
|
mu2 = f[0] * f[1] - f[2] + cmath.sqrt(d)
|
|
183
176
|
mu2 /= 2.0 * (np.power(f[1], 2) - f[0] * f[2])
|
|
184
177
|
mu1 = (mu2 * f[0] - 1.0) / (mu2 * f[1] - f[0])
|
|
@@ -200,13 +193,13 @@ def fit_pareto_moments(moments: list[float]):
|
|
|
200
193
|
return ParetoParams(alpha=a, K=k)
|
|
201
194
|
|
|
202
195
|
|
|
203
|
-
def
|
|
196
|
+
def fit_pareto_by_mean_and_cv(f1: float, cv: float):
|
|
204
197
|
"""
|
|
205
198
|
Get parameters of the distribution by mean and coefficient of variation.
|
|
206
199
|
:param f1: float, mean value of the distribution
|
|
207
|
-
:param
|
|
200
|
+
:param cv: float, coefficient of variation (mean / std)
|
|
208
201
|
"""
|
|
209
|
-
d = pow(f1 *
|
|
202
|
+
d = pow(f1 * cv, 2)
|
|
210
203
|
c = pow(f1, 2) / d
|
|
211
204
|
disc = 4 * (1 + c)
|
|
212
205
|
a = (2 + math.sqrt(disc)) / 2
|
|
@@ -287,9 +280,7 @@ def fit_gamma(moments: list[float]) -> GammaParams:
|
|
|
287
280
|
else:
|
|
288
281
|
B.append(moments[i - 1])
|
|
289
282
|
for j in range(len(moments) + 1):
|
|
290
|
-
A[i].append(
|
|
291
|
-
calc_gamma_func(alpha + i + j) / (pow(mu, i + j) * calc_gamma_func(alpha))
|
|
292
|
-
)
|
|
283
|
+
A[i].append(calc_gamma_func(alpha + i + j) / (pow(mu, i + j) * calc_gamma_func(alpha)))
|
|
293
284
|
g = np.linalg.solve(A, B)
|
|
294
285
|
return GammaParams(mu=mu, alpha=alpha, g=g)
|
|
295
286
|
|
|
@@ -311,14 +302,10 @@ def fit_weibull(moments: list[float]) -> WeibullParams:
|
|
|
311
302
|
a = moments[1] / (moments[0] * moments[0])
|
|
312
303
|
u0 = math.log(2 * a) / (2.0 * math.log(2))
|
|
313
304
|
ee = 1e-6
|
|
314
|
-
u1 = (1.0 / (2 * math.log(2))) * math.log(
|
|
315
|
-
a * math.sqrt(math.pi) * math.gamma(u0 + 1) / math.gamma(u0 + 0.5)
|
|
316
|
-
)
|
|
305
|
+
u1 = (1.0 / (2 * math.log(2))) * math.log(a * math.sqrt(math.pi) * math.gamma(u0 + 1) / math.gamma(u0 + 0.5))
|
|
317
306
|
delta = u1 - u0
|
|
318
307
|
while math.fabs(delta) > ee:
|
|
319
|
-
u1 = (1.0 / (2 * math.log(2))) * math.log(
|
|
320
|
-
a * math.sqrt(math.pi) * math.gamma(u0 + 1) / math.gamma(u0 + 0.5)
|
|
321
|
-
)
|
|
308
|
+
u1 = (1.0 / (2 * math.log(2))) * math.log(a * math.sqrt(math.pi) * math.gamma(u0 + 1) / math.gamma(u0 + 0.5))
|
|
322
309
|
delta = u1 - u0
|
|
323
310
|
u0 = u1
|
|
324
311
|
k = 1 / u1
|
|
@@ -327,14 +314,14 @@ def fit_weibull(moments: list[float]) -> WeibullParams:
|
|
|
327
314
|
return WeibullParams(k=k, W=big_w)
|
|
328
315
|
|
|
329
316
|
|
|
330
|
-
def
|
|
317
|
+
def gamma_moments_by_mean_and_cv(mean: float, cv: float) -> list[float]:
|
|
331
318
|
"""
|
|
332
319
|
Calculate the first three moments of a gamma distribution
|
|
333
320
|
given the mean and coefficient of variation.
|
|
334
321
|
"""
|
|
335
322
|
f = [0, 0, 0]
|
|
336
|
-
alpha = 1 / (
|
|
323
|
+
alpha = 1 / (cv**2)
|
|
337
324
|
f[0] = mean
|
|
338
|
-
f[1] = pow(f[0], 2) * (pow(
|
|
325
|
+
f[1] = pow(f[0], 2) * (pow(cv, 2) + 1)
|
|
339
326
|
f[2] = f[1] * f[0] * (1.0 + 2 / alpha)
|
|
340
327
|
return f
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# pylint: disable=too-many-lines
|
|
1
2
|
"""
|
|
2
3
|
Random distributions for simulation.
|
|
3
4
|
"""
|
|
@@ -8,17 +9,30 @@ import numpy as np
|
|
|
8
9
|
import scipy.special as sp
|
|
9
10
|
from scipy import stats
|
|
10
11
|
|
|
11
|
-
from most_queue.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
from most_queue.distr_utils.base_distribution import Distribution
|
|
13
|
+
from most_queue.distr_utils.distribution_fitting import (
|
|
14
|
+
FittingParams,
|
|
15
|
+
calc_gamma_func,
|
|
16
|
+
fit_cox,
|
|
17
|
+
fit_erlang,
|
|
18
|
+
fit_gamma,
|
|
19
|
+
fit_h2,
|
|
20
|
+
fit_h2_clx,
|
|
21
|
+
fit_pareto_by_mean_and_cv,
|
|
22
|
+
fit_pareto_moments,
|
|
23
|
+
fit_weibull,
|
|
24
|
+
gamma_moments_by_mean_and_cv,
|
|
25
|
+
)
|
|
26
|
+
from most_queue.distr_utils.distribution_params import (
|
|
27
|
+
Cox2Params,
|
|
28
|
+
ErlangParams,
|
|
29
|
+
GammaParams,
|
|
30
|
+
GaussianParams,
|
|
31
|
+
H2Params,
|
|
32
|
+
ParetoParams,
|
|
33
|
+
UniformParams,
|
|
34
|
+
WeibullParams,
|
|
35
|
+
)
|
|
22
36
|
|
|
23
37
|
|
|
24
38
|
class Weibull(Distribution):
|
|
@@ -85,17 +99,17 @@ class Weibull(Distribution):
|
|
|
85
99
|
return fit_weibull(moments)
|
|
86
100
|
|
|
87
101
|
@staticmethod
|
|
88
|
-
def
|
|
102
|
+
def get_params_by_mean_and_cv(f1: float, cv: float) -> WeibullParams:
|
|
89
103
|
"""
|
|
90
104
|
Subselect parameters of Weibull distribution by the given mean and coefficient of variation.
|
|
91
105
|
Args:
|
|
92
106
|
f1 (float): The first parameter of the Weibull distribution.
|
|
93
|
-
|
|
107
|
+
cv (float): The coefficient of variation.
|
|
94
108
|
Returns:
|
|
95
109
|
WeibullParams
|
|
96
110
|
"""
|
|
97
111
|
|
|
98
|
-
f =
|
|
112
|
+
f = gamma_moments_by_mean_and_cv(f1, cv)
|
|
99
113
|
|
|
100
114
|
return Weibull.get_params(f)
|
|
101
115
|
|
|
@@ -188,15 +202,15 @@ class NormalDistribution(Distribution):
|
|
|
188
202
|
return GaussianParams(mean, std_dev)
|
|
189
203
|
|
|
190
204
|
@staticmethod
|
|
191
|
-
def
|
|
205
|
+
def get_params_by_mean_and_cv(f1: float, cv: float):
|
|
192
206
|
"""
|
|
193
207
|
:param f1: mean of the distribution.
|
|
194
|
-
:param
|
|
208
|
+
:param cv: coefficient of variation (std_dev / mean).
|
|
195
209
|
:return: Parameters for the distribution that correspond
|
|
196
210
|
to the given mean and coefficient of variation.
|
|
197
211
|
"""
|
|
198
212
|
mean = f1
|
|
199
|
-
std_dev =
|
|
213
|
+
std_dev = cv * mean
|
|
200
214
|
return GaussianParams(mean, std_dev)
|
|
201
215
|
|
|
202
216
|
|
|
@@ -246,9 +260,7 @@ class UniformDistribution(Distribution):
|
|
|
246
260
|
mean, half_interval = params.mean, params.half_interval
|
|
247
261
|
f = [0.0] * num
|
|
248
262
|
for i in range(num):
|
|
249
|
-
f[i] = (pow(mean + half_interval, i + 2) - pow(mean - half_interval, i + 2)) / (
|
|
250
|
-
2 * half_interval * (i + 2)
|
|
251
|
-
)
|
|
263
|
+
f[i] = (pow(mean + half_interval, i + 2) - pow(mean - half_interval, i + 2)) / (2 * half_interval * (i + 2))
|
|
252
264
|
return f
|
|
253
265
|
|
|
254
266
|
@staticmethod
|
|
@@ -264,13 +276,13 @@ class UniformDistribution(Distribution):
|
|
|
264
276
|
return UniformParams(mean=mean, half_interval=half_interval)
|
|
265
277
|
|
|
266
278
|
@staticmethod
|
|
267
|
-
def
|
|
279
|
+
def get_params_by_mean_and_cv(f1: float, cv: float) -> UniformParams:
|
|
268
280
|
"""
|
|
269
281
|
Get parameters of the uniform distribution by mean and coefficient of variation.
|
|
270
282
|
Returns mean and half interval.
|
|
271
283
|
"""
|
|
272
284
|
|
|
273
|
-
D = pow(
|
|
285
|
+
D = pow(cv * f1, 2)
|
|
274
286
|
half_interval = math.sqrt(3 * D)
|
|
275
287
|
|
|
276
288
|
return UniformParams(mean=f1, half_interval=half_interval)
|
|
@@ -369,9 +381,7 @@ class H2Distribution(Distribution):
|
|
|
369
381
|
y2 = 1.0 - params.p1
|
|
370
382
|
|
|
371
383
|
for i in range(num):
|
|
372
|
-
f[i] = math.factorial(i + 1) * (
|
|
373
|
-
params.p1 / pow(params.mu1, i + 1) + y2 / pow(params.mu2, i + 1)
|
|
374
|
-
)
|
|
384
|
+
f[i] = math.factorial(i + 1) * (params.p1 / pow(params.mu1, i + 1) + y2 / pow(params.mu2, i + 1))
|
|
375
385
|
return f
|
|
376
386
|
|
|
377
387
|
@staticmethod
|
|
@@ -394,9 +404,7 @@ class H2Distribution(Distribution):
|
|
|
394
404
|
return fit_h2(moments)
|
|
395
405
|
|
|
396
406
|
@staticmethod
|
|
397
|
-
def get_params_clx(
|
|
398
|
-
moments: list[float], fitting_params: FittingParams | None = None
|
|
399
|
-
) -> H2Params:
|
|
407
|
+
def get_params_clx(moments: list[float], fitting_params: FittingParams | None = None) -> H2Params:
|
|
400
408
|
"""
|
|
401
409
|
Method of fitting H2 distribution parameters to given initial moments.
|
|
402
410
|
Uses the method of moments and optimization to fit the parameters.
|
|
@@ -406,12 +414,12 @@ class H2Distribution(Distribution):
|
|
|
406
414
|
return fit_h2_clx(moments, fitting_params=fitting_params)
|
|
407
415
|
|
|
408
416
|
@staticmethod
|
|
409
|
-
def
|
|
417
|
+
def get_params_by_mean_and_cv(f1: float, cv: float, is_clx=False) -> H2Params:
|
|
410
418
|
"""
|
|
411
419
|
Get parameters of the H2 distribution by mean and coefficient of variation.
|
|
412
420
|
"""
|
|
413
421
|
|
|
414
|
-
f =
|
|
422
|
+
f = gamma_moments_by_mean_and_cv(f1, cv)
|
|
415
423
|
|
|
416
424
|
if is_clx:
|
|
417
425
|
return H2Distribution.get_params_clx(f)
|
|
@@ -505,10 +513,7 @@ class CoxDistribution(Distribution):
|
|
|
505
513
|
y2 = 1.0 - y1
|
|
506
514
|
f = [0.0] * 3
|
|
507
515
|
f[0] = y2 / m1 + y1 * (1.0 / m1 + 1.0 / m2)
|
|
508
|
-
f[1] = 2.0 * (
|
|
509
|
-
y2 / math.pow(m1, 2)
|
|
510
|
-
+ y1 * (1.0 / math.pow(m1, 2) + 1.0 / (m1 * m2) + 1.0 / math.pow(m2, 2))
|
|
511
|
-
)
|
|
516
|
+
f[1] = 2.0 * (y2 / math.pow(m1, 2) + y1 * (1.0 / math.pow(m1, 2) + 1.0 / (m1 * m2) + 1.0 / math.pow(m2, 2)))
|
|
512
517
|
f[2] = 6.0 * (
|
|
513
518
|
y2 / (math.pow(m1, 3))
|
|
514
519
|
+ y1
|
|
@@ -530,12 +535,12 @@ class CoxDistribution(Distribution):
|
|
|
530
535
|
return fit_cox(moments, fitting_params=fitting_params)
|
|
531
536
|
|
|
532
537
|
@staticmethod
|
|
533
|
-
def
|
|
538
|
+
def get_params_by_mean_and_cv(f1: float, cv: float) -> Cox2Params:
|
|
534
539
|
"""
|
|
535
540
|
Get parameters of C2 distribution by mean and coefficient of variation
|
|
536
541
|
"""
|
|
537
542
|
|
|
538
|
-
f =
|
|
543
|
+
f = gamma_moments_by_mean_and_cv(f1, cv)
|
|
539
544
|
|
|
540
545
|
return CoxDistribution.get_params(f)
|
|
541
546
|
|
|
@@ -584,10 +589,10 @@ class DeterministicDistribution(Distribution):
|
|
|
584
589
|
return moments[0]
|
|
585
590
|
|
|
586
591
|
@staticmethod
|
|
587
|
-
def
|
|
592
|
+
def get_params_by_mean_and_cv(f1: float, cv: float):
|
|
588
593
|
"""
|
|
589
594
|
:param f1: mean of the distribution.
|
|
590
|
-
:param
|
|
595
|
+
:param cv: coefficient of variation (std_dev / mean).
|
|
591
596
|
:return: Parameters for the distribution that correspond
|
|
592
597
|
to the given mean and coefficient of variation.
|
|
593
598
|
"""
|
|
@@ -689,14 +694,14 @@ class ParetoDistribution(Distribution):
|
|
|
689
694
|
return fit_pareto_moments(moments)
|
|
690
695
|
|
|
691
696
|
@staticmethod
|
|
692
|
-
def
|
|
697
|
+
def get_params_by_mean_and_cv(f1: float, cv: float):
|
|
693
698
|
"""
|
|
694
699
|
Get parameters of the distribution by mean and coefficient of variation.
|
|
695
700
|
:param f1: float, mean value of the distribution
|
|
696
|
-
:param
|
|
701
|
+
:param cv: float, coefficient of variation (mean / std)
|
|
697
702
|
"""
|
|
698
703
|
|
|
699
|
-
return
|
|
704
|
+
return fit_pareto_by_mean_and_cv(f1, cv)
|
|
700
705
|
|
|
701
706
|
|
|
702
707
|
class ErlangDistribution(Distribution):
|
|
@@ -782,14 +787,14 @@ class ErlangDistribution(Distribution):
|
|
|
782
787
|
return fit_erlang(moments)
|
|
783
788
|
|
|
784
789
|
@staticmethod
|
|
785
|
-
def
|
|
790
|
+
def get_params_by_mean_and_cv(f1: float, cv: float) -> ErlangParams:
|
|
786
791
|
"""
|
|
787
792
|
Method selects the parameters of the Erlang distribution
|
|
788
793
|
by mean and coefficient of variation.
|
|
789
794
|
"""
|
|
790
795
|
f = [0, 0]
|
|
791
796
|
f[0] = f1
|
|
792
|
-
f[1] = (math.pow(
|
|
797
|
+
f[1] = (math.pow(cv, 2) + 1) * math.pow(f[0], 2)
|
|
793
798
|
return ErlangDistribution.get_params(f)
|
|
794
799
|
|
|
795
800
|
|
|
@@ -840,11 +845,11 @@ class ExpDistribution(Distribution):
|
|
|
840
845
|
return ErlangDistribution.get_params(moments).mu
|
|
841
846
|
|
|
842
847
|
@staticmethod
|
|
843
|
-
def
|
|
848
|
+
def get_params_by_mean_and_cv(f1: float, cv: float) -> float:
|
|
844
849
|
"""
|
|
845
850
|
Get parameters of the exponential distribution from mean and coefficient of variation.
|
|
846
851
|
:param f1: mean value
|
|
847
|
-
:param
|
|
852
|
+
:param cv: coefficient of variation (coefficient of dispersion)
|
|
848
853
|
"""
|
|
849
854
|
return 1 / f1
|
|
850
855
|
|
|
@@ -872,11 +877,11 @@ class GammaDistribution(Distribution):
|
|
|
872
877
|
return fit_gamma(moments)
|
|
873
878
|
|
|
874
879
|
@staticmethod
|
|
875
|
-
def
|
|
880
|
+
def get_params_by_mean_and_cv(f1: float, cv: float) -> GammaParams:
|
|
876
881
|
"""
|
|
877
882
|
Get parameters of gamma distribution by mean and coefficient of variation.
|
|
878
883
|
"""
|
|
879
|
-
d = pow(f1 *
|
|
884
|
+
d = pow(f1 * cv, 2)
|
|
880
885
|
mu = f1 / d
|
|
881
886
|
alpha = mu * f1
|
|
882
887
|
return GammaParams(mu=mu, alpha=alpha)
|
most_queue/general/plots.py
CHANGED
|
@@ -26,7 +26,7 @@ def plot_sim_vs_calc_moments(
|
|
|
26
26
|
is_errors=False,
|
|
27
27
|
is_waiting_time=True,
|
|
28
28
|
save_path=None,
|
|
29
|
-
):
|
|
29
|
+
): # pylint: disable=too-many-positional-arguments, too-many-arguments
|
|
30
30
|
"""
|
|
31
31
|
Plots the simulation and calculated moments for a given list of x values.
|
|
32
32
|
:param xs: A list of x values (e.g., utilization factors or number of channels).
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Structures for queueing systems.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from dataclasses import asdict, dataclass, is_dataclass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class QueueResults:
|
|
11
|
+
"""
|
|
12
|
+
Result of calculation for queueing system.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
v: list[float] | None = None # sojourn time initial moments
|
|
16
|
+
w: list[float] | None = None # waiting time initial moments
|
|
17
|
+
p: list[float] | None = None # probabilities of states
|
|
18
|
+
pi: list[float] | None = None # probabilities of states before arrival
|
|
19
|
+
utilization: float | None = None # utilization factor
|
|
20
|
+
|
|
21
|
+
duration: float = 0.0 # calculation or simulation duration in seconds
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class PriorityResults:
|
|
26
|
+
"""
|
|
27
|
+
Results of priority queue calculation
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
v: list[list[float]] | None = None # sojourn time moments for each class
|
|
31
|
+
w: list[list[float]] | None = None # waiting time moments for each class
|
|
32
|
+
p: list[float] | None = None # probabilities of states (low priority jobs)
|
|
33
|
+
|
|
34
|
+
h: list[list[float]] | None = None # initial moments of active time
|
|
35
|
+
busy: list[list[float]] | None = None # initial moments of busy period
|
|
36
|
+
w_with_pr: list[list[float]] | None = None # initial moments of waiting for service with interruptions
|
|
37
|
+
|
|
38
|
+
utilization: float | None = None # utilization factor
|
|
39
|
+
|
|
40
|
+
duration: float = 0.0 # calculation or simulation duration in seconds
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class VacationResults(QueueResults):
|
|
45
|
+
"""
|
|
46
|
+
Result of queue with vacations.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
warmup_prob: float = 0
|
|
50
|
+
cold_prob: float = 0
|
|
51
|
+
cold_delay_prob: float = 0
|
|
52
|
+
servers_busy_probs: list[float] | None = None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class NetworkResults:
|
|
57
|
+
"""
|
|
58
|
+
Data class to store network results.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
v: list[float] | None = None # initial moments of sojourn time distribution
|
|
62
|
+
intensities: list[float] | None = None # intensities of arrivals into nodes
|
|
63
|
+
loads: list[float] | None = None # nodes utilizations
|
|
64
|
+
|
|
65
|
+
duration: float = 0.0 # calculation or simulation duration in seconds
|
|
66
|
+
|
|
67
|
+
arrived: int = 0 # number of arrived jobs (for simulation)
|
|
68
|
+
served: int = 0 # number of served jobs (for simulation)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass
|
|
72
|
+
class NetworkResultsPriority:
|
|
73
|
+
"""
|
|
74
|
+
Data class to store results for network with priority discipline in nodes.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
v: list[list[float]] | None = None # initial moments of sojourn time distribution for each class
|
|
78
|
+
intensities: list[list[float]] | None = None # intensities of arrivals into nodes for each class
|
|
79
|
+
loads: list[float] | None = None # nodes utilizations
|
|
80
|
+
|
|
81
|
+
duration: float = 0.0 # calculation or simulation duration in seconds
|
|
82
|
+
|
|
83
|
+
arrived: int = 0 # number of arrived jobs (for simulation)
|
|
84
|
+
served: int = 0 # number of served jobs (for simulation)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class NegativeArrivalsResults(QueueResults):
|
|
89
|
+
"""
|
|
90
|
+
Class for storing results related to negative arrivals in a queueing system.
|
|
91
|
+
Contains lists of waiting times (w), sojourn times (v),
|
|
92
|
+
sojourn times of served jobs (v_served), sojourn times of broken jobs (v_broken),
|
|
93
|
+
and probabilities (p).
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
v_served: list[float] | None = None
|
|
97
|
+
v_broken: list[float] | None = None
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@dataclass
|
|
101
|
+
class DependsOnChannelsResults:
|
|
102
|
+
"""
|
|
103
|
+
Class for storing results that depend on the number of channels.
|
|
104
|
+
Contains calculated and simulated results,
|
|
105
|
+
as well as parameters such as the number of channels,
|
|
106
|
+
utilization factor, and service time variation coefficient.
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
calc: list[NegativeArrivalsResults]
|
|
110
|
+
sim: list[NegativeArrivalsResults]
|
|
111
|
+
channels: list[int]
|
|
112
|
+
utilization_factor: float
|
|
113
|
+
service_time_variation_coef: float
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@dataclass
|
|
117
|
+
class DependsOnUtilizationResults:
|
|
118
|
+
"""
|
|
119
|
+
Class for storing results that depend on the utilization factor.
|
|
120
|
+
Contains calculated and simulated results,
|
|
121
|
+
as well as parameters such as the number of channels,
|
|
122
|
+
utilization factor, and service time variation coefficient.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
calc: list[NegativeArrivalsResults]
|
|
126
|
+
sim: list[NegativeArrivalsResults]
|
|
127
|
+
utilization_factor: list[float]
|
|
128
|
+
channels: int
|
|
129
|
+
service_time_variation_coef: float
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@dataclass
|
|
133
|
+
class DependsOnVariationResults:
|
|
134
|
+
"""
|
|
135
|
+
Class for storing results that depend on the service time variation coefficient.
|
|
136
|
+
Contains calculated and simulated results,
|
|
137
|
+
as well as parameters such as the number of channels,
|
|
138
|
+
utilization factor, and service time variation coefficient.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
calc: list[NegativeArrivalsResults]
|
|
142
|
+
sim: list[NegativeArrivalsResults]
|
|
143
|
+
service_time_variation_coef: list[float]
|
|
144
|
+
channels: int
|
|
145
|
+
utilization_factor: float
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class DependsOnJSONEncoder(json.JSONEncoder):
|
|
149
|
+
"""
|
|
150
|
+
Encoder for dataclasses to JSON.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
def default(self, o):
|
|
154
|
+
if is_dataclass(o):
|
|
155
|
+
json_res = {
|
|
156
|
+
"service_time_variation_coef": o.service_time_variation_coef,
|
|
157
|
+
"channels": o.channels,
|
|
158
|
+
"utilization_factor": o.utilization_factor,
|
|
159
|
+
"calc": [asdict(r) for r in o.calc],
|
|
160
|
+
"sim": [asdict(r) for r in o.sim],
|
|
161
|
+
}
|
|
162
|
+
return json_res
|
|
163
|
+
return super().default(o)
|
most_queue/general/tables.py
CHANGED
|
@@ -16,7 +16,7 @@ def times_print(
|
|
|
16
16
|
header=None,
|
|
17
17
|
sim_header="Sim",
|
|
18
18
|
calc_header="Num",
|
|
19
|
-
):
|
|
19
|
+
): # pylint: disable=too-many-positional-arguments, too-many-arguments
|
|
20
20
|
"""
|
|
21
21
|
Prints the initial moments of waiting or sojourn time in the system.
|
|
22
22
|
Args:
|
|
@@ -41,9 +41,7 @@ def times_print(
|
|
|
41
41
|
print("-" * 45)
|
|
42
42
|
if isinstance(sim_moments, list):
|
|
43
43
|
for j in range(min(len(sim_moments), len(calc_moments))):
|
|
44
|
-
calc_mom = (
|
|
45
|
-
calc_moments[j].real if isinstance(calc_moments[j], complex) else calc_moments[j]
|
|
46
|
-
)
|
|
44
|
+
calc_mom = calc_moments[j].real if isinstance(calc_moments[j], complex) else calc_moments[j]
|
|
47
45
|
sim_mom = sim_moments[j].real if isinstance(sim_moments[j], complex) else sim_moments[j]
|
|
48
46
|
print(
|
|
49
47
|
Fore.CYAN
|
|
@@ -78,7 +76,7 @@ def times_print_with_two_numerical(
|
|
|
78
76
|
is_w=True,
|
|
79
77
|
num1_header="Num1",
|
|
80
78
|
num2_header="Num2",
|
|
81
|
-
):
|
|
79
|
+
): # pylint: disable=too-many-positional-arguments, too-many-arguments
|
|
82
80
|
"""
|
|
83
81
|
Prints the initial moments of waiting or sojourn time in the system.
|
|
84
82
|
Args:
|
|
@@ -103,12 +101,8 @@ def times_print_with_two_numerical(
|
|
|
103
101
|
print("-" * 60)
|
|
104
102
|
if isinstance(sim_moments, list):
|
|
105
103
|
for j in range(min(len(sim_moments), len(calc_moments1), len(calc_moments2))):
|
|
106
|
-
calc_mom1 = (
|
|
107
|
-
|
|
108
|
-
)
|
|
109
|
-
calc_mom2 = (
|
|
110
|
-
calc_moments2[j].real if isinstance(calc_moments2[j], complex) else calc_moments2[j]
|
|
111
|
-
)
|
|
104
|
+
calc_mom1 = calc_moments1[j].real if isinstance(calc_moments1[j], complex) else calc_moments1[j]
|
|
105
|
+
calc_mom2 = calc_moments2[j].real if isinstance(calc_moments2[j], complex) else calc_moments2[j]
|
|
112
106
|
sim_mom = sim_moments[j].real if isinstance(sim_moments[j], complex) else sim_moments[j]
|
|
113
107
|
print(
|
|
114
108
|
Fore.CYAN
|
|
@@ -167,11 +161,7 @@ def times_print_no_compare(wait_times=None, sojourn_times=None):
|
|
|
167
161
|
if isinstance(wait_times, list):
|
|
168
162
|
for j in range(min(len(wait_times), len(sojourn_times))):
|
|
169
163
|
w_mom = wait_times[j].real if isinstance(wait_times[j], complex) else wait_times[j]
|
|
170
|
-
v_mom = (
|
|
171
|
-
sojourn_times[j].real
|
|
172
|
-
if isinstance(sojourn_times[j], complex)
|
|
173
|
-
else sojourn_times[j]
|
|
174
|
-
)
|
|
164
|
+
v_mom = sojourn_times[j].real if isinstance(sojourn_times[j], complex) else sojourn_times[j]
|
|
175
165
|
print(
|
|
176
166
|
Fore.CYAN
|
|
177
167
|
+ f"{j + 1:^15d}|"
|
|
@@ -352,10 +342,6 @@ def print_mrx(mrx, is_short=False):
|
|
|
352
342
|
print(f"{color}{mrx[i, j].real:^4.2f} | ", end="")
|
|
353
343
|
else:
|
|
354
344
|
print(f"{color}{mrx[i, j]:^5.3f} | ", end="")
|
|
355
|
-
print(
|
|
356
|
-
"\n" + "-------" * col
|
|
357
|
-
if is_short or mrx[i, j].imag == 0.0
|
|
358
|
-
else "\n" + "---------------" * col
|
|
359
|
-
)
|
|
345
|
+
print("\n" + "-------" * col if is_short or mrx[i, j].imag == 0.0 else "\n" + "---------------" * col)
|
|
360
346
|
|
|
361
347
|
print(f"{Style.RESET_ALL}")
|