most-queue 1.54__tar.gz → 1.56__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 (145) hide show
  1. {most_queue-1.54 → most_queue-1.56}/.gitignore +2 -0
  2. {most_queue-1.54 → most_queue-1.56}/PKG-INFO +9 -1
  3. {most_queue-1.54 → most_queue-1.56}/README.md +8 -0
  4. most_queue-1.56/most_queue/general/conditional.py +52 -0
  5. most_queue-1.56/most_queue/general/plots.py +65 -0
  6. {most_queue-1.54 → most_queue-1.56}/most_queue/general/tables.py +9 -8
  7. {most_queue-1.54 → most_queue-1.56}/most_queue/general/vacations_paper_utils.py +6 -6
  8. most_queue-1.56/most_queue/misc/calc_v_pls.py +314 -0
  9. {most_queue-1.54 → most_queue-1.56}/most_queue/misc/compare_fj_calc.py +37 -32
  10. most_queue-1.54/most_queue/sim/queueing_systems/fifo.py → most_queue-1.56/most_queue/sim/queueing_systems/base.py +376 -538
  11. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/queueing_systems/batch.py +5 -8
  12. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/queueing_systems/finite_source.py +7 -52
  13. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/queueing_systems/fork_join.py +14 -79
  14. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/queueing_systems/fork_join_delta.py +3 -3
  15. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/queueing_systems/impatient.py +3 -8
  16. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/queueing_systems/negative.py +90 -204
  17. most_queue-1.56/most_queue/sim/queueing_systems/vacations.py +290 -0
  18. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/networks/open_network.py +1 -1
  19. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/fifo/mgn_takahasi.py +19 -7
  20. most_queue-1.56/most_queue/theory/queueing_systems/negative/mgn_disaster.py +344 -0
  21. most_queue-1.56/most_queue/theory/queueing_systems/negative/mgn_rcs.py +277 -0
  22. most_queue-1.56/most_queue/theory/queueing_systems/negative/structs.py +82 -0
  23. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/vacations/mmn_with_h2_cold_and_h2_warmup.py +4 -1
  24. {most_queue-1.54 → most_queue-1.56}/pyproject.toml +1 -1
  25. {most_queue-1.54 → most_queue-1.56}/setup.py +1 -1
  26. most_queue-1.56/tests/test_base_qs_sim.py +60 -0
  27. most_queue-1.56/tests/test_conditionals.py +110 -0
  28. {most_queue-1.54 → most_queue-1.56}/tests/test_ek_d_n.py +2 -2
  29. {most_queue-1.54 → most_queue-1.56}/tests/test_engset.py +6 -1
  30. {most_queue-1.54 → most_queue-1.56}/tests/test_gi_m_1_calc.py +3 -3
  31. {most_queue-1.54 → most_queue-1.56}/tests/test_gi_m_n_calc.py +3 -3
  32. {most_queue-1.54 → most_queue-1.56}/tests/test_m_d_n_calc.py +2 -2
  33. {most_queue-1.54 → most_queue-1.56}/tests/test_m_h2_h2warm.py +3 -3
  34. {most_queue-1.54 → most_queue-1.56}/tests/test_mg1_calc.py +4 -4
  35. most_queue-1.56/tests/test_mgn_disaster.py +76 -0
  36. {most_queue-1.54 → most_queue-1.56}/tests/test_mgn_rcs.py +23 -18
  37. {most_queue-1.54 → most_queue-1.56}/tests/test_mgn_tt.py +2 -2
  38. {most_queue-1.54 → most_queue-1.56}/tests/test_mgn_with_h2_delay_cold_warm.py +8 -10
  39. {most_queue-1.54 → most_queue-1.56}/tests/test_mmn_h2cold_h2warm.py +2 -2
  40. most_queue-1.54/tests/test_qs_sim_test.py → most_queue-1.56/tests/test_qs_sim.py +3 -4
  41. {most_queue-1.54 → most_queue-1.56}/tests/test_queue_types.py +2 -2
  42. most_queue-1.56/tests/vacations_ro_0.7.png +0 -0
  43. {most_queue-1.54 → most_queue-1.56}/tutorials/m_h2_h2warm.ipynb +3 -3
  44. {most_queue-1.54 → most_queue-1.56}/tutorials/mgn_takahasi_takami.ipynb +3 -3
  45. {most_queue-1.54 → most_queue-1.56}/tutorials/priority_queue.ipynb +2 -2
  46. most_queue-1.56/tutorials/queue_sim.ipynb +376 -0
  47. most_queue-1.56/works/__init__.py +0 -0
  48. most_queue-1.56/works/negative_queues/__init__.py +0 -0
  49. most_queue-1.56/works/negative_queues/work_mgn_disasters.py +357 -0
  50. most_queue-1.56/works/negative_queues/work_mgn_rcs.py +357 -0
  51. most_queue-1.54/most_queue/theory/queueing_systems/negative/mgn_rcs.py +0 -579
  52. most_queue-1.54/tutorials/queue_sim.ipynb +0 -335
  53. {most_queue-1.54 → most_queue-1.56}/LICENSE +0 -0
  54. {most_queue-1.54 → most_queue-1.56}/assets/queue_long.png +0 -0
  55. {most_queue-1.54 → most_queue-1.56}/deploy.txt +0 -0
  56. {most_queue-1.54 → most_queue-1.56}/docs/Makefile +0 -0
  57. {most_queue-1.54 → most_queue-1.56}/docs/make.bat +0 -0
  58. {most_queue-1.54 → most_queue-1.56}/docs/source/conf.py +0 -0
  59. {most_queue-1.54 → most_queue-1.56}/docs/source/index.rst +0 -0
  60. {most_queue-1.54 → most_queue-1.56}/docs/source/modules.rst +0 -0
  61. {most_queue-1.54 → most_queue-1.56}/docs/source/most_queue.rst +0 -0
  62. {most_queue-1.54 → most_queue-1.56}/docs/source/most_queue.sim.rst +0 -0
  63. {most_queue-1.54 → most_queue-1.56}/docs/source/most_queue.theory.rst +0 -0
  64. {most_queue-1.54 → most_queue-1.56}/googleb31d3dccb40f969f.html +0 -0
  65. {most_queue-1.54 → most_queue-1.56}/most_queue/__init__.py +0 -0
  66. {most_queue-1.54 → most_queue-1.56}/most_queue/general/__init__.py +0 -0
  67. {most_queue-1.54 → most_queue-1.56}/most_queue/general/approx_cdf_make.py +0 -0
  68. {most_queue-1.54 → most_queue-1.56}/most_queue/general/conv.py +0 -0
  69. {most_queue-1.54 → most_queue-1.56}/most_queue/general/distribution_params.py +0 -0
  70. {most_queue-1.54 → most_queue-1.56}/most_queue/general/interfaces.py +0 -0
  71. {most_queue-1.54 → most_queue-1.56}/most_queue/misc/flow_sum.py +0 -0
  72. {most_queue-1.54 → most_queue-1.56}/most_queue/misc/test_weibull.py +0 -0
  73. {most_queue-1.54 → most_queue-1.56}/most_queue/rand_distribution.py +0 -0
  74. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/__init__.py +0 -0
  75. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/flow_sum.py +0 -0
  76. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/networks/__init__.py +0 -0
  77. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/networks/priority_network.py +0 -0
  78. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/queueing_systems/__init__.py +0 -0
  79. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/queueing_systems/priority.py +0 -0
  80. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/utils/__init__.py +0 -0
  81. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/utils/distribution_utils.py +0 -0
  82. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/utils/exceptions.py +0 -0
  83. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/utils/phase.py +0 -0
  84. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/utils/qs.py +0 -0
  85. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/utils/qs_queue.py +0 -0
  86. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/utils/servers.py +0 -0
  87. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/utils/stats_update.py +0 -0
  88. {most_queue-1.54 → most_queue-1.56}/most_queue/sim/utils/tasks.py +0 -0
  89. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/__init__.py +0 -0
  90. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/networks/__init__.py +0 -0
  91. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/networks/network_viewer.py +0 -0
  92. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/__init__.py +0 -0
  93. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/batch/__init__.py +0 -0
  94. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/batch/mm1.py +0 -0
  95. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/closed/__init__.py +0 -0
  96. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/closed/engset.py +0 -0
  97. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/fifo/__init__.py +0 -0
  98. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/fifo/ek_d_n.py +0 -0
  99. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/fifo/gi_m_1.py +0 -0
  100. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/fifo/gi_m_n.py +0 -0
  101. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/fifo/m_d_n.py +0 -0
  102. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/fifo/mg1.py +0 -0
  103. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/fifo/mmnr.py +0 -0
  104. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/fork_join/__init__.py +0 -0
  105. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/fork_join/m_m_n.py +0 -0
  106. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/fork_join/split_join.py +0 -0
  107. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/impatience/__init__.py +0 -0
  108. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/impatience/mm1.py +0 -0
  109. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/priority/__init__.py +0 -0
  110. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/priority/mgn_invar_approx.py +0 -0
  111. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/priority/non_preemptive/__init__.py +0 -0
  112. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/priority/non_preemptive/mg1.py +0 -0
  113. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/priority/preemptive/__init__.py +0 -0
  114. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/priority/preemptive/m_ph_n_busy_approx.py +0 -0
  115. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/priority/preemptive/mg1.py +0 -0
  116. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/priority/preemptive/mmn_2cls_pr_busy_approx.py +0 -0
  117. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/priority/preemptive/mmn_3cls_busy_approx.py +0 -0
  118. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/vacations/__init__.py +0 -0
  119. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/vacations/m_h2_h2warm.py +0 -0
  120. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/vacations/mg1_warm_calc.py +0 -0
  121. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/queueing_systems/vacations/mgn_with_h2_delay_cold_warm.py +0 -0
  122. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/r_example.gexf +0 -0
  123. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/utils/__init__.py +0 -0
  124. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/utils/binom_probs.py +0 -0
  125. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/utils/busy_periods.py +0 -0
  126. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/utils/diff5dots.py +0 -0
  127. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/utils/flow_sum.py +0 -0
  128. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/utils/passage_time.py +0 -0
  129. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/utils/q_poisson_arrival_calc.py +0 -0
  130. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/utils/student_stat.py +0 -0
  131. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/utils/transforms.py +0 -0
  132. {most_queue-1.54 → most_queue-1.56}/most_queue/theory/utils/weibull.py +0 -0
  133. {most_queue-1.54 → most_queue-1.56}/requirements.txt +0 -0
  134. {most_queue-1.54 → most_queue-1.56}/tests/__init__.py +0 -0
  135. {most_queue-1.54 → most_queue-1.56}/tests/n_test/ro_0.700.json +0 -0
  136. {most_queue-1.54 → most_queue-1.56}/tests/ro_test/n_3.json +0 -0
  137. {most_queue-1.54 → most_queue-1.56}/tests/test_batch.py +0 -0
  138. {most_queue-1.54 → most_queue-1.56}/tests/test_fj_delta.py +0 -0
  139. {most_queue-1.54 → most_queue-1.56}/tests/test_fj_im.py +0 -0
  140. {most_queue-1.54 → most_queue-1.56}/tests/test_impatience.py +0 -0
  141. {most_queue-1.54 → most_queue-1.56}/tests/test_m_ph_n_prty.py +0 -0
  142. {most_queue-1.54 → most_queue-1.56}/tests/test_mmn3_pnz_cox_approx.py +0 -0
  143. {most_queue-1.54 → most_queue-1.56}/tests/test_mmn_prty_pnz_approx.py +0 -0
  144. {most_queue-1.54 → most_queue-1.56}/tests/test_network_im_prty.py +0 -0
  145. {most_queue-1.54 → most_queue-1.56}/tests/test_qs_sim_prty.py +0 -0
@@ -161,3 +161,5 @@ cython_debug/
161
161
  #.idea/
162
162
 
163
163
  .vscode
164
+
165
+ /works/results/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: most_queue
3
- Version: 1.54
3
+ Version: 1.56
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>
@@ -138,6 +138,14 @@ Most_queue consists of two main parts:
138
138
  |-----|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|-------------------|
139
139
  | 1. | M/M/1/D | Solving for M/M/1 with exponential impatience | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_impatience.py) | |
140
140
 
141
+
142
+ ### QS with Negative arrivals
143
+ | # | Kendall Notations | Description | Example | Tutorial |
144
+ |-----|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|-------------------|
145
+ | 1. | M/G/c RCS | Numerical calculation of M/G/c with RCS (remove customer from service) negative arrivals. Service time approximates by H<SUB>2</SUB> distribution | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_mgn_rcs.py) | |
146
+ | 2. | M/G/c disaster | Numerical calculation of M/G/c with disaster (remove all customer from service and queue by negative arrival). Service time approximates by H<SUB>2</SUB> distribution | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_mgn_disaster.py) | |
147
+
148
+
141
149
  ### Closed QS (with finite number of sources)
142
150
  | # | Kendall Notations | Description | Example | Tutorial |
143
151
  |-----|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|-------------------|
@@ -98,6 +98,14 @@ Most_queue consists of two main parts:
98
98
  |-----|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|-------------------|
99
99
  | 1. | M/M/1/D | Solving for M/M/1 with exponential impatience | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_impatience.py) | |
100
100
 
101
+
102
+ ### QS with Negative arrivals
103
+ | # | Kendall Notations | Description | Example | Tutorial |
104
+ |-----|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|-------------------|
105
+ | 1. | M/G/c RCS | Numerical calculation of M/G/c with RCS (remove customer from service) negative arrivals. Service time approximates by H<SUB>2</SUB> distribution | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_mgn_rcs.py) | |
106
+ | 2. | M/G/c disaster | Numerical calculation of M/G/c with disaster (remove all customer from service and queue by negative arrival). Service time approximates by H<SUB>2</SUB> distribution | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_mgn_disaster.py) | |
107
+
108
+
101
109
  ### Closed QS (with finite number of sources)
102
110
  | # | Kendall Notations | Description | Example | Tutorial |
103
111
  |-----|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|-------------------|
@@ -0,0 +1,52 @@
1
+ """
2
+ Conditional moments of random variables.
3
+ """
4
+ import math
5
+
6
+ import numpy as np
7
+
8
+ from most_queue.general.distribution_params import H2Params
9
+
10
+
11
+ def moments_h2_less_than_exp(gamma: float, h2_params: H2Params):
12
+ """
13
+ Compute the initial moments mean of Y given Y < X,
14
+ where Y is a hyperexponential random variable with parameters p1, mu1, and mu2.
15
+ X is exponentially distributed with rate gamma.
16
+ """
17
+ y = [h2_params.p1, 1-h2_params.p1]
18
+ mu = [h2_params.mu1, h2_params.mu2]
19
+ ps = [y[i]*mu[i] for i in range(2)]
20
+
21
+ coef = sum([y[i]*mu[i]/(mu[i]+gamma) for i in range(2)])
22
+
23
+ b = [sum([math.factorial(k+1)*ps[i]/pow(mu[i]+gamma, k+2)
24
+ for i in range(2)])/coef for k in range(3)]
25
+
26
+ return np.array([mom.real for mom in b])
27
+
28
+
29
+ def moments_exp_less_than_h2(gamma: float, h2_params: H2Params):
30
+ """
31
+ Compute the initial moments mean of X given X < Y,
32
+ where X is exponentially distributed with rate gamma.
33
+ Y is a hyperexponential random variable with parameters p1, mu1, and mu2.
34
+
35
+ 1. f_{X|X<Y}(x) = f_X(x) * P(Y > x) / P(X < Y)
36
+ 2. P(Y > x) = ∫_{x}^{∞} [p1mu1exp(-mu1y) + (1-p1)mu2exp(-mu2y)] dy
37
+ 3. P(X < Y) = ∫_{0}^{∞} f_X(x) * P(Y > x) dx
38
+ 4. f_{X|X<Y}(x) = gamma * exp(-gamma*x) * P(Y > x) / P(X < Y)
39
+ """
40
+ p1, mu1, mu2 = h2_params.p1, h2_params.mu1, h2_params.mu2
41
+ y = [p1, 1-p1]
42
+ mu = [mu1, mu2]
43
+ denominator = np.sum([y[i]/(mu[i]+gamma) for i in range(2)])
44
+ b = []
45
+
46
+ # Step 2: Compute the Numerator
47
+ for k in range(3):
48
+ numerator = math.factorial(
49
+ k+1) * np.sum([y[i] / (mu[i]+gamma)**(k+2) for i in range(2)])
50
+ b.append(numerator / denominator)
51
+
52
+ return np.array([mom.real for mom in b])
@@ -0,0 +1,65 @@
1
+ from enum import Enum
2
+
3
+ import matplotlib.pyplot as plt
4
+
5
+ class DependsType(Enum):
6
+ """
7
+ Enum to specify the type of dependency for plotting.
8
+ """
9
+ NONE = 0
10
+ UTILIZATION_FACTOR = 1
11
+ CHANNELS_NUMBER = 2
12
+ COEFFICIENT_OF_VARIATION = 3
13
+
14
+
15
+ def plot_sim_vs_calc_moments(xs: list[float], sim_results: list[float],
16
+ calc_results: list[float],
17
+ depends_on: DependsType = DependsType.CHANNELS_NUMBER,
18
+ is_errors=False, is_waiting_time=True, save_path=None):
19
+ """
20
+ Plots the simulation and calculated moments for a given list of x values.
21
+ :param xs: A list of x values (e.g., utilization factors or number of channels).
22
+ :type xs: list[float]
23
+ :param sim_results: A list of simulated results.
24
+ :type sim_results: list[float]
25
+ :param calc_results: A list of calculated results using some analytical or numerical method.
26
+ :param depends_on: The type of dependency for plotting (utilization factor, number of channels, etc.).
27
+ :type depends_on: DependsType
28
+ :param is_errors: If True, plots the percentage error between simulation and calculation results.
29
+ :type is_errors: bool
30
+ :param is_waiting_time: If True, labels the y-axis as waiting time; otherwise, as soujourn time.
31
+ :type is_waiting_time: bool
32
+ :param save_path: The path where the plot should be saved. If None, the plot will not be saved.
33
+ :type save_path: str or NoneType
34
+ :return: None
35
+ """
36
+ _fig, ax = plt.subplots()
37
+ if is_errors:
38
+ errors = [100 * (w_sim - w_tt) / w_tt for w_sim,
39
+ w_tt in zip(sim_results, calc_results)]
40
+
41
+ ax.plot(xs, errors)
42
+ ax.set_ylabel(r"$\varepsilon$, %")
43
+ else:
44
+ ax.plot(xs, sim_results, label="Sim")
45
+ ax.plot(xs, calc_results, label="Calc")
46
+ if is_waiting_time:
47
+ ax.set_ylabel(r"$\omega_{1}$")
48
+ else:
49
+ ax.set_ylabel(r"$\upsilon_{1}$")
50
+ plt.legend()
51
+
52
+ if depends_on == DependsType.UTILIZATION_FACTOR:
53
+ ax.set_xlabel(r"$\rho$")
54
+ elif depends_on == DependsType.COEFFICIENT_OF_VARIATION:
55
+ ax.set_xlabel(r"$\nu$")
56
+ else:
57
+ ax.set_xlabel("n")
58
+ plt.xticks(range(1, len(xs) + 1))
59
+
60
+ if save_path is not None:
61
+ plt.savefig(save_path, dpi=300)
62
+ else:
63
+ plt.show()
64
+
65
+ plt.close(_fig)
@@ -8,7 +8,7 @@ from colorama import Fore, Style, init
8
8
  init()
9
9
 
10
10
 
11
- def times_print(sim_moments, calc_moments, is_w=True):
11
+ def times_print(sim_moments, calc_moments, is_w=True, header=None):
12
12
  """
13
13
  Prints the initial moments of waiting or sojourn time in the system.
14
14
  Args:
@@ -17,15 +17,16 @@ def times_print(sim_moments, calc_moments, is_w=True):
17
17
  is_w (bool, optional): If True, prints waiting time moments. Otherwise, prints sojourn time moments. Defaults to True.
18
18
 
19
19
  """
20
- if is_w:
21
- spec = 'waiting'
22
- else:
23
- spec = 'soujorn'
24
20
 
25
- header = f'Initial moments of {spec} time in the system'
26
-
27
- print(Fore.CYAN + f'\r{header}')
21
+ if header is None:
22
+ if is_w:
23
+ spec = 'waiting'
24
+ else:
25
+ spec = 'soujorn'
26
+ header = f'Initial moments of {spec} time in the system'
28
27
 
28
+ print(Fore.CYAN + f'\n{header:^45}')
29
+ print("-" * 45)
29
30
  print("{0:^15s}|{1:^15s}|{2:^15s}".format("#", "Num", "Sim"))
30
31
  print("-" * 45)
31
32
  if isinstance(sim_moments, list):
@@ -1,11 +1,8 @@
1
1
  import json
2
2
  import math
3
3
 
4
- import matplotlib
5
4
  import matplotlib.pyplot as plt
6
5
 
7
- matplotlib.use('TkAgg')
8
-
9
6
 
10
7
  def print_table(experiments_stat):
11
8
  """
@@ -84,7 +81,7 @@ def calc_moments_by_mean_and_coev(mean, coev):
84
81
 
85
82
 
86
83
  def make_plot(experiments_stat, w_moments_num=0,
87
- param_name="ro", mode='error'):
84
+ param_name="ro", mode='error', save_path=None):
88
85
  """
89
86
  Build plot for wait times initial moments
90
87
  :param experiments_stat: list of experiment statistics
@@ -93,7 +90,7 @@ def make_plot(experiments_stat, w_moments_num=0,
93
90
  :param mode: 'error' or 'mass' - whether to plot errors or mass values
94
91
  :return: figure and axis objects
95
92
  """
96
- fig, ax = plt.subplots()
93
+ _fig, ax = plt.subplots()
97
94
  w_sim_mass = []
98
95
  w_tt_mass = []
99
96
  xs = []
@@ -132,4 +129,7 @@ def make_plot(experiments_stat, w_moments_num=0,
132
129
  elif param_name == "delay_mean":
133
130
  ax.set_xlabel("t, с")
134
131
 
135
- plt.show()
132
+ if save_path:
133
+ plt.savefig(save_path, dpi=300)
134
+ else:
135
+ plt.show()
@@ -0,0 +1,314 @@
1
+ """
2
+ Calculate M/H2/n queue with negative jobs with RCS discipline,
3
+ (remove customer from service)
4
+ """
5
+ import math
6
+ from functools import lru_cache
7
+
8
+ import numpy as np
9
+ from scipy.misc import derivative
10
+
11
+ from most_queue.general.conv import conv_moments
12
+ from most_queue.theory.queueing_systems.fifo.mgn_takahasi import MGnCalc
13
+ from most_queue.theory.utils.transforms import (
14
+ laplace_stieltjes_exp_transform as lst_exp,
15
+ )
16
+ from most_queue.rand_distribution import H2Distribution, H2Params
17
+
18
+ class MGnNegativeRCSCalc(MGnCalc):
19
+ """
20
+ Calculate M/H2/n queue with negative jobs with RCS discipline,
21
+ (remove customer from service)
22
+ """
23
+
24
+ def __init__(self, n: int, l_pos: float, l_neg: float, b: list[float],
25
+ buffer: int | None = None, N: int = 150,
26
+ accuracy: float = 1e-6, dtype="c16", verbose: bool = False):
27
+ """
28
+ n: number of servers
29
+ l: arrival rate of positive jobs
30
+ l_neg: arrival rate of negative jobs
31
+ b: initial moments of service time distribution
32
+ buffer: size of the buffer (optional)
33
+ N: number of levels in the system (default is 150)
34
+ accuracy: accuracy parameter for stopping the iteration
35
+ dtype: data type for calculations (default is complex double precision)
36
+ verbose: whether to print intermediate results (default is False)
37
+ """
38
+
39
+ self.l_neg = l_neg
40
+
41
+ super().__init__(n=n, l=l_pos, b=b, buffer=buffer, N=N,
42
+ accuracy=accuracy, dtype=dtype, verbose=verbose)
43
+
44
+ def get_q(self) -> float:
45
+ """
46
+ Calculation of the conditional probability of successful service completion at a node
47
+ """
48
+ return 1.0 - (self.l_neg/self.l)*(1.0-self.p[0].real)
49
+
50
+ def get_w(self, derivate=False) -> list[float]:
51
+ """
52
+ Get the waiting time moments
53
+ """
54
+
55
+ w = [0.0] * 3
56
+
57
+ if derivate:
58
+ for i in range(3):
59
+ w[i] = derivative(self._calc_w_pls, 0,
60
+ dx=1e-3 / self.b[0], n=i + 1, order=9)
61
+ return np.array([-w[0], w[1].real, -w[2]])
62
+
63
+ for j in range(1, len(self.p) - self.n):
64
+ w[0] += j * self.p[self.n + j]
65
+ for j in range(2, len(self.p) - self.n):
66
+ w[1] += j * (j - 1) * self.p[self.n + j]
67
+ for j in range(3, len(self.p) - self.n):
68
+ w[2] += j * (j - 1) * (j - 2) * self.p[self.n + j]
69
+
70
+ for j in range(3):
71
+ w[j] /= math.pow(self.l, j + 1)
72
+ w[j] = w[j].real
73
+
74
+ return np.array(w)
75
+
76
+ def _get_key_numbers(self, level):
77
+ key_numbers = []
78
+ if level >= self.n:
79
+ for i in range(level + 1):
80
+ key_numbers.append((self.n - i, i))
81
+ else:
82
+ for i in range(level + 1):
83
+ key_numbers.append((level - i, i))
84
+ return np.array(key_numbers, dtype=self.dt)
85
+
86
+ def _calc_up_probs(self, from_level):
87
+ if from_level == self.n:
88
+ return np.eye(self.n + 1)
89
+ b_matrix = self.B[from_level]
90
+ probs = []
91
+ for i in range(self.cols[from_level - 1]):
92
+ probs_on_level = []
93
+ for j in range(self.cols[from_level - 1]):
94
+ if from_level != 1:
95
+ probs_on_level.append(b_matrix[i, j] / sum(b_matrix[i, :]))
96
+ else:
97
+ probs_on_level.append(b_matrix[i, 0] / sum(b_matrix[i, :]))
98
+ probs.append(probs_on_level)
99
+ return np.array(probs, dtype=self.dt)
100
+
101
+ def _matrix_pow(self, matrix, k):
102
+ res = np.eye(self.n + 1, dtype=self.dt)
103
+ for i in range(k):
104
+ res = np.dot(res, matrix)
105
+ return res
106
+
107
+ @lru_cache
108
+ def _build_probs_down(self, num):
109
+ """
110
+ Create matrix with transition down probs by the given level number.
111
+ """
112
+ if num < self.n:
113
+ col = self.cols[num + 1]
114
+ row = self.cols[num]
115
+ else:
116
+ col = self.cols[self.n]
117
+ row = self.cols[self.n]
118
+
119
+ output = np.zeros((row, col), dtype=self.dt)
120
+
121
+ if num > self.n:
122
+ output = self._build_probs_down(self.n)
123
+ return output
124
+
125
+ for i in range(row):
126
+ if num < self.n:
127
+ output[i, i] = self.y[0]
128
+ output[i, i + 1] = self.y[1]
129
+ else:
130
+ output[i, i] = 1.0
131
+
132
+ return output
133
+
134
+ def _calc_v_pls(self, s) -> float:
135
+
136
+ v = 0
137
+
138
+ for k in range(self.n):
139
+ # When arrived, job see current state, move to next and need to serve on it
140
+ # so, we work with next levels (for example, k + 1 instead k)
141
+
142
+ # for k=1, [(2,0), (1,1), (0, 2)]
143
+ key_numbers = self._get_key_numbers(k+1)
144
+
145
+ # LST for serving in next state, for k=1, size=(1, 3)
146
+ a = np.array(
147
+ [lst_exp(key_numbers[j][0] * self.mu[0] + key_numbers[j][1] * self.mu[1] + self.l_neg, s) for j in
148
+ range(k + 2)])
149
+
150
+ # P - down transition matrix, for k=1 size = (2, 3)
151
+ # for 1 state y1 y2 0
152
+ # 0 y1 y2
153
+ P = self._build_probs_down(k)
154
+ # current state, for k=1 size = (1, 2)
155
+ Ys = np.array([self.Y[k][0, i] for i in range(k + 1)])
156
+
157
+ v_tek = np.dot(Ys, P.dot(a.T))
158
+
159
+ v += v_tek
160
+
161
+ key_numbers = self._get_key_numbers(self.n)
162
+
163
+ a_n = np.array(
164
+ [lst_exp(key_numbers[j][0] * self.mu[0] + key_numbers[j][1] * self.mu[1] + self.l_neg, s) for j in
165
+ range(self.n + 1)])
166
+
167
+ Pn_plus = self._calc_up_probs(self.n + 1) # size=(4, 4)
168
+
169
+ Pa = Pn_plus*a_n # 4,4
170
+
171
+ PdotaT = Pn_plus.dot(a_n.T) # 4,1
172
+
173
+ prod = np.eye(self.n+1)
174
+
175
+ for k in range(self.n, self.N):
176
+
177
+ Ys = np.array([self.Y[k][0, i]
178
+ for i in range(self.n + 1)]) # (1, 4)
179
+
180
+ ya = Ys*a_n # 1,4
181
+
182
+ v += np.dot(ya, prod.dot(PdotaT))
183
+
184
+ prod = prod.dot(Pa)
185
+
186
+ return v
187
+
188
+ def _calc_w_pls(self, s) -> float:
189
+ """
190
+ Calculate Laplace-Stietjes transform of the waiting time distribution.
191
+ :param s: Laplace variable
192
+ :return: Laplace-Stieltjes transform of the waiting time distribution
193
+ """
194
+ w = 0
195
+
196
+ key_numbers = self._get_key_numbers(self.n)
197
+
198
+ a = np.array(
199
+ [lst_exp(key_numbers[j][0] * self.mu[0] + key_numbers[j][1] * self.mu[1] + self.l_neg, s) for j in
200
+ range(self.n + 1)])
201
+
202
+ Pn_plus = self._calc_up_probs(self.n+1)
203
+
204
+ for k in range(self.n, self.N):
205
+
206
+ Pa = np.transpose(self._matrix_pow(
207
+ Pn_plus * a, k - self.n)) # n+1 x n+1
208
+
209
+ Ys = [self.Y[k][0, i] for i in range(self.n + 1)]
210
+ aPa = np.dot(a, Pa)
211
+ for i in range(self.n + 1):
212
+ w += Ys[i] * aPa[i]
213
+
214
+ return w
215
+
216
+ def get_v(self) -> list[float]:
217
+ """
218
+ Get the sojourn time moments
219
+ """
220
+ w = self.get_w(derivate=False)
221
+
222
+ # serving = min(H2_b, exp(l_neg)) = H2(y1=y1, mu1 = mu1+l_neg, mu2=mu2+l_neg)
223
+
224
+ params = H2Params(p1=self.y[0],
225
+ mu1=self.mu[0],
226
+ mu2=self.mu[1])
227
+ #
228
+ l_neg = 0
229
+ for i in range(1, self.n):
230
+ l_neg += self.p[i]*self.l_neg/i
231
+
232
+
233
+ b = H2Distribution.calc_theory_moments(H2Params(p1=params.p1,
234
+ mu1=l_neg + params.mu1,
235
+ mu2=l_neg + params.mu2))
236
+
237
+ return conv_moments(w, b)
238
+
239
+ def _build_big_b_matrix(self, num):
240
+ """
241
+ Create matrix B by the given level number.
242
+ """
243
+ if num == 0:
244
+ return np.zeros((1, 1), dtype=self.dt)
245
+
246
+ if num <= self.n:
247
+ col = self.cols[num - 1]
248
+ row = self.cols[num]
249
+ else:
250
+ col = self.cols[self.n + 1]
251
+ row = self.cols[self.n + 1]
252
+
253
+ output = np.zeros((row, col), dtype=self.dt)
254
+
255
+ if num > self.n + 1:
256
+ output = self.B[self.n + 1]
257
+ return output
258
+
259
+ for i in range(col):
260
+ if num <= self.n:
261
+ # key has two parts: left and right, like 21
262
+ # fill B matrix by pattern of 2 elements:
263
+ # up arrow, arrow from next to current key
264
+ # x 0
265
+ # x y
266
+ # 0 y
267
+ first_neg, second_neg = self.l_neg * \
268
+ (num-i)/num, self.l_neg*(i+1)/num
269
+ output[i, i] = (num - i) * self.mu[0] + first_neg
270
+ output[i + 1, i] = (i + 1) * self.mu[1] + second_neg
271
+ else:
272
+ # key has two parts: left and right, like 21
273
+ # fill B matrix by pattern of 3 elements:
274
+ # up arrow, right arrow, arrow from next to current key
275
+ # x x 0
276
+ # x y y
277
+ # 0 y 0
278
+ left = self.l_neg * (num-i-1)/(num-1)
279
+ right = self.l_neg * i/(num-1)
280
+ left_from_next = self.l_neg*(i+1)/(num-1)
281
+
282
+ output[i, i] = ((num - i - 1) * self.mu[0] + left) * \
283
+ self.y[0] + (i * self.mu[1] + right) * self.y[1]
284
+
285
+ if i != num - 1:
286
+ output[i, i + 1] = ((num - i - 1) * self.mu[0] +
287
+ left) * self.y[1]
288
+
289
+ output[i + 1, i] = ((i + 1) * self.mu[1] +
290
+ left_from_next) * self.y[0]
291
+ return output
292
+
293
+ def _build_big_d_matrix(self, num):
294
+ """
295
+ Create matrix D by the given level number.
296
+ """
297
+ if num < self.n:
298
+ col = self.cols[num]
299
+ row = col
300
+ else:
301
+ col = self.cols[self.n]
302
+ row = col
303
+
304
+ output = np.zeros((row, col), dtype=self.dt)
305
+
306
+ if num > self.n:
307
+ output = self.D[self.n]
308
+ return output
309
+
310
+ for i in range(row):
311
+ output[i, i] = self.l + self.l_neg + \
312
+ (num - i) * self.mu[0] + i * self.mu[1]
313
+
314
+ return output
@@ -1,29 +1,35 @@
1
- import matplotlib
1
+ """
2
+ Test approximation for Fork-Join queues
3
+ """
2
4
  import matplotlib.pyplot as plt
3
5
 
4
6
  from most_queue.sim.queueing_systems.fork_join import ForkJoinSim
5
- from most_queue.theory.fork_join.m_m_n import (
6
- get_v1_fj_nelson_tantawi,
7
- get_v1_fj_varki_merchant,
8
- get_v1_fj_varma,
9
- )
7
+ from most_queue.theory.queueing_systems.fork_join.m_m_n import \
8
+ ForkJoinMarkovianCalc
10
9
 
11
- matplotlib.use('TkAgg')
10
+
11
+ def calc_error(calc:float, sim:float)->float:
12
+ """
13
+ Вычисление относительной ошибки аппроксимации
14
+ :param calc: объект класса ForkJoinMarkovianCalc
15
+ :param sim: объект класса ForkJoinSim
16
+ :return:
17
+ """
18
+ return 100*(calc-sim)/calc
12
19
 
13
20
 
14
21
  def test_fj_calc():
15
22
  """
16
23
  Тестирование аппроксимаций для системы Fork-Join
17
- В пакете theory.fj_calc модержатся следующие методы:
24
+ - R. D. Nelson and A. N. Tantawi, “Approximate analysis of fork/join
25
+ synchronization in parallel queues.” IEEE Trans. Computers, vol. 37,
26
+ no. 6, pp. 739–743, 1988.
18
27
 
19
- get_v1_fj_nelson_tantawi - R. D. Nelson and A. N. Tantawi, “Approximate analysis of fork/join
20
- synchronization in parallel queues.” IEEE Trans. Computers, vol. 37, no. 6, pp. 739–743, 1988.
28
+ - S. Varma and A. M. Makowski, “Interpolation approximations for
29
+ symmetric fork-join queues.” Perform. Eval., vol. 20, no. 1, pp. 245–265, 1994.
21
30
 
22
- get_v1_fj_varma - S. Varma and A. M. Makowski, “Interpolation approximations for
23
- symmetric fork-join queues.” Perform. Eval., vol. 20, no. 1, pp. 245–265, 1994.
24
-
25
- get_v1_fj_varki_merchant - E. Varki, “Response time analysis of parallel computer and storage
26
- systems.” IEEE Trans. Parallel Distrib. Syst., 2001.
31
+ - E. Varki, “Response time analysis of parallel computer and storage
32
+ systems.” IEEE Trans. Parallel Distrib. Syst., 2001.
27
33
 
28
34
  Для верификации используем имитационное моделирование (ИМ).
29
35
 
@@ -56,10 +62,12 @@ def test_fj_calc():
56
62
 
57
63
  qs = ForkJoinSim(nn, nn, False)
58
64
 
59
- # задаем входной поток. Методу нужно передать параметры распределения и тип распределения. М - экспоненциальное
65
+ # задаем входной поток. Методу нужно передать параметры распределения и тип распределения.
66
+ # М - экспоненциальное
60
67
  qs.set_sources(l, 'M')
61
68
 
62
- # задаем каналы обслуживания. Методу нужно передать параметры распределения и тип распределения. М - экспоненциальное
69
+ # задаем каналы обслуживания. Методу нужно передать параметры распределения и тип распределения.
70
+ # М - экспоненциальное
63
71
  qs.set_servers(mu, 'M')
64
72
 
65
73
  # запускаем ИМ
@@ -73,15 +81,17 @@ def test_fj_calc():
73
81
  # расчет средних времен пребывания с помощью аппроксимаций. \
74
82
  # На вход каждого из методов - l, mu, nn (число каналов СМО)
75
83
 
76
- v_varki.append(get_v1_fj_varki_merchant(l, mu, nn))
77
- v_varma.append(get_v1_fj_varma(l, mu, nn))
78
- v_nelson.append(get_v1_fj_nelson_tantawi(l, mu, nn))
84
+ calcs = ForkJoinMarkovianCalc(l, mu, nn)
85
+
86
+ v_varki.append(calcs.get_v1_fj_varki_merchant())
87
+ v_varma.append(calcs.get_v1_fj_varma())
88
+ v_nelson.append(calcs.get_v1_fj_nelson_tantawi())
79
89
 
80
90
  print(str_f_v.format(v_sim[i], v_varki[i], v_varma[i], v_nelson[i]))
81
91
 
82
92
  # строим графики и сохраняем в текущую директорию:
83
93
 
84
- fig, ax = plt.subplots()
94
+ _fig, ax = plt.subplots()
85
95
 
86
96
  linestyles = ["solid", "dotted", "dashed", "dashdot"]
87
97
 
@@ -94,19 +104,14 @@ def test_fj_calc():
94
104
  ax.set_xlabel("n")
95
105
 
96
106
  plt.legend()
97
- plt.savefig("v1_from_n_with_ro = {0:^4.2f}.png".format(ro), dpi=300)
107
+ plt.savefig(f"v1_from_n_with_ro = {ro:^4.2f}.png", dpi=300)
98
108
 
99
109
  # errors
100
- v_nelson_err = []
101
- v_varma_err = []
102
- v_varki_err = []
103
-
104
- for i in range(len(v_sim)):
105
- v_varma_err.append(100 * (v_varma[i] - v_sim[i]) / v_sim[i])
106
- v_varki_err.append(100 * (v_varki[i] - v_sim[i]) / v_sim[i])
107
- v_nelson_err.append(100 * (v_nelson[i] - v_sim[i]) / v_sim[i])
110
+ v_varma_err = [calc_error(v, s) for v, s in zip(v_varma, v_sim)]
111
+ v_varki_err = [calc_error(v, s) for v, s in zip(v_varki, v_sim)]
112
+ v_nelson_err = [calc_error(v, s) for v, s in zip(v_nelson, v_sim)]
108
113
 
109
- fig, ax = plt.subplots()
114
+ _fig, ax = plt.subplots()
110
115
  ax.plot(n, v_varki_err, label="Varki", linestyle=linestyles[0])
111
116
  ax.plot(n, v_varma_err, label="Varma", linestyle=linestyles[1])
112
117
  ax.plot(n, v_nelson_err, label="Nelson", linestyle=linestyles[2])
@@ -115,7 +120,7 @@ def test_fj_calc():
115
120
  ax.set_xlabel("n")
116
121
 
117
122
  plt.legend()
118
- plt.savefig("error_from_n_with_ro = {0:^4.2f}.png".format(ro), dpi=300)
123
+ plt.savefig(f"error_from_n_with_ro = {ro:^4.2f}.png", dpi=300)
119
124
 
120
125
 
121
126
  if __name__ == "__main__":