most-queue 1.63__py3-none-any.whl → 2.1__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/general/distribution_fitting.py +14 -22
- most_queue/general/plots.py +1 -1
- most_queue/general/tables.py +7 -21
- most_queue/misc/approx_cdf_make.py +1 -5
- most_queue/misc/calc_v_pls.py +26 -16
- most_queue/misc/compare_fj_calc.py +3 -1
- most_queue/misc/flow_sum.py +3 -6
- most_queue/misc/run_mgn_with_h2_delay_cold_warm.py +16 -16
- most_queue/misc/test_fj_delta.py +8 -10
- most_queue/misc/test_network_opt_approx.py +7 -6
- most_queue/misc/test_network_opt_plus.py +6 -6
- most_queue/rand_distribution.py +27 -22
- 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 +10 -5
- most_queue/sim/fork_join.py +1 -1
- most_queue/sim/fork_join_delta.py +3 -5
- most_queue/sim/negative.py +21 -17
- most_queue/sim/networks/base_network_sim.py +103 -0
- most_queue/sim/networks/network.py +85 -50
- most_queue/sim/networks/priority_network.py +124 -88
- most_queue/sim/priority.py +83 -76
- most_queue/sim/utils/distribution_utils.py +17 -15
- most_queue/sim/utils/servers.py +10 -11
- most_queue/sim/utils/tasks.py +5 -7
- most_queue/sim/vacations.py +27 -8
- most_queue/structs.py +163 -0
- 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 +79 -47
- most_queue/theory/fifo/gi_m_1.py +89 -32
- most_queue/theory/fifo/gi_m_n.py +89 -37
- 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 +101 -49
- most_queue/theory/fifo/mmnr.py +60 -10
- 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 +77 -25
- most_queue/theory/negative/mg1_rcs.py +61 -34
- most_queue/theory/negative/mgn_disaster.py +220 -184
- most_queue/theory/negative/mgn_rcs.py +143 -106
- 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 +68 -29
- most_queue/theory/networks/open_network_prty.py +68 -30
- 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 +59 -6
- most_queue/theory/priority/preemptive/m_ph_n_busy_approx.py +123 -52
- most_queue/theory/priority/preemptive/mg1.py +48 -29
- most_queue/theory/priority/preemptive/{mmn_3cls_busy_approx.py → mm2_3cls_busy_approx.py} +222 -153
- most_queue/theory/priority/preemptive/mmn_2cls_pr_busy_approx.py +181 -113
- most_queue/theory/utils/busy_periods.py +2 -6
- most_queue/theory/utils/conditional.py +3 -10
- most_queue/theory/utils/diff5dots.py +3 -9
- most_queue/theory/utils/flow_sum.py +2 -10
- 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 +3 -15
- most_queue/theory/utils/student_stat.py +1 -5
- most_queue/theory/utils/transforms.py +1 -3
- most_queue/theory/utils/utilization_approx.py +4 -1
- most_queue/theory/vacations/m_h2_h2warm.py +184 -139
- most_queue/theory/vacations/mg1_warm_calc.py +71 -18
- most_queue/theory/vacations/mgn_with_h2_delay_cold_warm.py +157 -119
- most_queue/theory/vacations/mmn_with_h2_cold_and_h2_warmup.py +257 -191
- {most_queue-1.63.dist-info → most_queue-2.1.dist-info}/METADATA +8 -8
- most_queue-2.1.dist-info/RECORD +109 -0
- most_queue-1.63.dist-info/RECORD +0 -104
- {most_queue-1.63.dist-info → most_queue-2.1.dist-info}/WHEEL +0 -0
- {most_queue-1.63.dist-info → most_queue-2.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -8,10 +8,14 @@ from dataclasses import dataclass
|
|
|
8
8
|
|
|
9
9
|
import numpy as np
|
|
10
10
|
|
|
11
|
-
from most_queue.general.distribution_params import (
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
from most_queue.general.distribution_params import (
|
|
12
|
+
Cox2Params,
|
|
13
|
+
ErlangParams,
|
|
14
|
+
GammaParams,
|
|
15
|
+
H2Params,
|
|
16
|
+
ParetoParams,
|
|
17
|
+
WeibullParams,
|
|
18
|
+
)
|
|
15
19
|
|
|
16
20
|
|
|
17
21
|
@dataclass
|
|
@@ -117,8 +121,7 @@ def fit_h2_clx(moments: list[float], fitting_params: FittingParams | None = None
|
|
|
117
121
|
if math.fabs(coev.real - 1.0 / math.sqrt(2.0)) < fitting_params.ee:
|
|
118
122
|
if fitting_params.verbose:
|
|
119
123
|
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}."
|
|
124
|
+
f"H2 is close to E2. Multiply moments to (1+je)" f"coev = {coev:5.3f}, e = {fitting_params.e:5.3f}."
|
|
122
125
|
)
|
|
123
126
|
f = []
|
|
124
127
|
for i, mom in enumerate(moments):
|
|
@@ -151,10 +154,7 @@ def fit_cox(moments: list[float], fitting_params: FittingParams | None = None) -
|
|
|
151
154
|
coev = cmath.sqrt(moments[1] - moments[0] ** 2) / moments[0]
|
|
152
155
|
if abs(moments[1] - moments[0] * moments[0]) < fitting_params.ee:
|
|
153
156
|
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
|
-
)
|
|
157
|
+
print(f"Cox special 1. Multiply moments to (1+je)" f"coev = {coev:5.3f} e = {fitting_params.e:5.3f}.")
|
|
158
158
|
f = []
|
|
159
159
|
for i, mom in enumerate(moments):
|
|
160
160
|
f.append(mom * complex(1, (i + 1) * fitting_params.e))
|
|
@@ -176,9 +176,7 @@ def fit_cox(moments: list[float], fitting_params: FittingParams | None = None) -
|
|
|
176
176
|
for i in range(3):
|
|
177
177
|
f[i] = moments[i] / math.factorial(i + 1)
|
|
178
178
|
|
|
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
|
-
)
|
|
179
|
+
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
180
|
mu2 = f[0] * f[1] - f[2] + cmath.sqrt(d)
|
|
183
181
|
mu2 /= 2.0 * (np.power(f[1], 2) - f[0] * f[2])
|
|
184
182
|
mu1 = (mu2 * f[0] - 1.0) / (mu2 * f[1] - f[0])
|
|
@@ -287,9 +285,7 @@ def fit_gamma(moments: list[float]) -> GammaParams:
|
|
|
287
285
|
else:
|
|
288
286
|
B.append(moments[i - 1])
|
|
289
287
|
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
|
-
)
|
|
288
|
+
A[i].append(calc_gamma_func(alpha + i + j) / (pow(mu, i + j) * calc_gamma_func(alpha)))
|
|
293
289
|
g = np.linalg.solve(A, B)
|
|
294
290
|
return GammaParams(mu=mu, alpha=alpha, g=g)
|
|
295
291
|
|
|
@@ -311,14 +307,10 @@ def fit_weibull(moments: list[float]) -> WeibullParams:
|
|
|
311
307
|
a = moments[1] / (moments[0] * moments[0])
|
|
312
308
|
u0 = math.log(2 * a) / (2.0 * math.log(2))
|
|
313
309
|
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
|
-
)
|
|
310
|
+
u1 = (1.0 / (2 * math.log(2))) * math.log(a * math.sqrt(math.pi) * math.gamma(u0 + 1) / math.gamma(u0 + 0.5))
|
|
317
311
|
delta = u1 - u0
|
|
318
312
|
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
|
-
)
|
|
313
|
+
u1 = (1.0 / (2 * math.log(2))) * math.log(a * math.sqrt(math.pi) * math.gamma(u0 + 1) / math.gamma(u0 + 0.5))
|
|
322
314
|
delta = u1 - u0
|
|
323
315
|
u0 = u1
|
|
324
316
|
k = 1 / u1
|
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).
|
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}")
|
|
@@ -55,11 +55,7 @@ if __name__ == "__main__":
|
|
|
55
55
|
print("{0:^3s}|{1:^15s}|{2:^15s}|{3:^15s}".format("№", "Реал", "Gamma", "H2"))
|
|
56
56
|
print("-" * 50)
|
|
57
57
|
for i in range(3):
|
|
58
|
-
print(
|
|
59
|
-
"{0:^4d}|{1:^15.3g}|{2:^15.3g}|{3:^15.3g}".format(
|
|
60
|
-
i + 1, b[i], b_approx_gamma[i], b_approx_h2[i]
|
|
61
|
-
)
|
|
62
|
-
)
|
|
58
|
+
print("{0:^4d}|{1:^15.3g}|{2:^15.3g}|{3:^15.3g}".format(i + 1, b[i], b_approx_gamma[i], b_approx_h2[i]))
|
|
63
59
|
|
|
64
60
|
dots_num = 10000
|
|
65
61
|
|
most_queue/misc/calc_v_pls.py
CHANGED
|
@@ -24,16 +24,11 @@ class MGnNegativeRCSCalc(MGnCalc):
|
|
|
24
24
|
def __init__(
|
|
25
25
|
self,
|
|
26
26
|
n: int,
|
|
27
|
-
l_pos: float,
|
|
28
|
-
l_neg: float,
|
|
29
|
-
b: list[float],
|
|
30
27
|
buffer: int | None = None,
|
|
31
28
|
calc_params: TakahashiTakamiParams | None = None,
|
|
32
29
|
):
|
|
33
30
|
"""
|
|
34
31
|
n: number of servers
|
|
35
|
-
l: arrival rate of positive jobs
|
|
36
|
-
l_neg: arrival rate of negative jobs
|
|
37
32
|
b: initial moments of service time distribution
|
|
38
33
|
buffer: size of the buffer (optional)
|
|
39
34
|
N: number of levels in the system (default is 150)
|
|
@@ -42,9 +37,29 @@ class MGnNegativeRCSCalc(MGnCalc):
|
|
|
42
37
|
verbose: whether to print intermediate results (default is False)
|
|
43
38
|
"""
|
|
44
39
|
|
|
40
|
+
super().__init__(n=n, buffer=buffer, calc_params=calc_params)
|
|
41
|
+
|
|
42
|
+
self.l_pos = None
|
|
43
|
+
self.l_neg = None
|
|
44
|
+
self.b = None
|
|
45
|
+
|
|
46
|
+
def set_sources(self, l_pos: float, l_neg: float): # pylint: disable=arguments-differ
|
|
47
|
+
"""
|
|
48
|
+
Set the arrival rates of positive and negative jobs
|
|
49
|
+
:param l_pos: arrival rate of positive jobs
|
|
50
|
+
:param l_neg: arrival rate of negative jobs
|
|
51
|
+
"""
|
|
52
|
+
self.l_pos = l_pos
|
|
45
53
|
self.l_neg = l_neg
|
|
54
|
+
self.is_sources_set = True
|
|
46
55
|
|
|
47
|
-
|
|
56
|
+
def set_servers(self, b: list[float]): # pylint: disable=arguments-differ
|
|
57
|
+
"""
|
|
58
|
+
Set the initial moments of service time distribution
|
|
59
|
+
:param b: initial moments of service time distribution
|
|
60
|
+
"""
|
|
61
|
+
self.b = b
|
|
62
|
+
self.is_servers_set = True
|
|
48
63
|
|
|
49
64
|
def get_q(self) -> float:
|
|
50
65
|
"""
|
|
@@ -150,9 +165,7 @@ class MGnNegativeRCSCalc(MGnCalc):
|
|
|
150
165
|
a = np.array(
|
|
151
166
|
[
|
|
152
167
|
lst_exp(
|
|
153
|
-
key_numbers[j][0] * self.mu[0]
|
|
154
|
-
+ key_numbers[j][1] * self.mu[1]
|
|
155
|
-
+ self.l_neg,
|
|
168
|
+
key_numbers[j][0] * self.mu[0] + key_numbers[j][1] * self.mu[1] + self.l_neg,
|
|
156
169
|
s,
|
|
157
170
|
)
|
|
158
171
|
for j in range(k + 2)
|
|
@@ -241,7 +254,8 @@ class MGnNegativeRCSCalc(MGnCalc):
|
|
|
241
254
|
"""
|
|
242
255
|
w = self.get_w(derivate=False)
|
|
243
256
|
|
|
244
|
-
# serving = min(H2_b, exp(l_neg)) = H2(y1=y1, mu1 = mu1+l_neg,
|
|
257
|
+
# serving = min(H2_b, exp(l_neg)) = H2(y1=y1, mu1 = mu1+l_neg,
|
|
258
|
+
# mu2=mu2+l_neg)
|
|
245
259
|
|
|
246
260
|
params = H2Params(p1=self.y[0], mu1=self.mu[0], mu2=self.mu[1])
|
|
247
261
|
#
|
|
@@ -249,9 +263,7 @@ class MGnNegativeRCSCalc(MGnCalc):
|
|
|
249
263
|
for i in range(1, self.n):
|
|
250
264
|
l_neg += self.p[i] * self.l_neg / i
|
|
251
265
|
|
|
252
|
-
b = H2Distribution.calc_theory_moments(
|
|
253
|
-
H2Params(p1=params.p1, mu1=l_neg + params.mu1, mu2=l_neg + params.mu2)
|
|
254
|
-
)
|
|
266
|
+
b = H2Distribution.calc_theory_moments(H2Params(p1=params.p1, mu1=l_neg + params.mu1, mu2=l_neg + params.mu2))
|
|
255
267
|
|
|
256
268
|
return conv_moments(w, b)
|
|
257
269
|
|
|
@@ -300,9 +312,7 @@ class MGnNegativeRCSCalc(MGnCalc):
|
|
|
300
312
|
right = self.l_neg * i / (num - 1)
|
|
301
313
|
left_from_next = self.l_neg * (i + 1) / (num - 1)
|
|
302
314
|
|
|
303
|
-
output[i, i] = ((num - i - 1) * self.mu[0] + left) * self.y[0] + (
|
|
304
|
-
i * self.mu[1] + right
|
|
305
|
-
) * self.y[1]
|
|
315
|
+
output[i, i] = ((num - i - 1) * self.mu[0] + left) * self.y[0] + (i * self.mu[1] + right) * self.y[1]
|
|
306
316
|
|
|
307
317
|
if i != num - 1:
|
|
308
318
|
output[i, i + 1] = ((num - i - 1) * self.mu[0] + left) * self.y[1]
|
|
@@ -81,7 +81,9 @@ def test_fj_calc():
|
|
|
81
81
|
# расчет средних времен пребывания с помощью аппроксимаций. \
|
|
82
82
|
# На вход каждого из методов - l, mu, nn (число каналов СМО)
|
|
83
83
|
|
|
84
|
-
calcs = ForkJoinMarkovianCalc(
|
|
84
|
+
calcs = ForkJoinMarkovianCalc(n=nn)
|
|
85
|
+
calcs.set_sources(l=l)
|
|
86
|
+
calcs.set_servers(mu=mu)
|
|
85
87
|
|
|
86
88
|
v_varki.append(calcs.get_v1_fj_varki_merchant())
|
|
87
89
|
v_varma.append(calcs.get_v1_fj_varma())
|
most_queue/misc/flow_sum.py
CHANGED
|
@@ -26,7 +26,8 @@ def test():
|
|
|
26
26
|
# число суммируемых потоков
|
|
27
27
|
ns = [x + 2 for x in range(n_nums - 1)]
|
|
28
28
|
|
|
29
|
-
# начальные моменты суммируемых потоков. В нашем случае все потоки
|
|
29
|
+
# начальные моменты суммируемых потоков. В нашем случае все потоки
|
|
30
|
+
# одинаково распределены
|
|
30
31
|
a = []
|
|
31
32
|
for i in range(n_nums):
|
|
32
33
|
params1 = GammaDistribution.get_params_by_mean_and_coev(mean, coev)
|
|
@@ -53,11 +54,7 @@ def test():
|
|
|
53
54
|
errors_coev = []
|
|
54
55
|
|
|
55
56
|
str_f = "{0:^18s}|{1:^10.3f}|{2:^10.3f}|{3:^10.3f}|{4:^10.3f}|{5:^10.3f}"
|
|
56
|
-
print(
|
|
57
|
-
"{0:^18s}|{1:^10s}|{2:^10s}|{3:^10s}|{4:^10s}|{5:^10s}".format(
|
|
58
|
-
"-", "a1", "a2", "a3", "a4", "coev"
|
|
59
|
-
)
|
|
60
|
-
)
|
|
57
|
+
print("{0:^18s}|{1:^10s}|{2:^10s}|{3:^10s}|{4:^10s}|{5:^10s}".format("-", "a1", "a2", "a3", "a4", "coev"))
|
|
61
58
|
print("-" * 80)
|
|
62
59
|
|
|
63
60
|
for i in range(n_nums - 1):
|
|
@@ -9,12 +9,18 @@ import time
|
|
|
9
9
|
import numpy as np
|
|
10
10
|
|
|
11
11
|
from most_queue.misc.vacations_paper_utils import (
|
|
12
|
-
calc_moments_by_mean_and_coev,
|
|
13
|
-
|
|
12
|
+
calc_moments_by_mean_and_coev,
|
|
13
|
+
dump_stat,
|
|
14
|
+
load_stat,
|
|
15
|
+
make_plot,
|
|
16
|
+
print_table,
|
|
17
|
+
)
|
|
14
18
|
from most_queue.rand_distribution import GammaDistribution
|
|
15
19
|
from most_queue.sim.vacations import VacationQueueingSystemSimulator
|
|
16
|
-
from most_queue.theory.vacations.mgn_with_h2_delay_cold_warm import
|
|
17
|
-
MGnH2ServingColdWarmDelay
|
|
20
|
+
from most_queue.theory.vacations.mgn_with_h2_delay_cold_warm import (
|
|
21
|
+
MGnH2ServingColdWarmDelay,
|
|
22
|
+
TakahashiTakamiParams,
|
|
23
|
+
)
|
|
18
24
|
|
|
19
25
|
|
|
20
26
|
def get_sim_stat(stat, n, l, buff, b, b_c, b_w, b_d, num_of_jobs, p_limit, sim_ave):
|
|
@@ -113,18 +119,12 @@ def get_tt_stat(stat, n, l, buff, b, b_c, b_w, b_d, p_limit, w_pls_dt, stable_w_
|
|
|
113
119
|
:return: None
|
|
114
120
|
"""
|
|
115
121
|
tt_start = time.process_time()
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
n,
|
|
123
|
-
buffer=buff,
|
|
124
|
-
verbose=verbose,
|
|
125
|
-
w_pls_dt=w_pls_dt,
|
|
126
|
-
stable_w_pls=stable_w_pls,
|
|
127
|
-
)
|
|
122
|
+
|
|
123
|
+
tt_params = TakahashiTakamiParams(verbose=verbose, w_pls_dt=w_pls_dt, stable_w_pls=stable_w_pls)
|
|
124
|
+
tt = MGnH2ServingColdWarmDelay(n=n, buffer=buff, calc_params=tt_params)
|
|
125
|
+
|
|
126
|
+
tt.set_sources(l=l)
|
|
127
|
+
tt.set_servers(b=b, b_warm=b_w, b_cold=b_c, b_cold_delay=b_d)
|
|
128
128
|
|
|
129
129
|
tt.run()
|
|
130
130
|
p_tt = tt.get_p()
|
most_queue/misc/test_fj_delta.py
CHANGED
|
@@ -46,16 +46,16 @@ def test_fj_delta():
|
|
|
46
46
|
|
|
47
47
|
b_params = GammaDistribution.get_params_by_mean_and_coev(SERVICE_TIME_AVERAGE, SERVICE_TIME_CV)
|
|
48
48
|
|
|
49
|
-
delta_params = GammaDistribution.get_params_by_mean_and_coev(
|
|
50
|
-
SERVICE_TIME_DELTA_AVERAGE, SERVICE_TIME_CV
|
|
51
|
-
)
|
|
49
|
+
delta_params = GammaDistribution.get_params_by_mean_and_coev(SERVICE_TIME_DELTA_AVERAGE, SERVICE_TIME_CV)
|
|
52
50
|
b_delta = GammaDistribution.calc_theory_moments(delta_params)
|
|
53
51
|
b = GammaDistribution.calc_theory_moments(b_params)
|
|
54
52
|
|
|
55
|
-
sj_delta = SplitJoinCalc(
|
|
53
|
+
sj_delta = SplitJoinCalc(n=NUM_OF_CHANNELS)
|
|
54
|
+
sj_delta.set_sources(l=ARRIVAL_RATE)
|
|
55
|
+
sj_delta.set_servers(b=b)
|
|
56
56
|
|
|
57
57
|
v_num = sj_delta.get_v_delta(b_delta)
|
|
58
|
-
|
|
58
|
+
utilization = sj_delta.get_utilization()
|
|
59
59
|
|
|
60
60
|
qs = ForkJoinSimDelta(NUM_OF_CHANNELS, NUM_OF_CHANNELS, b_delta, True)
|
|
61
61
|
|
|
@@ -68,16 +68,14 @@ def test_fj_delta():
|
|
|
68
68
|
print(f"{'Split-Join QS with service start delay':^60s}")
|
|
69
69
|
print("-" * 60)
|
|
70
70
|
print(f"Coefficient of variation of service time: {SERVICE_TIME_CV}")
|
|
71
|
-
print(f"Average delay before service start: {SERVICE_TIME_DELTA_AVERAGE:.3f}")
|
|
71
|
+
print(f"Average delay before service start: { SERVICE_TIME_DELTA_AVERAGE:.3f}")
|
|
72
72
|
print(f"Coefficient of variation of delay: {SERVICE_TIME_CV:.3f}")
|
|
73
|
-
print(f"Utilization coefficient: {
|
|
73
|
+
print(f"Utilization coefficient: {utilization:.3f}")
|
|
74
74
|
|
|
75
75
|
times_print(v_sim, v_num, is_w=False)
|
|
76
76
|
|
|
77
77
|
assert len(v_sim) == len(v_num)
|
|
78
|
-
assert np.allclose(
|
|
79
|
-
np.array(v_sim), np.array(v_num), rtol=MOMENTS_RTOL, atol=MOMENTS_ATOL
|
|
80
|
-
), ERROR_MSG
|
|
78
|
+
assert np.allclose(np.array(v_sim), np.array(v_num), rtol=MOMENTS_RTOL, atol=MOMENTS_ATOL), ERROR_MSG
|
|
81
79
|
|
|
82
80
|
|
|
83
81
|
if __name__ == "__main__":
|
|
@@ -5,8 +5,8 @@ Test the NetworkOptimizerWithApprox class.
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
|
|
7
7
|
from most_queue.rand_distribution import ExpDistribution
|
|
8
|
-
from most_queue.theory.networks.
|
|
9
|
-
|
|
8
|
+
from most_queue.theory.networks.open_network import OpenNetworkCalc
|
|
9
|
+
from most_queue.theory.networks.opt.transition_approx import NetworkOptimizerWithApprox
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def test_network_opt_approx():
|
|
@@ -34,11 +34,12 @@ def test_network_opt_approx():
|
|
|
34
34
|
ExpDistribution.calc_theory_moments(1.0) for _m in range(num_of_nodes)
|
|
35
35
|
] # List of service time moments for each node
|
|
36
36
|
|
|
37
|
+
network = OpenNetworkCalc()
|
|
38
|
+
network.set_sources(R=transition_mrx, arrival_rate=arrival_rate)
|
|
39
|
+
network.set_nodes(b=service_times, n=num_of_channels)
|
|
40
|
+
|
|
37
41
|
optimizer = NetworkOptimizerWithApprox(
|
|
38
|
-
|
|
39
|
-
arrival_rate=arrival_rate,
|
|
40
|
-
b=service_times,
|
|
41
|
-
num_channels=num_of_channels,
|
|
42
|
+
network=network,
|
|
42
43
|
maximum_rates_to_end=max_ends,
|
|
43
44
|
is_service_markovian=True,
|
|
44
45
|
verbose=True,
|
|
@@ -5,8 +5,8 @@ Test the NetworkOptimizerPlus class.
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
|
|
7
7
|
from most_queue.rand_distribution import ExpDistribution
|
|
8
|
-
from most_queue.theory.networks.
|
|
9
|
-
|
|
8
|
+
from most_queue.theory.networks.open_network import OpenNetworkCalc
|
|
9
|
+
from most_queue.theory.networks.opt.transition_plus import NetworkOptimizerPlus, Strategy
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def test_network_opt_plus():
|
|
@@ -42,11 +42,11 @@ def test_network_opt_plus():
|
|
|
42
42
|
Strategy.TOP_K,
|
|
43
43
|
Strategy.ALL,
|
|
44
44
|
]:
|
|
45
|
+
network = OpenNetworkCalc()
|
|
46
|
+
network.set_sources(R=transition_mrx, arrival_rate=arrival_rate)
|
|
47
|
+
network.set_nodes(b=service_times, n=num_of_channels)
|
|
45
48
|
optimizer = NetworkOptimizerPlus(
|
|
46
|
-
|
|
47
|
-
arrival_rate=arrival_rate,
|
|
48
|
-
b=service_times,
|
|
49
|
-
num_channels=num_of_channels,
|
|
49
|
+
network=network,
|
|
50
50
|
maximum_rates_to_end=max_ends,
|
|
51
51
|
is_service_markovian=True,
|
|
52
52
|
verbose=False,
|
most_queue/rand_distribution.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# pylint: disable=too-many-lines
|
|
1
2
|
"""
|
|
2
3
|
Random distributions for simulation.
|
|
3
4
|
"""
|
|
@@ -9,15 +10,28 @@ import scipy.special as sp
|
|
|
9
10
|
from scipy import stats
|
|
10
11
|
|
|
11
12
|
from most_queue.general.distribution_fitting import (
|
|
12
|
-
FittingParams,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
FittingParams,
|
|
14
|
+
calc_gamma_func,
|
|
15
|
+
fit_cox,
|
|
16
|
+
fit_erlang,
|
|
17
|
+
fit_gamma,
|
|
18
|
+
fit_h2,
|
|
19
|
+
fit_h2_clx,
|
|
20
|
+
fit_pareto_by_mean_and_coev,
|
|
21
|
+
fit_pareto_moments,
|
|
22
|
+
fit_weibull,
|
|
23
|
+
gamma_moments_by_mean_and_coev,
|
|
24
|
+
)
|
|
25
|
+
from most_queue.general.distribution_params import (
|
|
26
|
+
Cox2Params,
|
|
27
|
+
ErlangParams,
|
|
28
|
+
GammaParams,
|
|
29
|
+
GaussianParams,
|
|
30
|
+
H2Params,
|
|
31
|
+
ParetoParams,
|
|
32
|
+
UniformParams,
|
|
33
|
+
WeibullParams,
|
|
34
|
+
)
|
|
21
35
|
from most_queue.general.interfaces import Distribution
|
|
22
36
|
|
|
23
37
|
|
|
@@ -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
|
|
@@ -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.
|
|
@@ -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
|
most_queue/sim/base.py
CHANGED
|
@@ -8,13 +8,13 @@ import numpy as np
|
|
|
8
8
|
from colorama import Fore, Style, init
|
|
9
9
|
from tqdm import tqdm
|
|
10
10
|
|
|
11
|
-
from most_queue.sim.utils.distribution_utils import
|
|
12
|
-
create_distribution)
|
|
11
|
+
from most_queue.sim.utils.distribution_utils import calc_qs_load, create_distribution
|
|
13
12
|
from most_queue.sim.utils.exceptions import QsWrongQueueTypeException
|
|
14
13
|
from most_queue.sim.utils.qs_queue import QsQueueDeque, QsQueueList
|
|
15
14
|
from most_queue.sim.utils.servers import Server
|
|
16
15
|
from most_queue.sim.utils.stats_update import refresh_moments_stat
|
|
17
16
|
from most_queue.sim.utils.tasks import Task
|
|
17
|
+
from most_queue.structs import QueueResults
|
|
18
18
|
|
|
19
19
|
init()
|
|
20
20
|
|
|
@@ -285,7 +285,7 @@ class QsSim:
|
|
|
285
285
|
# Arrival
|
|
286
286
|
self.arrival()
|
|
287
287
|
|
|
288
|
-
def run(self, total_served
|
|
288
|
+
def run(self, total_served) -> QueueResults:
|
|
289
289
|
"""
|
|
290
290
|
Run simulation process
|
|
291
291
|
"""
|
|
@@ -293,34 +293,34 @@ class QsSim:
|
|
|
293
293
|
|
|
294
294
|
print(Fore.GREEN + "\rStart simulation")
|
|
295
295
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
last_percent = 0
|
|
299
|
-
|
|
300
|
-
with tqdm(total=100) as pbar:
|
|
301
|
-
while self.served < total_served:
|
|
302
|
-
self.run_one_step()
|
|
303
|
-
percent = int(100 * (self.served / total_served))
|
|
304
|
-
if last_percent != percent:
|
|
305
|
-
last_percent = percent
|
|
306
|
-
pbar.update(1)
|
|
307
|
-
pbar.set_description(
|
|
308
|
-
Fore.MAGENTA
|
|
309
|
-
+ "\rJob served: "
|
|
310
|
-
+ Fore.YELLOW
|
|
311
|
-
+ f"{self.served}/{total_served}"
|
|
312
|
-
+ Fore.LIGHTGREEN_EX
|
|
313
|
-
)
|
|
296
|
+
last_percent = 0
|
|
314
297
|
|
|
315
|
-
|
|
316
|
-
|
|
298
|
+
with tqdm(total=100) as pbar:
|
|
299
|
+
while self.served < total_served:
|
|
317
300
|
self.run_one_step()
|
|
301
|
+
percent = int(100 * (self.served / total_served))
|
|
302
|
+
if last_percent != percent:
|
|
303
|
+
last_percent = percent
|
|
304
|
+
pbar.update(1)
|
|
305
|
+
pbar.set_description(
|
|
306
|
+
Fore.MAGENTA
|
|
307
|
+
+ "\rJob served: "
|
|
308
|
+
+ Fore.YELLOW
|
|
309
|
+
+ f"{self.served}/{total_served}"
|
|
310
|
+
+ Fore.LIGHTGREEN_EX
|
|
311
|
+
)
|
|
318
312
|
|
|
319
313
|
print(Fore.GREEN + "\rSimulation is finished")
|
|
320
314
|
print(Style.RESET_ALL)
|
|
321
315
|
|
|
316
|
+
v = self.get_v()
|
|
317
|
+
w = self.get_w()
|
|
318
|
+
p = self.get_p()
|
|
319
|
+
|
|
322
320
|
self.time_spent = time.process_time() - start
|
|
323
321
|
|
|
322
|
+
return QueueResults(v=v, w=w, p=p, duration=self.time_spent, utilization=self.calc_load())
|
|
323
|
+
|
|
324
324
|
def refresh_busy_stat(self, new_a):
|
|
325
325
|
"""
|
|
326
326
|
Updating statistics of the busy period
|
|
@@ -366,14 +366,7 @@ class QsSim:
|
|
|
366
366
|
|
|
367
367
|
def __str__(self, is_short=False):
|
|
368
368
|
|
|
369
|
-
res = (
|
|
370
|
-
"Queueing system "
|
|
371
|
-
+ self.source_kendall_notation
|
|
372
|
-
+ "/"
|
|
373
|
-
+ self.server_kendall_notation
|
|
374
|
-
+ "/"
|
|
375
|
-
+ str(self.n)
|
|
376
|
-
)
|
|
369
|
+
res = "Queueing system " + self.source_kendall_notation + "/" + self.server_kendall_notation + "/" + str(self.n)
|
|
377
370
|
if self.buffer is not None:
|
|
378
371
|
res += "/" + str(self.buffer)
|
|
379
372
|
res += f"\nLoad: {self.calc_load():4.3f}\n"
|
most_queue/sim/batch.py
CHANGED
|
@@ -13,7 +13,9 @@ class QueueingSystemBatchSim(QsSim):
|
|
|
13
13
|
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
-
def __init__(
|
|
16
|
+
def __init__(
|
|
17
|
+
self, num_of_channels, batch_prob, buffer=None, verbose=True, buffer_type="list"
|
|
18
|
+
): # pylint: disable=too-many-positional-arguments, too-many-arguments
|
|
17
19
|
"""
|
|
18
20
|
:param num_of_channels: int : number of channels (servers)
|
|
19
21
|
:param batch_prob: list : probabilities for different batch sizes
|
most_queue/sim/finite_source.py
CHANGED
|
@@ -23,7 +23,7 @@ class QueueingFiniteSourceSim(QsSim):
|
|
|
23
23
|
buffer=None,
|
|
24
24
|
verbose=True,
|
|
25
25
|
buffer_type="list",
|
|
26
|
-
):
|
|
26
|
+
): # pylint: disable=too-many-positional-arguments, too-many-arguments
|
|
27
27
|
"""
|
|
28
28
|
num_of_channels - number of channels in the system.
|
|
29
29
|
number_of_sources - number of sources.
|