most-queue 1.53__tar.gz → 1.54__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.

Files changed (129) hide show
  1. {most_queue-1.53 → most_queue-1.54}/PKG-INFO +7 -2
  2. {most_queue-1.53 → most_queue-1.54}/README.md +6 -1
  3. {most_queue-1.53 → most_queue-1.54}/most_queue/general/conv.py +12 -4
  4. {most_queue-1.53 → most_queue-1.54}/most_queue/general/tables.py +2 -2
  5. {most_queue-1.53 → most_queue-1.54}/most_queue/rand_distribution.py +5 -5
  6. most_queue-1.54/most_queue/sim/queueing_systems/negative.py +482 -0
  7. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/utils/distribution_utils.py +30 -30
  8. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/utils/qs_queue.py +24 -0
  9. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/fifo/mgn_takahasi.py +1 -9
  10. most_queue-1.54/most_queue/theory/queueing_systems/negative/mgn_rcs.py +579 -0
  11. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/vacations/m_h2_h2warm.py +3 -11
  12. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/vacations/mgn_with_h2_delay_cold_warm.py +5 -16
  13. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/vacations/mmn_with_h2_cold_and_h2_warmup.py +1 -12
  14. {most_queue-1.53 → most_queue-1.54}/pyproject.toml +1 -1
  15. {most_queue-1.53 → most_queue-1.54}/setup.py +1 -1
  16. {most_queue-1.53 → most_queue-1.54}/tests/test_m_h2_h2warm.py +1 -1
  17. most_queue-1.54/tests/test_mgn_rcs.py +72 -0
  18. {most_queue-1.53 → most_queue-1.54}/.gitignore +0 -0
  19. {most_queue-1.53 → most_queue-1.54}/LICENSE +0 -0
  20. {most_queue-1.53 → most_queue-1.54}/assets/queue_long.png +0 -0
  21. {most_queue-1.53 → most_queue-1.54}/deploy.txt +0 -0
  22. {most_queue-1.53 → most_queue-1.54}/docs/Makefile +0 -0
  23. {most_queue-1.53 → most_queue-1.54}/docs/make.bat +0 -0
  24. {most_queue-1.53 → most_queue-1.54}/docs/source/conf.py +0 -0
  25. {most_queue-1.53 → most_queue-1.54}/docs/source/index.rst +0 -0
  26. {most_queue-1.53 → most_queue-1.54}/docs/source/modules.rst +0 -0
  27. {most_queue-1.53 → most_queue-1.54}/docs/source/most_queue.rst +0 -0
  28. {most_queue-1.53 → most_queue-1.54}/docs/source/most_queue.sim.rst +0 -0
  29. {most_queue-1.53 → most_queue-1.54}/docs/source/most_queue.theory.rst +0 -0
  30. {most_queue-1.53 → most_queue-1.54}/googleb31d3dccb40f969f.html +0 -0
  31. {most_queue-1.53 → most_queue-1.54}/most_queue/__init__.py +0 -0
  32. {most_queue-1.53 → most_queue-1.54}/most_queue/general/__init__.py +0 -0
  33. {most_queue-1.53 → most_queue-1.54}/most_queue/general/approx_cdf_make.py +0 -0
  34. {most_queue-1.53 → most_queue-1.54}/most_queue/general/distribution_params.py +0 -0
  35. {most_queue-1.53 → most_queue-1.54}/most_queue/general/interfaces.py +0 -0
  36. {most_queue-1.53 → most_queue-1.54}/most_queue/general/vacations_paper_utils.py +0 -0
  37. {most_queue-1.53 → most_queue-1.54}/most_queue/misc/compare_fj_calc.py +0 -0
  38. {most_queue-1.53 → most_queue-1.54}/most_queue/misc/flow_sum.py +0 -0
  39. {most_queue-1.53 → most_queue-1.54}/most_queue/misc/test_weibull.py +0 -0
  40. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/__init__.py +0 -0
  41. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/flow_sum.py +0 -0
  42. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/networks/__init__.py +0 -0
  43. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/networks/priority_network.py +0 -0
  44. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/queueing_systems/__init__.py +0 -0
  45. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/queueing_systems/batch.py +0 -0
  46. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/queueing_systems/fifo.py +0 -0
  47. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/queueing_systems/finite_source.py +0 -0
  48. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/queueing_systems/fork_join.py +0 -0
  49. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/queueing_systems/fork_join_delta.py +0 -0
  50. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/queueing_systems/impatient.py +0 -0
  51. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/queueing_systems/priority.py +0 -0
  52. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/utils/__init__.py +0 -0
  53. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/utils/exceptions.py +0 -0
  54. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/utils/phase.py +0 -0
  55. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/utils/qs.py +0 -0
  56. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/utils/servers.py +0 -0
  57. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/utils/stats_update.py +0 -0
  58. {most_queue-1.53 → most_queue-1.54}/most_queue/sim/utils/tasks.py +0 -0
  59. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/__init__.py +0 -0
  60. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/networks/__init__.py +0 -0
  61. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/networks/network_viewer.py +0 -0
  62. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/networks/open_network.py +0 -0
  63. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/__init__.py +0 -0
  64. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/batch/__init__.py +0 -0
  65. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/batch/mm1.py +0 -0
  66. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/closed/__init__.py +0 -0
  67. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/closed/engset.py +0 -0
  68. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/fifo/__init__.py +0 -0
  69. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/fifo/ek_d_n.py +0 -0
  70. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/fifo/gi_m_1.py +0 -0
  71. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/fifo/gi_m_n.py +0 -0
  72. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/fifo/m_d_n.py +0 -0
  73. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/fifo/mg1.py +0 -0
  74. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/fifo/mmnr.py +0 -0
  75. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/fork_join/__init__.py +0 -0
  76. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/fork_join/m_m_n.py +0 -0
  77. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/fork_join/split_join.py +0 -0
  78. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/impatience/__init__.py +0 -0
  79. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/impatience/mm1.py +0 -0
  80. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/priority/__init__.py +0 -0
  81. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/priority/mgn_invar_approx.py +0 -0
  82. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/priority/non_preemptive/__init__.py +0 -0
  83. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/priority/non_preemptive/mg1.py +0 -0
  84. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/priority/preemptive/__init__.py +0 -0
  85. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/priority/preemptive/m_ph_n_busy_approx.py +0 -0
  86. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/priority/preemptive/mg1.py +0 -0
  87. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/priority/preemptive/mmn_2cls_pr_busy_approx.py +0 -0
  88. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/priority/preemptive/mmn_3cls_busy_approx.py +0 -0
  89. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/vacations/__init__.py +0 -0
  90. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/queueing_systems/vacations/mg1_warm_calc.py +0 -0
  91. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/r_example.gexf +0 -0
  92. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/utils/__init__.py +0 -0
  93. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/utils/binom_probs.py +0 -0
  94. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/utils/busy_periods.py +0 -0
  95. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/utils/diff5dots.py +0 -0
  96. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/utils/flow_sum.py +0 -0
  97. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/utils/passage_time.py +0 -0
  98. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/utils/q_poisson_arrival_calc.py +0 -0
  99. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/utils/student_stat.py +0 -0
  100. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/utils/transforms.py +0 -0
  101. {most_queue-1.53 → most_queue-1.54}/most_queue/theory/utils/weibull.py +0 -0
  102. {most_queue-1.53 → most_queue-1.54}/requirements.txt +0 -0
  103. {most_queue-1.53 → most_queue-1.54}/tests/__init__.py +0 -0
  104. {most_queue-1.53 → most_queue-1.54}/tests/n_test/ro_0.700.json +0 -0
  105. {most_queue-1.53 → most_queue-1.54}/tests/ro_test/n_3.json +0 -0
  106. {most_queue-1.53 → most_queue-1.54}/tests/test_batch.py +0 -0
  107. {most_queue-1.53 → most_queue-1.54}/tests/test_ek_d_n.py +0 -0
  108. {most_queue-1.53 → most_queue-1.54}/tests/test_engset.py +0 -0
  109. {most_queue-1.53 → most_queue-1.54}/tests/test_fj_delta.py +0 -0
  110. {most_queue-1.53 → most_queue-1.54}/tests/test_fj_im.py +0 -0
  111. {most_queue-1.53 → most_queue-1.54}/tests/test_gi_m_1_calc.py +0 -0
  112. {most_queue-1.53 → most_queue-1.54}/tests/test_gi_m_n_calc.py +0 -0
  113. {most_queue-1.53 → most_queue-1.54}/tests/test_impatience.py +0 -0
  114. {most_queue-1.53 → most_queue-1.54}/tests/test_m_d_n_calc.py +0 -0
  115. {most_queue-1.53 → most_queue-1.54}/tests/test_m_ph_n_prty.py +0 -0
  116. {most_queue-1.53 → most_queue-1.54}/tests/test_mg1_calc.py +0 -0
  117. {most_queue-1.53 → most_queue-1.54}/tests/test_mgn_tt.py +0 -0
  118. {most_queue-1.53 → most_queue-1.54}/tests/test_mgn_with_h2_delay_cold_warm.py +0 -0
  119. {most_queue-1.53 → most_queue-1.54}/tests/test_mmn3_pnz_cox_approx.py +0 -0
  120. {most_queue-1.53 → most_queue-1.54}/tests/test_mmn_h2cold_h2warm.py +0 -0
  121. {most_queue-1.53 → most_queue-1.54}/tests/test_mmn_prty_pnz_approx.py +0 -0
  122. {most_queue-1.53 → most_queue-1.54}/tests/test_network_im_prty.py +0 -0
  123. {most_queue-1.53 → most_queue-1.54}/tests/test_qs_sim_prty.py +0 -0
  124. {most_queue-1.53 → most_queue-1.54}/tests/test_qs_sim_test.py +0 -0
  125. {most_queue-1.53 → most_queue-1.54}/tests/test_queue_types.py +0 -0
  126. {most_queue-1.53 → most_queue-1.54}/tutorials/m_h2_h2warm.ipynb +0 -0
  127. {most_queue-1.53 → most_queue-1.54}/tutorials/mgn_takahasi_takami.ipynb +0 -0
  128. {most_queue-1.53 → most_queue-1.54}/tutorials/priority_queue.ipynb +0 -0
  129. {most_queue-1.53 → most_queue-1.54}/tutorials/queue_sim.ipynb +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: most_queue
3
- Version: 1.53
3
+ Version: 1.54
4
4
  Summary: Software package for calculation and simulation of queuing systems
5
5
  Project-URL: Homepage, https://github.com/xabarov/most-queue
6
6
  Author-email: Xabarov Roman <xabarov1985@gmail.com>
@@ -68,11 +68,16 @@ Contributions are welcome! If you find any issues or have suggestions, please op
68
68
  ---
69
69
 
70
70
  ## Installation
71
- Install most-queue with pip
71
+ - install most-queue with pip
72
72
  ```bash
73
73
  pip install most-queue
74
74
  ```
75
75
 
76
+ - install most-queue from repository
77
+ ```bash
78
+ pip install -e .
79
+ ```
80
+
76
81
  ---
77
82
 
78
83
  ## Description of the Project
@@ -28,11 +28,16 @@ Contributions are welcome! If you find any issues or have suggestions, please op
28
28
  ---
29
29
 
30
30
  ## Installation
31
- Install most-queue with pip
31
+ - install most-queue with pip
32
32
  ```bash
33
33
  pip install most-queue
34
34
  ```
35
35
 
36
+ - install most-queue from repository
37
+ ```bash
38
+ pip install -e .
39
+ ```
40
+
36
41
  ---
37
42
 
38
43
  ## Description of the Project
@@ -1,7 +1,7 @@
1
1
  """
2
2
  Functions for calculating convolutions of distributions.
3
3
  """
4
-
4
+ import numpy as np
5
5
 
6
6
  def conv_moments(a: list[float], b: list[float], num: int = 3) -> list[float]:
7
7
  """
@@ -18,7 +18,7 @@ def conv_moments(a: list[float], b: list[float], num: int = 3) -> list[float]:
18
18
  res[1] = a[1] + b[1] + 2 * a[0] * b[0]
19
19
  if num > 2:
20
20
  res[2] = a[2] + b[2] + 3 * a[1] * b[0] + 3 * a[0] * b[1]
21
- return res
21
+ return np.array(res)
22
22
 
23
23
 
24
24
  def get_self_conv_moments(b: list[float], n_times, num: int = 3) -> list[float]:
@@ -48,6 +48,14 @@ def conv_moments_minus(a: list[float], b: list[float], num: int = 3) -> list[flo
48
48
  num = min(num, 3)
49
49
  res = [0] * num
50
50
  res[0] = a[0] - b[0]
51
- res[1] = a[1] - b[1] - 2 * a[0] * b[0]
52
- res[2] = a[2] - b[2] - 3 * a[1] * b[0] - 3 * a[0] * b[1]
51
+ if num > 1:
52
+ res[1] = a[1] - b[1] - 2 * a[0] * b[0]
53
+ if num > 2:
54
+ res[2] = a[2] - b[2] - 3 * a[1] * b[0] - 3 * a[0] * b[1]
53
55
  return res
56
+
57
+ def get_residual_distr_moments(a):
58
+ f = [0.0] * (len(a) - 1)
59
+ for i in range(len(f)):
60
+ f[i] = a[i + 1] / ((i + 2) * a[0])
61
+ return f
@@ -226,11 +226,11 @@ def print_mrx(mrx, is_short=False):
226
226
  color = Fore.RED
227
227
  else:
228
228
  color = Fore.GREEN
229
- if is_short:
229
+ if is_short or mrx[i, j].imag == 0.0:
230
230
  print(f"{color}{mrx[i, j].real:^4.2f} | ", end="")
231
231
  else:
232
232
  print(f"{color}{mrx[i, j]:^5.3f} | ", end="")
233
- print("\n" + "-------" * col if is_short else "\n" + "---------------" * col)
233
+ print("\n" + "-------" * col if is_short or mrx[i, j].imag == 0.0 else "\n" + "---------------" * col)
234
234
  Fore.RESET # Reset colors after each row
235
235
 
236
236
 
@@ -572,21 +572,21 @@ class DeterministicDistribution(Distribution):
572
572
  return DeterministicDistribution.generate_static(self.b)
573
573
 
574
574
  @staticmethod
575
- def generate_static(b):
575
+ def generate_static(params, generator=None):
576
576
  """
577
577
  Generate a constant value b. Static method for use without creating an instance of the class.
578
578
  """
579
- return b
579
+ return params
580
580
 
581
581
  @staticmethod
582
- def calc_theory_moments(b, num: int) -> list[float]:
582
+ def calc_theory_moments(params, num: int) -> list[float]:
583
583
  """
584
584
  Calculates theoretical moments of the distribution up to the specified order.
585
- :param b: constant value.
585
+ :param params = b: constant value.
586
586
  :param num: number of moments to calculate.
587
587
  :return: list[float]
588
588
  """
589
- moments = [b**i for i in range(1, num+1)]
589
+ moments = [params**i for i in range(1, num+1)]
590
590
  return moments
591
591
 
592
592
  @staticmethod
@@ -0,0 +1,482 @@
1
+ """
2
+ Simulation model of QS GI/G/n/r and GI/G/n with negative jobs
3
+ """
4
+ import random
5
+ import time
6
+ from enum import Enum
7
+
8
+ import numpy as np
9
+ from colorama import Fore, Style, init
10
+ from tqdm import tqdm
11
+
12
+ from most_queue.sim.utils.distribution_utils import calc_qs_load, create_distribution
13
+ from most_queue.sim.utils.exceptions import QsWrongQueueTypeException
14
+ from most_queue.sim.utils.qs_queue import QsQueueDeque, QsQueueList
15
+ from most_queue.sim.utils.servers import Server
16
+ from most_queue.sim.utils.stats_update import refresh_moments_stat
17
+ from most_queue.sim.utils.tasks import Task
18
+
19
+ init()
20
+
21
+
22
+ class NegativeServiceType(Enum):
23
+ """
24
+ Negative service types
25
+ """
26
+ DISASTER = 1 # remove all customers
27
+ RCS = 2 # remove customer in service
28
+ RCH = 3 # remove customer at the Head
29
+ RCE = 4 # remove customer at the End
30
+
31
+
32
+ class QueueingSystemSimulatorWithNegatives:
33
+ """
34
+ Simulation model of QS GI/G/n/r and GI/G/n with negative jobs
35
+ """
36
+
37
+ def __init__(self, num_of_channels: int,
38
+ type_of_negatives: NegativeServiceType = NegativeServiceType.DISASTER,
39
+ buffer: int | None = None,
40
+ verbose: bool = True,
41
+ buffer_type="list"):
42
+ """
43
+ Initialize the queueing system with GI/G/n/r or GI/G/n model.
44
+ :param num_of_channels: int : number of channels in the system
45
+ :param buffer: Optional(int, None) : maximum length of the queue, None if infinite
46
+ :param verbose: bool : whether to print detailed information during simulation
47
+ :param buffer_type: str : type of the buffer, "list" or "deque"
48
+ """
49
+ self.n = num_of_channels
50
+ self.buffer = buffer
51
+ self.verbose = verbose
52
+ self.type_of_negatives = type_of_negatives
53
+
54
+ self.generator = np.random.default_rng()
55
+
56
+ self.free_channels = self.n
57
+ self.num_of_states = 100000
58
+ self.load = 0 # utilization factor
59
+
60
+ self.ttek = 0 # current simulation time
61
+
62
+ self.w = [0, 0, 0] # initial moments of waiting time in the QS
63
+ self.v_served = [0, 0, 0] # initial moments of sojourn time of served job in the QS
64
+ self.v_breaked = [0, 0, 0] # initial moments of sojourn time of breaked job in the QS
65
+
66
+ # probabilities of the QS states:
67
+ self.p = [0.0] * self.num_of_states
68
+
69
+ self.taked = 0 # number of job accepted for service
70
+ self.served = 0 # number of job serviced by the system
71
+ self.breaked = 0 # number of job breaked by negative arrivals in the system
72
+ self.in_sys = 0 # number of job in the system
73
+
74
+ # Positive arrivals
75
+ self.positive_arrived = 0 # number of job received
76
+ self.positive_dropped = 0 # number of job denied service
77
+ self.positive_arrival_time = 0 # time of arrival of the next job
78
+ self.positive_source = None
79
+ self.positive_source_params = None
80
+ self.positive_source_types = None
81
+ self.is_set_positive_source_params = False
82
+
83
+ # Negative arrivals
84
+ self.negative_arrived = 0 # number of job received
85
+ self.negative_arrival_time = 0 # time of arrival of the next job
86
+ self.negative_source = None
87
+ self.negative_source_params = None
88
+ self.negative_source_types = None
89
+ self.is_set_negative_source_params = False
90
+
91
+ # queue of jobs: class - Task
92
+ if buffer_type == "list":
93
+ self.queue = QsQueueList()
94
+ elif buffer_type == "deque":
95
+ self.queue = QsQueueDeque()
96
+ else:
97
+ raise QsWrongQueueTypeException("Unknown queue type")
98
+
99
+ self.servers = [] # service channels, list of Server's
100
+
101
+ self.server_params = None
102
+ self.server_types = None
103
+
104
+ self.is_set_server_params = False
105
+
106
+ self.time_spent = 0
107
+
108
+ def set_positive_sources(self, params, types):
109
+ """
110
+ Specifies the type and parameters of positives source time distribution.
111
+ :param params: list : parameters for the positives source time distribution
112
+ :param types: list : types of positives source time distribution
113
+
114
+ """
115
+ self.positive_source_params = params
116
+ self.positive_source_types = types
117
+
118
+ self.is_set_positive_source_params = True
119
+
120
+ self.positive_source = create_distribution(
121
+ params, types, self.generator)
122
+
123
+ self.positive_arrival_time = self.positive_source.generate()
124
+
125
+ def set_negative_sources(self, params, types):
126
+ """
127
+ Specifies the type and parameters of negative source time distribution.
128
+ :param params: list : parameters for the negative source time distribution
129
+ :param types: list : types of negative source time distribution
130
+
131
+ """
132
+ self.negative_source_params = params
133
+ self.negative_source_types = types
134
+
135
+ self.is_set_negative_source_params = True
136
+
137
+ self.negative_source = create_distribution(
138
+ params, types, self.generator)
139
+
140
+ self.negative_arrival_time = self.negative_source.generate()
141
+
142
+ def set_servers(self, params, types):
143
+ """
144
+ Specifies the type and parameters of service time distribution.
145
+ :param params: list : parameters for the service time distribution
146
+ :param types: list : types of service time distribution
147
+ """
148
+ self.server_params = params
149
+ self.server_types = types
150
+
151
+ self.is_set_server_params = True
152
+
153
+ self.servers = [Server(self.server_params, self.server_types,
154
+ generator=self.generator) for i in range(self.n)]
155
+
156
+ def calc_positive_load(self):
157
+ """
158
+ Calculates the load factor of the QS if has no disatsers
159
+ """
160
+
161
+ return calc_qs_load(self.positive_source_types,
162
+ self.positive_source_params,
163
+ self.server_types,
164
+ self.server_params, self.n)
165
+
166
+ def send_task_to_channel(self):
167
+ """
168
+ Sends a job to the service channel
169
+ """
170
+ for s in self.servers:
171
+ if s.is_free:
172
+ tsk = Task(self.ttek)
173
+ tsk.wait_time = 0
174
+ self.taked += 1
175
+ self.refresh_w_stat(tsk.wait_time)
176
+
177
+ s.start_service(tsk, self.ttek, False)
178
+ self.free_channels -= 1
179
+
180
+ break
181
+
182
+ def send_task_to_queue(self):
183
+ """
184
+ Send Task to Queue
185
+ """
186
+ if self.buffer is None: # queue length is not specified, i.e. infinite queue
187
+ new_tsk = Task(self.ttek)
188
+ new_tsk.start_waiting_time = self.ttek
189
+ self.queue.append(new_tsk)
190
+ else:
191
+ if self.queue.size() < self.buffer:
192
+ new_tsk = Task(self.ttek)
193
+ new_tsk.start_waiting_time = self.ttek
194
+ self.queue.append(new_tsk)
195
+ else:
196
+ self.positive_dropped += 1
197
+ self.in_sys -= 1
198
+
199
+ def positive_arrival(self):
200
+ """
201
+ Actions upon arrival of positive job by the QS.
202
+ """
203
+
204
+ self.positive_arrived += 1
205
+ self.p[self.in_sys] += self.positive_arrival_time - self.ttek
206
+
207
+ self.in_sys += 1
208
+ self.ttek = self.positive_arrival_time
209
+ self.positive_arrival_time = self.ttek + self.positive_source.generate()
210
+
211
+ if self.free_channels == 0:
212
+ self.send_task_to_queue()
213
+ else:
214
+ self.send_task_to_channel()
215
+
216
+ def negative_arrival(self):
217
+ """
218
+ Actions upon arrival of negative job by the QS.
219
+ """
220
+
221
+ self.negative_arrived += 1
222
+ self.p[self.in_sys] += self.negative_arrival_time - self.ttek
223
+ self.ttek = self.negative_arrival_time
224
+ self.negative_arrival_time = self.ttek + self.negative_source.generate()
225
+
226
+ if self.in_sys == 0:
227
+ # If no jobs in system, negatives has no effect
228
+ return
229
+
230
+ if self.type_of_negatives == NegativeServiceType.DISASTER:
231
+ self.in_sys = 0
232
+ self.free_channels = self.n
233
+ while self.queue:
234
+ ts = self.queue.pop()
235
+ ts.wait_time += self.ttek - ts.start_waiting_time
236
+ self.taked += 1
237
+ self.breaked += 1
238
+ self.refresh_w_stat(ts.wait_time)
239
+ self.refresh_v_stat_breaked(self.ttek - ts.arr_time)
240
+
241
+ elif self.type_of_negatives == NegativeServiceType.RCE:
242
+ self.in_sys -= 1
243
+ ts = self.queue.tail()
244
+ ts.wait_time += self.ttek - ts.start_waiting_time
245
+ self.taked += 1
246
+ self.breaked += 1
247
+ self.refresh_w_stat(ts.wait_time)
248
+ self.refresh_v_stat_breaked(self.ttek - ts.arr_time)
249
+
250
+ elif self.type_of_negatives == NegativeServiceType.RCH:
251
+ self.in_sys -= 1
252
+ ts = self.queue.pop()
253
+ ts.wait_time += self.ttek - ts.start_waiting_time
254
+ self.taked += 1
255
+ self.breaked += 1
256
+ self.refresh_w_stat(ts.wait_time)
257
+ self.refresh_v_stat_breaked(self.ttek - ts.arr_time)
258
+
259
+ elif self.type_of_negatives == NegativeServiceType.RCS:
260
+
261
+ not_free_servers = [c for c in range(self.n) if not self.servers[c].is_free]
262
+ c = random.choice(not_free_servers)
263
+
264
+ end_ts = self.servers[c].end_service()
265
+ self.breaked += 1
266
+ self.free_channels += 1
267
+ self.refresh_v_stat_breaked(self.ttek - end_ts.arr_time)
268
+
269
+ self.in_sys -= 1
270
+
271
+ if self.queue.size() != 0:
272
+ self.send_head_of_queue_to_channel(c)
273
+
274
+
275
+ def serving(self, c):
276
+ """
277
+ Actions upon receipt of a service job with - channel number
278
+ """
279
+ time_to_end = self.servers[c].time_to_end_service
280
+ end_ts = self.servers[c].end_service()
281
+
282
+ self.p[self.in_sys] += time_to_end - self.ttek
283
+
284
+ self.ttek = time_to_end
285
+ self.served += 1
286
+ self.free_channels += 1
287
+ self.refresh_v_stat_served(self.ttek - end_ts.arr_time)
288
+
289
+ self.in_sys -= 1
290
+
291
+ if self.queue.size() != 0:
292
+ self.send_head_of_queue_to_channel(c)
293
+
294
+ def send_head_of_queue_to_channel(self, channel_num):
295
+ """
296
+ Send first Task (head of queue) to Channel
297
+ """
298
+ que_ts = self.queue.pop()
299
+
300
+ self.taked += 1
301
+ que_ts.wait_time += self.ttek - que_ts.start_waiting_time
302
+ self.refresh_w_stat(que_ts.wait_time)
303
+
304
+ self.servers[channel_num].start_service(que_ts, self.ttek)
305
+ self.free_channels -= 1
306
+
307
+ def run_one_step(self):
308
+ """
309
+ Run Open step of simulation
310
+ """
311
+
312
+ num_of_server_earlier = -1
313
+ serv_earl = 1e16
314
+
315
+ for c in range(self.n):
316
+ if self.servers[c].time_to_end_service < serv_earl:
317
+ serv_earl = self.servers[c].time_to_end_service
318
+ num_of_server_earlier = c
319
+
320
+ # Global warm-up is set. Need to track
321
+ # including the moment of warm-up end
322
+ times = [serv_earl, self.positive_arrival_time,
323
+ self.negative_arrival_time]
324
+ min_time_num = np.argmin(times)
325
+ if min_time_num == 0:
326
+ # Serving
327
+ self.serving(num_of_server_earlier)
328
+ elif min_time_num == 1:
329
+ # Arrival positive
330
+ self.positive_arrival()
331
+ else:
332
+ # Arrival negative
333
+ self.negative_arrival()
334
+
335
+ def run(self, total_served, is_real_served=True):
336
+ """
337
+ Run simulation process
338
+ """
339
+
340
+ # Check if is_set_server_params is set
341
+ if not self.is_set_server_params:
342
+ raise ValueError('Server parameters are not set. Please call set_servers() first.')
343
+ # Check if is_set_positive_source_params
344
+ if not self.is_set_positive_source_params:
345
+ raise ValueError('Positive source parameters are not set. Please call set_positive_sources() first.')
346
+ # Check if is_set_negative_source_params
347
+ if not self.is_set_negative_source_params:
348
+ raise ValueError('Negative source parameters are not set. Please call set_negative_sources() first.')
349
+
350
+ start = time.process_time()
351
+
352
+ print(Fore.GREEN + '\rStart simulation')
353
+
354
+ if is_real_served:
355
+
356
+ last_percent = 0
357
+
358
+ with tqdm(total=100) as pbar:
359
+ while self.served < total_served:
360
+ self.run_one_step()
361
+ percent = int(100*(self.served/total_served))
362
+ if last_percent != percent:
363
+ last_percent = percent
364
+ pbar.update(1)
365
+ pbar.set_description(Fore.MAGENTA + '\rJob served: ' +
366
+ Fore.YELLOW + f'{self.served}/{total_served}' +
367
+ Fore.LIGHTGREEN_EX)
368
+
369
+ else:
370
+ for _ in tqdm(range(total_served)):
371
+ self.run_one_step()
372
+
373
+ print(Fore.GREEN + '\rSimulation is finished')
374
+ print(Style.RESET_ALL)
375
+
376
+ self.time_spent = time.process_time() - start
377
+
378
+ def refresh_v_stat_served(self, new_a):
379
+ """
380
+ Updating statistics of sojourn times of served jobs
381
+ """
382
+ self.v_served = refresh_moments_stat(self.v_served, new_a, self.served)
383
+
384
+
385
+ def refresh_v_stat_breaked(self, new_a):
386
+ """
387
+ Updating statistics of sojourn times of breaked jobs
388
+ """
389
+ self.v_breaked = refresh_moments_stat(self.v_breaked, new_a, self.breaked)
390
+
391
+ def refresh_w_stat(self, new_a):
392
+ """
393
+ Updating statistics of wait times
394
+ """
395
+ self.w = refresh_moments_stat(self.w, new_a, self.taked)
396
+
397
+ def get_p(self):
398
+ """
399
+ Returns a list with probabilities of QS states
400
+ p[j] - the probability that there will be exactly j jobs
401
+ in the QS at a random moment in time
402
+ """
403
+ res = [0.0] * len(self.p)
404
+ for j in range(0, self.num_of_states):
405
+ res[j] = self.p[j] / self.ttek
406
+ return res
407
+
408
+ def get_w(self):
409
+ """
410
+ Returns waiting time initial moments
411
+ """
412
+ return self.w
413
+
414
+ def get_v_served(self):
415
+ """
416
+ Returns initial moments of soujourn time served jobs
417
+ """
418
+ return self.v_served
419
+
420
+ def get_v_breaked(self):
421
+ """
422
+ Returns initial moments of soujourn time breaked jobs
423
+ """
424
+ return self.v_breaked
425
+
426
+ def __str__(self, is_short=False):
427
+
428
+ type_of_neg_str = ''
429
+ if self.type_of_negatives == NegativeServiceType.DISASTER:
430
+ type_of_neg_str = 'Disaster'
431
+ elif self.type_of_negatives == NegativeServiceType.RCE:
432
+ type_of_neg_str = 'Remove customer from the End of the Queue'
433
+ elif self.type_of_negatives == NegativeServiceType.RCH:
434
+ type_of_neg_str = 'Remove customer from the Head of the Queue'
435
+ elif self.type_of_negatives == NegativeServiceType.RCS:
436
+ type_of_neg_str = 'Remove customer from the Service'
437
+ else:
438
+ type_of_neg_str = 'Unknown'
439
+
440
+ res = "Queueing system " + self.positive_source_types + \
441
+ "/" + self.server_types + "/" + str(self.n) + type_of_neg_str
442
+ if self.buffer is not None:
443
+ res += "/" + str(self.buffer)
444
+ res += f"\nLoad: {self.calc_positive_load():4.3f}\n"
445
+ res += f"Current Time {self.ttek:8.3f}\n"
446
+ res += f"Positive arrival Time: {self.positive_arrival_time:8.3f}\n"
447
+ res += f"Negative arrival Time: {self.negative_arrival_time:8.3f}\n"
448
+
449
+ res += "Sojourn moments of served jobs:\n"
450
+ for i in range(3):
451
+ res += f"\t{self.v_served[i]:8.4f}"
452
+ res += "\n"
453
+
454
+ res += "Sojourn moments of breaked jobs:\n"
455
+ for i in range(3):
456
+ res += f"\t{self.v_breaked[i]:8.4f}"
457
+ res += "\n"
458
+
459
+ res += "Wait moments:\n"
460
+ for i in range(3):
461
+ res += f"\t{self.w[i]:8.4f}"
462
+ res += "\n"
463
+
464
+ if not is_short:
465
+ res += "Stationary prob:\n"
466
+ res += "\t"
467
+ for i in range(10):
468
+ res += f"{self.p[i] / self.ttek:6.5f}\t"
469
+ res += "\n"
470
+ res += f"Positive arrived: {self.positive_arrived}\n"
471
+ if self.buffer is not None:
472
+ res += f"Positive dropped: {self.positive_dropped}\n"
473
+ res += f"Negative arrived: {self.negative_arrived}\n"
474
+ res += f"Taken: {self.taked}\n"
475
+ res += f"Served: {self.served}\n"
476
+ res += f"In System: {self.in_sys}\n"
477
+ res += "\n"
478
+ for c in range(self.n):
479
+ res += str(self.servers[c])
480
+ res += f"\nQueue Count {self.queue.size()}\n"
481
+
482
+ return res