most-queue 1.53__tar.gz → 1.55__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.53 → most_queue-1.55}/PKG-INFO +15 -2
- {most_queue-1.53 → most_queue-1.55}/README.md +14 -1
- most_queue-1.55/most_queue/general/conditional.py +58 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/general/conv.py +12 -4
- {most_queue-1.53 → most_queue-1.55}/most_queue/general/distribution_params.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/general/interfaces.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/general/tables.py +9 -8
- {most_queue-1.53 → most_queue-1.55}/most_queue/general/vacations_paper_utils.py +0 -0
- most_queue-1.55/most_queue/misc/calc_v_pls.py +314 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/rand_distribution.py +5 -5
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/networks/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/queueing_systems/__init__.py +0 -0
- most_queue-1.55/most_queue/sim/queueing_systems/negative.py +532 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/utils/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/utils/distribution_utils.py +30 -30
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/utils/exceptions.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/utils/phase.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/utils/qs.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/utils/qs_queue.py +24 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/utils/servers.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/utils/stats_update.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/utils/tasks.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/networks/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/networks/open_network.py +1 -1
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/batch/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/closed/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/fifo/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/fifo/mgn_takahasi.py +20 -16
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/fork_join/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/impatience/__init__.py +0 -0
- most_queue-1.55/most_queue/theory/queueing_systems/negative/mgn_disaster.py +329 -0
- most_queue-1.55/most_queue/theory/queueing_systems/negative/mgn_rcs.py +192 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/priority/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/priority/mgn_invar_approx.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/priority/non_preemptive/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/priority/non_preemptive/mg1.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/priority/preemptive/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/priority/preemptive/mg1.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/vacations/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/vacations/m_h2_h2warm.py +3 -11
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/vacations/mgn_with_h2_delay_cold_warm.py +5 -16
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/vacations/mmn_with_h2_cold_and_h2_warmup.py +1 -12
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/utils/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/utils/busy_periods.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/utils/transforms.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/pyproject.toml +1 -1
- {most_queue-1.53 → most_queue-1.55}/setup.py +1 -1
- {most_queue-1.53 → most_queue-1.55}/tests/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/n_test/ro_0.700.json +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/ro_test/n_3.json +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_ek_d_n.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_engset.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_impatience.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_m_h2_h2warm.py +1 -1
- most_queue-1.55/tests/test_mgn_disaster.py +76 -0
- most_queue-1.55/tests/test_mgn_rcs.py +77 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_mmn_h2cold_h2warm.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_queue_types.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/.gitignore +0 -0
- {most_queue-1.53 → most_queue-1.55}/LICENSE +0 -0
- {most_queue-1.53 → most_queue-1.55}/assets/queue_long.png +0 -0
- {most_queue-1.53 → most_queue-1.55}/deploy.txt +0 -0
- {most_queue-1.53 → most_queue-1.55}/docs/Makefile +0 -0
- {most_queue-1.53 → most_queue-1.55}/docs/make.bat +0 -0
- {most_queue-1.53 → most_queue-1.55}/docs/source/conf.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/docs/source/index.rst +0 -0
- {most_queue-1.53 → most_queue-1.55}/docs/source/modules.rst +0 -0
- {most_queue-1.53 → most_queue-1.55}/docs/source/most_queue.rst +0 -0
- {most_queue-1.53 → most_queue-1.55}/docs/source/most_queue.sim.rst +0 -0
- {most_queue-1.53 → most_queue-1.55}/docs/source/most_queue.theory.rst +0 -0
- {most_queue-1.53 → most_queue-1.55}/googleb31d3dccb40f969f.html +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/general/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/general/approx_cdf_make.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/misc/compare_fj_calc.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/misc/flow_sum.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/misc/test_weibull.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/flow_sum.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/networks/priority_network.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/queueing_systems/batch.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/queueing_systems/fifo.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/queueing_systems/finite_source.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/queueing_systems/fork_join.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/queueing_systems/fork_join_delta.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/queueing_systems/impatient.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/sim/queueing_systems/priority.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/networks/network_viewer.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/__init__.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/batch/mm1.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/closed/engset.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/fifo/ek_d_n.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/fifo/gi_m_1.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/fifo/gi_m_n.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/fifo/m_d_n.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/fifo/mg1.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/fifo/mmnr.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/fork_join/m_m_n.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/fork_join/split_join.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/impatience/mm1.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/priority/preemptive/m_ph_n_busy_approx.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/priority/preemptive/mmn_2cls_pr_busy_approx.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/priority/preemptive/mmn_3cls_busy_approx.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/queueing_systems/vacations/mg1_warm_calc.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/r_example.gexf +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/utils/binom_probs.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/utils/diff5dots.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/utils/flow_sum.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/utils/passage_time.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/utils/q_poisson_arrival_calc.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/utils/student_stat.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/most_queue/theory/utils/weibull.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/requirements.txt +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_batch.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_fj_delta.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_fj_im.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_gi_m_1_calc.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_gi_m_n_calc.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_m_d_n_calc.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_m_ph_n_prty.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_mg1_calc.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_mgn_tt.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_mgn_with_h2_delay_cold_warm.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_mmn3_pnz_cox_approx.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_mmn_prty_pnz_approx.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_network_im_prty.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_qs_sim_prty.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tests/test_qs_sim_test.py +0 -0
- {most_queue-1.53 → most_queue-1.55}/tutorials/m_h2_h2warm.ipynb +0 -0
- {most_queue-1.53 → most_queue-1.55}/tutorials/mgn_takahasi_takami.ipynb +0 -0
- {most_queue-1.53 → most_queue-1.55}/tutorials/priority_queue.ipynb +0 -0
- {most_queue-1.53 → most_queue-1.55}/tutorials/queue_sim.ipynb +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: most_queue
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.55
|
|
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
|
-
|
|
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
|
|
@@ -133,6 +138,14 @@ Most_queue consists of two main parts:
|
|
|
133
138
|
|-----|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|-------------------|
|
|
134
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) | |
|
|
135
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
|
+
|
|
136
149
|
### Closed QS (with finite number of sources)
|
|
137
150
|
| # | Kendall Notations | Description | Example | Tutorial |
|
|
138
151
|
|-----|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|-------------------|
|
|
@@ -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
|
-
|
|
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
|
|
@@ -93,6 +98,14 @@ Most_queue consists of two main parts:
|
|
|
93
98
|
|-----|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|-------------------|
|
|
94
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) | |
|
|
95
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
|
+
|
|
96
109
|
### Closed QS (with finite number of sources)
|
|
97
110
|
| # | Kendall Notations | Description | Example | Tutorial |
|
|
98
111
|
|-----|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|-------------------|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from most_queue.general.distribution_params import H2Params
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def moments_H2_less_than_exp(gamma:float, h2_params:H2Params):
|
|
9
|
+
"""
|
|
10
|
+
Compute the initial moments mean of Y given Y < X,
|
|
11
|
+
where Y is a hyperexponential random variable with parameters p1, mu1, and mu2.
|
|
12
|
+
X is exponentially distributed with rate gamma.
|
|
13
|
+
"""
|
|
14
|
+
y = [h2_params.p1, 1-h2_params.p1]
|
|
15
|
+
mu = [h2_params.mu1, h2_params.mu2]
|
|
16
|
+
ps = [y[i]*mu[i] for i in range(2)]
|
|
17
|
+
|
|
18
|
+
coef = sum([y[i]*mu[i]/(mu[i]+gamma) for i in range(2)])
|
|
19
|
+
|
|
20
|
+
b = [sum([math.factorial(k+1)*ps[i]/pow(mu[i]+gamma, k+2)
|
|
21
|
+
for i in range(2)])/coef for k in range(3)]
|
|
22
|
+
|
|
23
|
+
return np.array([mom.real for mom in b])
|
|
24
|
+
|
|
25
|
+
def moments_exp_less_than_H2(gamma:float, h2_params:H2Params):
|
|
26
|
+
"""
|
|
27
|
+
Compute the initial moments mean of X given X < Y,
|
|
28
|
+
where X is exponentially distributed with rate gamma.
|
|
29
|
+
Y is a hyperexponential random variable with parameters p1, mu1, and mu2.
|
|
30
|
+
|
|
31
|
+
1. f_{X|X<Y}(x) = f_X(x) * P(Y > x) / P(X < Y)
|
|
32
|
+
2. P(Y > x) = ∫_{x}^{∞} [p1mu1exp(-mu1y) + (1-p1)mu2exp(-mu2y)] dy
|
|
33
|
+
3. P(X < Y) = ∫_{0}^{∞} f_X(x) * P(Y > x) dx
|
|
34
|
+
4. f_{X|X<Y}(x) = gamma * exp(-gamma*x) * P(Y > x) / P(X < Y)
|
|
35
|
+
"""
|
|
36
|
+
p1, mu1, mu2 = h2_params.p1, h2_params.mu1, h2_params.mu2
|
|
37
|
+
y = [p1, 1-p1]
|
|
38
|
+
mu = [mu1, mu2]
|
|
39
|
+
denominator = np.sum([y[i]/(mu[i]+gamma) for i in range(2)])
|
|
40
|
+
b = []
|
|
41
|
+
|
|
42
|
+
# Step 2: Compute the Numerator
|
|
43
|
+
for k in range(3):
|
|
44
|
+
numerator = math.factorial(k+1) * np.sum([y[i] / (mu[i]+gamma)**(k+2) for i in range(2)])
|
|
45
|
+
b.append(numerator / denominator)
|
|
46
|
+
|
|
47
|
+
return np.array([mom.real for mom in b])
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
|
|
51
|
+
# Example usage:
|
|
52
|
+
gamma = 1.0
|
|
53
|
+
p1 = 0.5
|
|
54
|
+
mu1 = 2.0
|
|
55
|
+
mu2 = 3.0
|
|
56
|
+
|
|
57
|
+
result = moments_exp_less_than_H2(gamma, H2Params(p1=p1, mu1=mu1, mu2=mu2))
|
|
58
|
+
print(f"The mean of Y given X < Y is: {result}")
|
|
@@ -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
|
-
|
|
52
|
-
|
|
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
|
|
File without changes
|
|
File without changes
|
|
@@ -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,12 +17,13 @@ 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
|
|
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'
|
|
26
27
|
|
|
27
28
|
print(Fore.CYAN + f'\r{header}')
|
|
28
29
|
|
|
@@ -226,11 +227,11 @@ def print_mrx(mrx, is_short=False):
|
|
|
226
227
|
color = Fore.RED
|
|
227
228
|
else:
|
|
228
229
|
color = Fore.GREEN
|
|
229
|
-
if is_short:
|
|
230
|
+
if is_short or mrx[i, j].imag == 0.0:
|
|
230
231
|
print(f"{color}{mrx[i, j].real:^4.2f} | ", end="")
|
|
231
232
|
else:
|
|
232
233
|
print(f"{color}{mrx[i, j]:^5.3f} | ", end="")
|
|
233
|
-
print("\n" + "-------" * col if is_short else "\n" + "---------------" * col)
|
|
234
|
+
print("\n" + "-------" * col if is_short or mrx[i, j].imag == 0.0 else "\n" + "---------------" * col)
|
|
234
235
|
Fore.RESET # Reset colors after each row
|
|
235
236
|
|
|
236
237
|
|
|
File without changes
|
|
@@ -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].real, w[1].real, -w[2].real])
|
|
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
|
|
@@ -572,21 +572,21 @@ class DeterministicDistribution(Distribution):
|
|
|
572
572
|
return DeterministicDistribution.generate_static(self.b)
|
|
573
573
|
|
|
574
574
|
@staticmethod
|
|
575
|
-
def generate_static(
|
|
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
|
|
579
|
+
return params
|
|
580
580
|
|
|
581
581
|
@staticmethod
|
|
582
|
-
def calc_theory_moments(
|
|
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 = [
|
|
589
|
+
moments = [params**i for i in range(1, num+1)]
|
|
590
590
|
return moments
|
|
591
591
|
|
|
592
592
|
@staticmethod
|
|
File without changes
|
|
File without changes
|