most-queue 1.45__tar.gz → 1.47__tar.gz
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-1.45 → most_queue-1.47}/PKG-INFO +6 -3
- {most_queue-1.45 → most_queue-1.47}/README.md +1 -1
- {most_queue-1.45 → most_queue-1.47}/most_queue/sim/batch_sim.py +8 -8
- {most_queue-1.45 → most_queue-1.47}/most_queue/sim/fj_delta_sim.py +37 -23
- {most_queue-1.45 → most_queue-1.47}/most_queue/sim/fj_sim.py +47 -32
- {most_queue-1.45 → most_queue-1.47}/most_queue/sim/impatient_queue_sim.py +71 -30
- most_queue-1.47/most_queue/sim/priority_network.py +228 -0
- most_queue-1.47/most_queue/sim/priority_queue_sim.py +725 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/sim/qs_sim.py +53 -40
- most_queue-1.47/most_queue/sim/queue_finite_source_sim.py +244 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/sim/utils/distribution_utils.py +30 -0
- most_queue-1.47/most_queue/sim/utils/servers.py +219 -0
- most_queue-1.47/most_queue/sim/utils/tasks.py +117 -0
- {most_queue-1.45/most_queue/tests → most_queue-1.47/most_queue/theory}/__init__.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/batch_mm1.py +4 -6
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/ek_d_n_calc.py +53 -43
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/mmn3_pnz_cox_approx.py +2 -2
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/priority_calc.py +8 -8
- {most_queue-1.45/most_queue/theory → most_queue-1.47/most_queue/theory/utils}/__init__.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/utils/passage_time.py +5 -5
- {most_queue-1.45 → most_queue-1.47}/most_queue.egg-info/PKG-INFO +6 -3
- {most_queue-1.45 → most_queue-1.47}/most_queue.egg-info/SOURCES.txt +23 -23
- {most_queue-1.45 → most_queue-1.47}/most_queue.egg-info/top_level.txt +1 -0
- {most_queue-1.45 → most_queue-1.47}/pyproject.toml +1 -1
- {most_queue-1.45 → most_queue-1.47}/setup.py +10 -9
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_fj_delta.py +1 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_impatience.py +1 -3
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_network_im_prty.py +1 -1
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_qs_sim_prty.py +2 -4
- most_queue-1.45/most_queue/sim/priority_network.py +0 -167
- most_queue-1.45/most_queue/sim/priority_queue_sim.py +0 -785
- most_queue-1.45/most_queue/sim/queue_finite_source_sim.py +0 -247
- most_queue-1.45/most_queue/sim/utils/servers.py +0 -113
- most_queue-1.45/most_queue/sim/utils/tasks.py +0 -70
- {most_queue-1.45 → most_queue-1.47}/LICENSE +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/__init__.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/general_utils/__init__.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/general_utils/approx_cdf_make.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/general_utils/conv.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/general_utils/tables.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/general_utils/vacations_paper_utils.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/rand_distribution.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/sim/__init__.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/sim/flow_sum_sim.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/sim/utils/__init__.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/sim/utils/exceptions.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/sim/utils/phase.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/sim/utils/qs_queue.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/sim/utils/stats_update.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/engset_model.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/fj_calc.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/gi_m_1_calc.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/gi_m_n_calc.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/impatience_calc.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/m_d_n_calc.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/m_h2_h2warm.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/m_ph_n_prty.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/mg1_calc.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/mg1_warm_calc.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/mgn_tt.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/mgn_with_h2_delay_cold_warm.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/mmn_prty_pnz_approx.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/mmn_with_h2_cold_and_h2_warmup.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/mmnr_calc.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/network_calc.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/network_viewer.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/utils/binom_probs.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/utils/diff5dots.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/utils/flow_sum.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/utils/q_poisson_arrival_calc.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/utils/student_stat.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue/theory/utils/weibull.py +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue.egg-info/dependency_links.txt +0 -0
- {most_queue-1.45 → most_queue-1.47}/most_queue.egg-info/not-zip-safe +0 -0
- {most_queue-1.45 → most_queue-1.47}/setup.cfg +0 -0
- {most_queue-1.45/most_queue/theory/utils → most_queue-1.47/tests}/__init__.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_batch.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_ek_d_n.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_engset.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_fj_im.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_gi_m_1_calc.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_gi_m_n_calc.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_m_d_n_calc.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_m_h2_h2warm.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_m_ph_n_prty.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_mg1_calc.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_mgn_tt.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_mgn_with_h2_delay_cold_warm.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_mmn3_pnz_cox_approx.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_mmn_h2cold_h2warm.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_mmn_prty_pnz_approx.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_qs_sim_test.py +0 -0
- {most_queue-1.45/most_queue → most_queue-1.47}/tests/test_queue_types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: most_queue
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.47
|
|
4
4
|
Summary: Software package for calculation and simulation of queuing systems
|
|
5
5
|
Home-page: https://github.com/xabarov/most-queue
|
|
6
6
|
Author: Xabarov Roman
|
|
@@ -31,8 +31,11 @@ Classifier: Operating System :: OS Independent
|
|
|
31
31
|
Requires-Python: >=3.7
|
|
32
32
|
Description-Content-Type: text/markdown
|
|
33
33
|
License-File: LICENSE
|
|
34
|
+
Dynamic: author
|
|
35
|
+
Dynamic: home-page
|
|
36
|
+
Dynamic: license-file
|
|
34
37
|
|
|
35
|
-
#
|
|
38
|
+
# Queueing systems. Simulation and numerical methods of queuing theory
|
|
36
39
|
|
|
37
40
|

|
|
38
41
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Queueing system with batch arrivals.
|
|
3
3
|
"""
|
|
4
4
|
import numpy as np
|
|
5
5
|
|
|
@@ -8,17 +8,17 @@ from most_queue.sim.qs_sim import QueueingSystemSimulator, Task
|
|
|
8
8
|
|
|
9
9
|
class QueueingSystemBatchSim(QueueingSystemSimulator):
|
|
10
10
|
"""
|
|
11
|
-
|
|
11
|
+
Queueing system with batch arrivals.
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
def __init__(self, num_of_channels,
|
|
15
15
|
batch_prob,
|
|
16
16
|
buffer=None, verbose=True):
|
|
17
17
|
"""
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
:param num_of_channels: int : number of channels (servers)
|
|
19
|
+
:param batch_prob: list : probabilities for different batch sizes
|
|
20
|
+
:param buffer: Optional(int, None) : length of queueu
|
|
21
|
+
:param verbose: bool : if True prints info about simulation process
|
|
22
22
|
"""
|
|
23
23
|
super().__init__(num_of_channels, buffer, verbose)
|
|
24
24
|
|
|
@@ -52,7 +52,7 @@ class QueueingSystemBatchSim(QueueingSystemSimulator):
|
|
|
52
52
|
|
|
53
53
|
self.arrival_time = self.ttek + self.source.generate()
|
|
54
54
|
|
|
55
|
-
for
|
|
55
|
+
for _tsk in range(batch_size):
|
|
56
56
|
self.arrived += 1
|
|
57
57
|
self.p[self.in_sys] += self.arrival_time - self.t_old
|
|
58
58
|
|
|
@@ -89,5 +89,5 @@ class QueueingSystemBatchSim(QueueingSystemSimulator):
|
|
|
89
89
|
# Проверям, не наступил ли ПНЗ:
|
|
90
90
|
if self.free_channels == 0:
|
|
91
91
|
if self.in_sys == self.n:
|
|
92
|
-
self.
|
|
92
|
+
self.start_busy = self.ttek
|
|
93
93
|
break
|
|
@@ -12,13 +12,16 @@ class ForkJoinSimDelta(ForkJoinSim):
|
|
|
12
12
|
Имитационная модель СМО Fork-Join, Split-Join
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
-
def __init__(self, num_of_channels, num_of_parts, delta,
|
|
15
|
+
def __init__(self, num_of_channels, num_of_parts, delta, is_sj=False, buffer=None):
|
|
16
16
|
"""
|
|
17
|
-
num_of_channels
|
|
18
|
-
|
|
17
|
+
:param num_of_channels: int : количество каналов СМО
|
|
18
|
+
:param num_of_parts: int : количество частей на которые разбивается задача
|
|
19
|
+
:param delta: float : параметр модели Fork-Join с дельта-разбиением
|
|
20
|
+
:param is_sj: bool : если True, то используется модель Split-Join, иначе - Fork-Join
|
|
21
|
+
:param buffer: Optional(int, None) : максимальная длина очереди
|
|
19
22
|
"""
|
|
20
23
|
ForkJoinSim.__init__(self, num_of_channels,
|
|
21
|
-
num_of_parts,
|
|
24
|
+
num_of_parts, is_sj, buffer)
|
|
22
25
|
self.delta = delta
|
|
23
26
|
self.subtask_arr_queue = []
|
|
24
27
|
self.serv_task_id = -1
|
|
@@ -26,7 +29,7 @@ class ForkJoinSimDelta(ForkJoinSim):
|
|
|
26
29
|
|
|
27
30
|
def task_arrival(self):
|
|
28
31
|
"""
|
|
29
|
-
|
|
32
|
+
Действия по прибытию заявки в СМО.
|
|
30
33
|
"""
|
|
31
34
|
|
|
32
35
|
self.arrived += 1
|
|
@@ -37,7 +40,7 @@ class ForkJoinSimDelta(ForkJoinSim):
|
|
|
37
40
|
is_dropped = False
|
|
38
41
|
|
|
39
42
|
if self.buffer: # ограниченная длина очереди
|
|
40
|
-
if not self.
|
|
43
|
+
if not self.is_sj:
|
|
41
44
|
if self.queue.size() + self.k - 1 > self.buffer + self.free_channels:
|
|
42
45
|
self.dropped += 1
|
|
43
46
|
is_dropped = True
|
|
@@ -54,7 +57,7 @@ class ForkJoinSimDelta(ForkJoinSim):
|
|
|
54
57
|
self.in_sys += 1
|
|
55
58
|
self.sub_task_in_sys += 1
|
|
56
59
|
|
|
57
|
-
if not self.
|
|
60
|
+
if not self.is_sj: # Fork-Join discipline
|
|
58
61
|
|
|
59
62
|
if self.free_channels == 0:
|
|
60
63
|
self.queue.append(t.subtasks[0])
|
|
@@ -85,6 +88,9 @@ class ForkJoinSimDelta(ForkJoinSim):
|
|
|
85
88
|
self.subtask_arr_queue.append(t.subtasks[i])
|
|
86
89
|
|
|
87
90
|
def subtask_arrival(self, subtask_num):
|
|
91
|
+
"""
|
|
92
|
+
Действия по прибытию подзадачи в СМО.
|
|
93
|
+
"""
|
|
88
94
|
|
|
89
95
|
subtsk = self.subtask_arr_queue.pop(subtask_num)
|
|
90
96
|
self.p[self.in_sys] += subtsk.future_arr_time - self.t_old
|
|
@@ -99,7 +105,7 @@ class ForkJoinSimDelta(ForkJoinSim):
|
|
|
99
105
|
if not is_dropped:
|
|
100
106
|
self.sub_task_in_sys += 1
|
|
101
107
|
|
|
102
|
-
if not self.
|
|
108
|
+
if not self.is_sj: # Fork-Join discipline
|
|
103
109
|
|
|
104
110
|
if self.free_channels == 0:
|
|
105
111
|
self.queue.append(subtsk)
|
|
@@ -136,7 +142,7 @@ class ForkJoinSimDelta(ForkJoinSim):
|
|
|
136
142
|
self.total += 1
|
|
137
143
|
self.free_channels += 1
|
|
138
144
|
|
|
139
|
-
if not self.
|
|
145
|
+
if not self.is_sj:
|
|
140
146
|
|
|
141
147
|
if self.served_subtask_in_task[end_ts.task_id] == self.k:
|
|
142
148
|
self.served += 1
|
|
@@ -186,6 +192,9 @@ class ForkJoinSimDelta(ForkJoinSim):
|
|
|
186
192
|
q for q in self.queue.queue if q.task_id != end_ts.task_id]
|
|
187
193
|
|
|
188
194
|
def run_one_step(self):
|
|
195
|
+
"""
|
|
196
|
+
Runs one step of simulation.
|
|
197
|
+
"""
|
|
189
198
|
|
|
190
199
|
num_of_server_earlier = -1
|
|
191
200
|
serv_earl = 1e10
|
|
@@ -198,9 +207,9 @@ class ForkJoinSimDelta(ForkJoinSim):
|
|
|
198
207
|
subtask_arr_time_earl = 1e10
|
|
199
208
|
num_of_subtask_earl = -1
|
|
200
209
|
|
|
201
|
-
for c in
|
|
202
|
-
if
|
|
203
|
-
subtask_arr_time_earl =
|
|
210
|
+
for c, subtask in enumerate(self.subtask_arr_queue):
|
|
211
|
+
if subtask.future_arr_time < subtask_arr_time_earl:
|
|
212
|
+
subtask_arr_time_earl = subtask.future_arr_time
|
|
204
213
|
num_of_subtask_earl = c
|
|
205
214
|
|
|
206
215
|
is_task_arr = False
|
|
@@ -219,37 +228,42 @@ class ForkJoinSimDelta(ForkJoinSim):
|
|
|
219
228
|
self.serving(num_of_server_earlier)
|
|
220
229
|
|
|
221
230
|
def __str__(self, is_short=False):
|
|
231
|
+
"""
|
|
232
|
+
Returns string representation of the system
|
|
233
|
+
:param is_short: bool : if True returns short version of string
|
|
234
|
+
:return: str : string representation of the system
|
|
235
|
+
"""
|
|
222
236
|
|
|
223
237
|
res = "Queueing system " + self.source_types + \
|
|
224
238
|
"/" + self.server_types + "/" + str(self.n)
|
|
225
|
-
if self.buffer
|
|
239
|
+
if self.buffer is not None:
|
|
226
240
|
res += "/" + str(self.buffer)
|
|
227
|
-
if self.
|
|
241
|
+
if self.is_sj:
|
|
228
242
|
res += '| Split-Join'
|
|
229
243
|
else:
|
|
230
244
|
res += '| Fork-Join'
|
|
231
245
|
|
|
232
246
|
res += "\n"
|
|
233
247
|
# res += "Load: " + "{0:4.3f}".format(self.calc_load()) + "\n"
|
|
234
|
-
res += "Current Time
|
|
235
|
-
res += "Arrival Time:
|
|
248
|
+
res += f"Current Time {self.ttek:8.3f}\n"
|
|
249
|
+
res += f"Arrival Time: {self.arrival_time:8.3f}\n"
|
|
236
250
|
|
|
237
251
|
res += "Sojourn moments:\n"
|
|
238
252
|
for i in range(3):
|
|
239
|
-
res += "\t
|
|
253
|
+
res += f"\t{self.v[i]:8.4f}"
|
|
240
254
|
res += "\n"
|
|
241
255
|
|
|
242
256
|
if not is_short:
|
|
243
257
|
res += "Stationary prob:\n"
|
|
244
258
|
res += "\t"
|
|
245
259
|
for i in range(10):
|
|
246
|
-
res += "{
|
|
260
|
+
res += f"{self.p[i] / self.ttek:6.5f} "
|
|
247
261
|
res += "\n"
|
|
248
|
-
res += "Arrived:
|
|
249
|
-
if self.buffer
|
|
250
|
-
res += "Dropped:
|
|
251
|
-
res += "Served:
|
|
252
|
-
res += "In System:
|
|
262
|
+
res += f"Arrived: {self.arrived}\n"
|
|
263
|
+
if self.buffer is not None:
|
|
264
|
+
res += f"Dropped: {self.dropped}\n"
|
|
265
|
+
res += f"Served: {self.served}\n"
|
|
266
|
+
res += f"In System: {self.in_sys}\n"
|
|
253
267
|
|
|
254
268
|
for c in range(self.n):
|
|
255
269
|
res += str(self.servers[c])
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
ForkJoin Queue
|
|
3
3
|
"""
|
|
4
4
|
import math
|
|
5
|
-
import sys
|
|
6
5
|
|
|
7
6
|
from colorama import Fore, Style, init
|
|
8
7
|
from tqdm import tqdm
|
|
@@ -15,35 +14,39 @@ init()
|
|
|
15
14
|
|
|
16
15
|
class ForkJoinSim(QueueingSystemSimulator):
|
|
17
16
|
"""
|
|
18
|
-
|
|
17
|
+
Simulation of a ForkJoin Queueing System (Fork-Join, Split-Join)
|
|
19
18
|
"""
|
|
20
19
|
|
|
21
|
-
def __init__(self, num_of_channels, k,
|
|
20
|
+
def __init__(self, num_of_channels, k, is_sj=False, is_purge=False, buffer=None):
|
|
22
21
|
"""
|
|
23
|
-
num_of_channels
|
|
24
|
-
|
|
22
|
+
:param num_of_channels: int : number of channels in the system
|
|
23
|
+
:param k: int : number of parts a task is split into
|
|
24
|
+
:param is_sj: bool : if True, then Split-Join model is used, otherwise Fork-Join model is used
|
|
25
|
+
:param buffer: Optional(int, None) : maximum length of the queue
|
|
26
|
+
:param is_purge: bool : if True, then Purge model is used
|
|
27
|
+
|
|
25
28
|
"""
|
|
26
29
|
QueueingSystemSimulator.__init__(self, num_of_channels, buffer)
|
|
27
30
|
self.k = k
|
|
28
|
-
self.
|
|
29
|
-
self.
|
|
31
|
+
self.is_sj = is_sj
|
|
32
|
+
self.is_purge = is_purge
|
|
30
33
|
self.served_subtask_in_task = {}
|
|
31
34
|
self.sub_task_in_sys = 0
|
|
32
35
|
|
|
33
36
|
self.queues = []
|
|
34
|
-
for
|
|
37
|
+
for _ in range(num_of_channels):
|
|
35
38
|
self.queues.append([])
|
|
36
39
|
|
|
37
40
|
def calc_load(self):
|
|
38
41
|
"""
|
|
39
|
-
|
|
42
|
+
calculates the load of the system.
|
|
40
43
|
"""
|
|
41
44
|
|
|
42
45
|
pass
|
|
43
46
|
|
|
44
47
|
def arrival(self):
|
|
45
48
|
"""
|
|
46
|
-
|
|
49
|
+
action on arrival of a task in the system.
|
|
47
50
|
"""
|
|
48
51
|
|
|
49
52
|
self.arrived += 1
|
|
@@ -55,7 +58,7 @@ class ForkJoinSim(QueueingSystemSimulator):
|
|
|
55
58
|
is_dropped = False
|
|
56
59
|
|
|
57
60
|
if self.buffer: # ограниченная длина очереди
|
|
58
|
-
if not self.
|
|
61
|
+
if not self.is_sj:
|
|
59
62
|
|
|
60
63
|
if self.queue.size() + self.k - 1 > self.buffer + self.free_channels:
|
|
61
64
|
self.dropped += 1
|
|
@@ -71,7 +74,7 @@ class ForkJoinSim(QueueingSystemSimulator):
|
|
|
71
74
|
self.in_sys += 1
|
|
72
75
|
self.sub_task_in_sys += self.n
|
|
73
76
|
|
|
74
|
-
if not self.
|
|
77
|
+
if not self.is_sj: # Fork-Join discipline
|
|
75
78
|
|
|
76
79
|
for i in range(self.n):
|
|
77
80
|
if self.free_channels == 0:
|
|
@@ -96,8 +99,8 @@ class ForkJoinSim(QueueingSystemSimulator):
|
|
|
96
99
|
|
|
97
100
|
def serving(self, c):
|
|
98
101
|
"""
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
Action when a service is completed on channel c.
|
|
103
|
+
:param c: int : number of channel where service is completed.
|
|
101
104
|
"""
|
|
102
105
|
time_to_end = self.servers[c].time_to_end_service
|
|
103
106
|
self.p[self.in_sys] += time_to_end - self.t_old
|
|
@@ -109,11 +112,11 @@ class ForkJoinSim(QueueingSystemSimulator):
|
|
|
109
112
|
self.free_channels += 1
|
|
110
113
|
self.sub_task_in_sys -= 1
|
|
111
114
|
|
|
112
|
-
if not self.
|
|
115
|
+
if not self.is_sj:
|
|
113
116
|
|
|
114
117
|
if self.served_subtask_in_task[end_ts.task_id] == self.k:
|
|
115
118
|
|
|
116
|
-
if self.
|
|
119
|
+
if self.is_purge:
|
|
117
120
|
# найти все остальные подзадачи в СМО и выкинуть
|
|
118
121
|
task_id = end_ts.task_id
|
|
119
122
|
for i in range(self.n):
|
|
@@ -147,6 +150,11 @@ class ForkJoinSim(QueueingSystemSimulator):
|
|
|
147
150
|
self.free_channels -= 1
|
|
148
151
|
|
|
149
152
|
def run_one_step(self):
|
|
153
|
+
"""
|
|
154
|
+
Run one step of the simulation.
|
|
155
|
+
If there is an arrival before the earliest service completion time,
|
|
156
|
+
then process the arrival. Otherwise, process the earliest service completion.
|
|
157
|
+
"""
|
|
150
158
|
|
|
151
159
|
num_of_server_earlier = -1
|
|
152
160
|
serv_earl = 1e10
|
|
@@ -164,12 +172,15 @@ class ForkJoinSim(QueueingSystemSimulator):
|
|
|
164
172
|
self.serving(num_of_server_earlier)
|
|
165
173
|
|
|
166
174
|
def run(self, total_served, is_real_served=True):
|
|
175
|
+
"""
|
|
176
|
+
Run simulation until total_served tasks are served.
|
|
177
|
+
"""
|
|
167
178
|
|
|
168
179
|
if is_real_served:
|
|
169
|
-
|
|
180
|
+
|
|
170
181
|
last_percent = 0
|
|
171
182
|
|
|
172
|
-
with tqdm(total=100
|
|
183
|
+
with tqdm(total=100) as pbar:
|
|
173
184
|
while self.served < total_served:
|
|
174
185
|
self.run_one_step()
|
|
175
186
|
percent = int(100*(self.served/total_served))
|
|
@@ -178,7 +189,7 @@ class ForkJoinSim(QueueingSystemSimulator):
|
|
|
178
189
|
pbar.update(1)
|
|
179
190
|
pbar.set_description(Fore.MAGENTA + '\rJob served: ' +
|
|
180
191
|
Fore.YELLOW + f'{self.served}/{total_served}' + Fore.LIGHTGREEN_EX)
|
|
181
|
-
|
|
192
|
+
|
|
182
193
|
else:
|
|
183
194
|
print(Fore.GREEN + '\rStart simulation')
|
|
184
195
|
print(Style.RESET_ALL)
|
|
@@ -197,8 +208,7 @@ class ForkJoinSim(QueueingSystemSimulator):
|
|
|
197
208
|
|
|
198
209
|
def get_p(self):
|
|
199
210
|
"""
|
|
200
|
-
|
|
201
|
-
p[j] - вероятность того, что в СМО в случайный момент времени будет ровно j заявок
|
|
211
|
+
Get probabilities of states for Fork-Join model
|
|
202
212
|
"""
|
|
203
213
|
res = [0.0] * len(self.p)
|
|
204
214
|
for j in range(0, self.num_of_states):
|
|
@@ -206,37 +216,42 @@ class ForkJoinSim(QueueingSystemSimulator):
|
|
|
206
216
|
return res
|
|
207
217
|
|
|
208
218
|
def __str__(self, is_short=False):
|
|
219
|
+
"""
|
|
220
|
+
Prints the model of the queueing system
|
|
221
|
+
:param is_short: bool : if True, then short information about the model of the queueing system is returned
|
|
222
|
+
:return: str : string representation of the model of the queueing system
|
|
223
|
+
"""
|
|
209
224
|
|
|
210
225
|
res = "Queueing system " + self.source_types + \
|
|
211
226
|
"/" + self.server_types + "/" + str(self.n)
|
|
212
|
-
if self.buffer
|
|
227
|
+
if self.buffer is not None:
|
|
213
228
|
res += "/" + str(self.buffer)
|
|
214
|
-
if self.
|
|
229
|
+
if self.is_sj:
|
|
215
230
|
res += '| Split-Join'
|
|
216
231
|
else:
|
|
217
232
|
res += '| Fork-Join'
|
|
218
233
|
|
|
219
234
|
res += "\n"
|
|
220
235
|
# res += "Load: " + "{0:4.3f}".format(self.calc_load()) + "\n"
|
|
221
|
-
res += "Current Time
|
|
222
|
-
res += "Arrival Time:
|
|
236
|
+
res += f"Current Time {self.ttek:8.3f}\n"
|
|
237
|
+
res += f"Arrival Time: {self.arrival_time:8.3f}\n"
|
|
223
238
|
|
|
224
239
|
res += "Sojourn moments:\n"
|
|
225
240
|
for i in range(3):
|
|
226
|
-
res += "\t
|
|
241
|
+
res += f"\t{self.v[i]:8.4f}"
|
|
227
242
|
res += "\n"
|
|
228
243
|
|
|
229
244
|
if not is_short:
|
|
230
245
|
res += "Stationary prob:\n"
|
|
231
246
|
res += "\t"
|
|
232
247
|
for i in range(10):
|
|
233
|
-
res += "{
|
|
248
|
+
res += f"{self.p[i] / self.ttek:6.5f} "
|
|
234
249
|
res += "\n"
|
|
235
|
-
res += "Arrived:
|
|
236
|
-
if self.buffer
|
|
237
|
-
res += "Dropped:
|
|
238
|
-
res += "Served:
|
|
239
|
-
res += "In System:
|
|
250
|
+
res += f"Arrived: {self.arrived}\n"
|
|
251
|
+
if self.buffer is not None:
|
|
252
|
+
res += f"Dropped: {self.dropped}\n"
|
|
253
|
+
res += f"Served: {self.served}\n"
|
|
254
|
+
res += f"In System: {self.in_sys}\n"
|
|
240
255
|
|
|
241
256
|
for c in range(self.n):
|
|
242
257
|
res += str(self.servers[c])
|
|
@@ -1,38 +1,65 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"""
|
|
2
|
+
Simulation model for queueing systems with impatient tasks
|
|
3
|
+
"""
|
|
4
|
+
from colorama import Fore, Style, init
|
|
3
5
|
|
|
6
|
+
from most_queue.sim.qs_sim import QueueingSystemSimulator
|
|
7
|
+
from most_queue.sim.utils.distribution_utils import create_distribution
|
|
8
|
+
from most_queue.sim.utils.tasks import ImpatientTask
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
def __init__(self, arr_time, moment_to_leave):
|
|
7
|
-
super().__init__(arr_time)
|
|
8
|
-
self.moment_to_leave = moment_to_leave
|
|
10
|
+
init()
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
class ImpatientQueueSim(QueueingSystemSimulator):
|
|
13
|
+
"""
|
|
14
|
+
Queueing system with impatient tasks
|
|
12
15
|
|
|
16
|
+
"""
|
|
13
17
|
|
|
14
|
-
class ImpatientQueueSim(QueueingSystemSimulator):
|
|
15
18
|
def __init__(self, num_of_channels, buffer=None, verbose=True):
|
|
19
|
+
"""
|
|
20
|
+
:param num_of_channels: int
|
|
21
|
+
Number of channels in the system.
|
|
22
|
+
:param buffer: int or None
|
|
23
|
+
Buffer size. If None, then infinite buffer.
|
|
24
|
+
:param verbose: bool
|
|
25
|
+
If True, then print information about simulation process.
|
|
26
|
+
|
|
27
|
+
To start the simulation, you need to:
|
|
28
|
+
- call the constructor with parameters
|
|
29
|
+
- set the input arrival distribution using the set_sorces() method
|
|
30
|
+
- set the service distribution using the set_servers() method
|
|
31
|
+
- set the impatience distribution using the set_impatience() method
|
|
32
|
+
- start the simulation using the run() method
|
|
33
|
+
to which you need to pass the number of job required for servicing
|
|
34
|
+
|
|
35
|
+
See supported distributions params in the README.md file or use
|
|
36
|
+
```
|
|
37
|
+
from most_queue.sim.utils.distribution_utils import print_supported_distributions
|
|
38
|
+
print_supported_distributions()
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
"""
|
|
16
42
|
super().__init__(num_of_channels, buffer, verbose)
|
|
17
43
|
|
|
18
44
|
self.impatience_params = None
|
|
19
45
|
self.impatience_types = None
|
|
20
|
-
|
|
46
|
+
|
|
21
47
|
self.impatience = None
|
|
22
48
|
self.is_set_impatience_params = False
|
|
23
49
|
|
|
24
|
-
def
|
|
50
|
+
def set_impatience(self, params, types):
|
|
25
51
|
"""
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
52
|
+
set impatience parameters and types
|
|
53
|
+
:param params: list
|
|
54
|
+
List of lists with parameters for each type of impatience.
|
|
55
|
+
:param types: list
|
|
56
|
+
List of strings with types of impatience.
|
|
57
|
+
|
|
58
|
+
See supported distributions params in the README.md file or use
|
|
59
|
+
```
|
|
60
|
+
from most_queue.sim.utils.distribution_utils import print_supported_distributions
|
|
61
|
+
print_supported_distributions()
|
|
62
|
+
```
|
|
36
63
|
"""
|
|
37
64
|
self.impatience_params = params
|
|
38
65
|
self.impatience_types = types
|
|
@@ -43,7 +70,7 @@ class ImpatientQueueSim(QueueingSystemSimulator):
|
|
|
43
70
|
|
|
44
71
|
def arrival(self):
|
|
45
72
|
"""
|
|
46
|
-
|
|
73
|
+
Actions on arrival of a task.
|
|
47
74
|
"""
|
|
48
75
|
|
|
49
76
|
self.arrived += 1
|
|
@@ -57,7 +84,7 @@ class ImpatientQueueSim(QueueingSystemSimulator):
|
|
|
57
84
|
moment_to_leave = self.ttek + self.impatience.generate()
|
|
58
85
|
|
|
59
86
|
if self.free_channels == 0:
|
|
60
|
-
if self.buffer
|
|
87
|
+
if self.buffer is None: # не задана длина очереди, т.е бесконечная очередь
|
|
61
88
|
new_tsk = ImpatientTask(self.ttek, moment_to_leave)
|
|
62
89
|
new_tsk.start_waiting_time = self.ttek
|
|
63
90
|
self.queue.append(new_tsk)
|
|
@@ -87,14 +114,18 @@ class ImpatientQueueSim(QueueingSystemSimulator):
|
|
|
87
114
|
# Проверям, не наступил ли ПНЗ:
|
|
88
115
|
if self.free_channels == 0:
|
|
89
116
|
if self.in_sys == self.n:
|
|
90
|
-
self.
|
|
117
|
+
self.start_busy = self.ttek
|
|
91
118
|
break
|
|
92
119
|
|
|
93
|
-
def drop_task(self,
|
|
120
|
+
def drop_task(self, num_of_task_earlier, moment_to_leave_earlier):
|
|
121
|
+
"""
|
|
122
|
+
Drop a task from the queue and update statistics.
|
|
123
|
+
"""
|
|
94
124
|
self.ttek = moment_to_leave_earlier
|
|
95
125
|
new_queue = []
|
|
126
|
+
end_ts = None
|
|
96
127
|
for i, tsk in enumerate(self.queue.queue):
|
|
97
|
-
if i !=
|
|
128
|
+
if i != num_of_task_earlier:
|
|
98
129
|
new_queue.append(tsk)
|
|
99
130
|
else:
|
|
100
131
|
end_ts = self.queue.queue[i]
|
|
@@ -103,11 +134,16 @@ class ImpatientQueueSim(QueueingSystemSimulator):
|
|
|
103
134
|
self.in_sys -= 1
|
|
104
135
|
self.dropped += 1
|
|
105
136
|
self.served += 1
|
|
106
|
-
|
|
107
|
-
end_ts
|
|
108
|
-
|
|
137
|
+
|
|
138
|
+
if end_ts is not None:
|
|
139
|
+
self.refresh_v_stat(self.ttek - end_ts.arr_time)
|
|
140
|
+
end_ts.wait_time = self.ttek - end_ts.arr_time
|
|
141
|
+
self.refresh_w_stat(end_ts.wait_time)
|
|
109
142
|
|
|
110
143
|
def run_one_step(self):
|
|
144
|
+
"""
|
|
145
|
+
Run one step of the simulation.
|
|
146
|
+
"""
|
|
111
147
|
|
|
112
148
|
num_of_server_earlier = -1
|
|
113
149
|
serv_earl = 1e10
|
|
@@ -138,6 +174,11 @@ class ImpatientQueueSim(QueueingSystemSimulator):
|
|
|
138
174
|
self.drop_task(num_of_task_earlier, moment_to_leave_earlier)
|
|
139
175
|
|
|
140
176
|
def __str__(self, is_short=False):
|
|
177
|
+
"""
|
|
178
|
+
Returns a string representation of the system.
|
|
179
|
+
If `is_short` is True, it returns a short version of the string.
|
|
180
|
+
Otherwise, it returns a detailed version of the string.
|
|
181
|
+
"""
|
|
141
182
|
super().__str__(is_short)
|
|
142
183
|
num_of_task_earlier = -1
|
|
143
184
|
moment_to_leave_earlier = 1e10
|
|
@@ -145,4 +186,4 @@ class ImpatientQueueSim(QueueingSystemSimulator):
|
|
|
145
186
|
if tsk.moment_to_leave < moment_to_leave_earlier:
|
|
146
187
|
moment_to_leave_earlier = tsk.moment_to_leave
|
|
147
188
|
num_of_task_earlier = i
|
|
148
|
-
return f'Task {num_of_task_earlier} is earlier to leave at {moment_to_leave_earlier:8.3f}'
|
|
189
|
+
return f'{Fore.GREEN}Task {num_of_task_earlier}{Style.RESET_ALL} is earlier to leave at {Fore.YELLOW}{moment_to_leave_earlier:8.3f}{Style.RESET_ALL}'
|