most-queue 1.60__tar.gz → 1.61__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.60 → most_queue-1.61}/.gitignore +1 -1
- {most_queue-1.60 → most_queue-1.61}/PKG-INFO +1 -1
- {most_queue-1.60 → most_queue-1.61}/most_queue/general/distribution_params.py +9 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/rand_distribution.py +125 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/fifo/mgn_takahasi.py +61 -1
- most_queue-1.61/most_queue/theory/utils/residual.py +19 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/utils/transforms.py +3 -0
- {most_queue-1.60 → most_queue-1.61}/pyproject.toml +1 -1
- {most_queue-1.60 → most_queue-1.61}/setup.py +1 -1
- {most_queue-1.60 → most_queue-1.61}/tests/test_mgn_tt.py +4 -1
- most_queue-1.61/tests/units/test_tt_up_probs.py +48 -0
- most_queue-1.61/tests/units/test_weibull.py +29 -0
- {most_queue-1.60 → most_queue-1.61}/tutorials/queue_sim.ipynb +1 -1
- most_queue-1.61/works/negative_queues/base_parameters.yaml +21 -0
- most_queue-1.61/works/negative_queues/work_mgn_negatives.py +303 -0
- most_queue-1.61/works/vacations/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/works/vacations/main.py +1 -1
- most_queue-1.60/most_queue/misc/test_weibull.py +0 -37
- most_queue-1.60/most_queue/theory/utils/weibull.py +0 -155
- most_queue-1.60/works/negative_queues/work_mgn_disasters.py +0 -358
- most_queue-1.60/works/negative_queues/work_mgn_rcs.py +0 -358
- {most_queue-1.60 → most_queue-1.61}/LICENSE +0 -0
- {most_queue-1.60 → most_queue-1.61}/README.md +0 -0
- {most_queue-1.60 → most_queue-1.61}/assets/queue_long.png +0 -0
- {most_queue-1.60 → most_queue-1.61}/deploy.txt +0 -0
- {most_queue-1.60 → most_queue-1.61}/docs/Makefile +0 -0
- {most_queue-1.60 → most_queue-1.61}/docs/make.bat +0 -0
- {most_queue-1.60 → most_queue-1.61}/docs/source/conf.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/docs/source/index.rst +0 -0
- {most_queue-1.60 → most_queue-1.61}/docs/source/modules.rst +0 -0
- {most_queue-1.60 → most_queue-1.61}/docs/source/most_queue.rst +0 -0
- {most_queue-1.60 → most_queue-1.61}/docs/source/most_queue.sim.rst +0 -0
- {most_queue-1.60 → most_queue-1.61}/docs/source/most_queue.theory.rst +0 -0
- {most_queue-1.60 → most_queue-1.61}/googleb31d3dccb40f969f.html +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/general/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/general/interfaces.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/general/plots.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/general/tables.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/misc/approx_cdf_make.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/misc/calc_v_pls.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/misc/compare_fj_calc.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/misc/flow_sum.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/misc/vacations_paper_utils.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/base.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/batch.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/finite_source.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/flow_sum.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/fork_join.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/fork_join_delta.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/impatient.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/negative.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/networks/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/networks/priority_network.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/priority.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/utils/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/utils/distribution_utils.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/utils/exceptions.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/utils/phase.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/utils/qs_queue.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/utils/servers.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/utils/stats_update.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/utils/tasks.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/sim/vacations.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/batch/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/batch/mm1.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/closed/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/closed/engset.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/fifo/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/fifo/ek_d_n.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/fifo/gi_m_1.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/fifo/gi_m_n.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/fifo/m_d_n.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/fifo/mg1.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/fifo/mmnr.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/fork_join/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/fork_join/m_m_n.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/fork_join/split_join.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/impatience/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/impatience/mm1.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/negative/mg1_disasters.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/negative/mg1_rcs.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/negative/mgn_disaster.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/negative/mgn_rcs.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/negative/structs.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/networks/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/networks/network_viewer.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/networks/open_network.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/priority/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/priority/mgn_invar_approx.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/priority/non_preemptive/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/priority/non_preemptive/mg1.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/priority/preemptive/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/priority/preemptive/m_ph_n_busy_approx.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/priority/preemptive/mg1.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/priority/preemptive/mmn_2cls_pr_busy_approx.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/priority/preemptive/mmn_3cls_busy_approx.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/r_example.gexf +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/utils/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/utils/binom_probs.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/utils/busy_periods.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/utils/conditional.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/utils/conv.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/utils/diff5dots.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/utils/flow_sum.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/utils/passage_time.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/utils/q_poisson_arrival_calc.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/utils/student_stat.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/vacations/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/vacations/m_h2_h2warm.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/vacations/mg1_warm_calc.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/vacations/mgn_with_h2_delay_cold_warm.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/most_queue/theory/vacations/mmn_with_h2_cold_and_h2_warmup.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/requirements.txt +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/cold_warm_delay_params.yaml +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_base_qs_sim.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_batch.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_ek_d_n.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_engset.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_fj_delta.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_fj_im.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_gi_m_1_calc.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_gi_m_n_calc.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_impatience.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_m_d_n_calc.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_m_h2_h2warm.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_m_ph_n_prty.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_mg1_calc.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_mg1_disaster.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_mg1_rcs.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_mg1_warmup.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_mgn_disaster.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_mgn_rcs.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_mgn_with_h2_delay_cold_warm.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_mgn_with_h2_delay_cold_warm_one_shot.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_mmn3_pnz_cox_approx.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_mmn_h2cold_h2warm.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_mmn_prty_pnz_approx.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_network_im_prty.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_qs_sim.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/test_qs_sim_prty.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/units/h2_params_cv_greater_than_exp.png +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/units/h2_params_cv_less_than_exp.png +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/units/test_busy_moments_calc.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/units/test_conditionals.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/units/test_h2_params_cv.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tests/units/test_queue_types.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/tutorials/m_h2_h2warm.ipynb +0 -0
- {most_queue-1.60 → most_queue-1.61}/tutorials/mgn_takahasi_takami.ipynb +0 -0
- {most_queue-1.60 → most_queue-1.61}/tutorials/network_with_priorities.ipynb +0 -0
- {most_queue-1.60 → most_queue-1.61}/tutorials/priority_queue.ipynb +0 -0
- {most_queue-1.60 → most_queue-1.61}/works/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/works/negative_queues/__init__.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/works/vacations/base_parameters.yaml +0 -0
- {most_queue-1.60 → most_queue-1.61}/works/vacations/channels.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/works/vacations/cooling.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/works/vacations/cooling_delay.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/works/vacations/run_one_calc_vs_sim.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/works/vacations/service.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/works/vacations/utilization.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/works/vacations/utils.py +0 -0
- {most_queue-1.60 → most_queue-1.61}/works/vacations/warmup.py +0 -0
|
@@ -35,6 +35,15 @@ class GammaParams:
|
|
|
35
35
|
g: list[float] | None = None
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
@dataclass
|
|
39
|
+
class WeibullParams:
|
|
40
|
+
"""
|
|
41
|
+
Weibull distribution parameters.
|
|
42
|
+
"""
|
|
43
|
+
k: float # Shape parameter
|
|
44
|
+
W: float # Scale parameter
|
|
45
|
+
|
|
46
|
+
|
|
38
47
|
@dataclass
|
|
39
48
|
class GaussianParams:
|
|
40
49
|
"""
|
|
@@ -16,10 +16,135 @@ from most_queue.general.distribution_params import (
|
|
|
16
16
|
H2Params,
|
|
17
17
|
ParetoParams,
|
|
18
18
|
UniformParams,
|
|
19
|
+
WeibullParams
|
|
19
20
|
)
|
|
20
21
|
from most_queue.general.interfaces import Distribution
|
|
21
22
|
|
|
22
23
|
|
|
24
|
+
class Weibull(Distribution):
|
|
25
|
+
"""
|
|
26
|
+
Class for working with the Weibull distribution
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, params: WeibullParams, generator=None):
|
|
30
|
+
"""
|
|
31
|
+
:param params: WeibullParams object containing shape parameter (k) and scale parameter (T)
|
|
32
|
+
:param generator: random number generator. If None, np.random is used.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
self.k = params.k
|
|
36
|
+
self.W = params.W
|
|
37
|
+
self.params = params
|
|
38
|
+
self.type = 'Weibull'
|
|
39
|
+
self.generator = generator
|
|
40
|
+
|
|
41
|
+
@staticmethod
|
|
42
|
+
def generate_static(params: WeibullParams, generator=None):
|
|
43
|
+
"""
|
|
44
|
+
Generates a random number according to the Weibull distribution.
|
|
45
|
+
"""
|
|
46
|
+
if generator:
|
|
47
|
+
p = generator.random()
|
|
48
|
+
else:
|
|
49
|
+
p = np.random.rand()
|
|
50
|
+
return math.pow(-math.log(p)*params.W, -1 / params.k)
|
|
51
|
+
|
|
52
|
+
def generate(self) -> float:
|
|
53
|
+
"""
|
|
54
|
+
Generates a random number according to the Weibull distribution.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
return self.generate_static(self.params, self.generator)
|
|
58
|
+
|
|
59
|
+
@staticmethod
|
|
60
|
+
def calc_theory_moments(params: WeibullParams, num: int) -> list[float]:
|
|
61
|
+
"""
|
|
62
|
+
Calculates theoretical moments of the distribution up to the specified order.
|
|
63
|
+
:param params: WeibullParams parameters for the distribution.
|
|
64
|
+
:param num: number of moments to calculate.
|
|
65
|
+
:return: list[float]
|
|
66
|
+
"""
|
|
67
|
+
f = [0.0]*num
|
|
68
|
+
for i in range(num):
|
|
69
|
+
f[i] = math.gamma(1 + i/params.k) * math.pow(params.W, i/params.k)
|
|
70
|
+
return f
|
|
71
|
+
|
|
72
|
+
@staticmethod
|
|
73
|
+
def get_params(moments: list[float]) -> WeibullParams:
|
|
74
|
+
"""
|
|
75
|
+
Parameter selection for the distribution based
|
|
76
|
+
on initial moments of the distribution
|
|
77
|
+
|
|
78
|
+
params:
|
|
79
|
+
moments: initial moments of the random variable
|
|
80
|
+
|
|
81
|
+
return:
|
|
82
|
+
WeibullParams
|
|
83
|
+
|
|
84
|
+
"""
|
|
85
|
+
a = moments[1] / (moments[0] * moments[0])
|
|
86
|
+
u0 = math.log(2 * a) / (2.0 * math.log(2))
|
|
87
|
+
ee = 1e-6
|
|
88
|
+
u1 = (1.0 / (2 * math.log(2))) * math.log(
|
|
89
|
+
a * math.sqrt(math.pi) * math.gamma(u0 + 1) / math.gamma(u0 + 0.5))
|
|
90
|
+
delta = u1 - u0
|
|
91
|
+
while math.fabs(delta) > ee:
|
|
92
|
+
u1 = (1.0 / (2 * math.log(2))) * math.log(
|
|
93
|
+
a * math.sqrt(math.pi) * math.gamma(u0 + 1) / math.gamma(u0 + 0.5))
|
|
94
|
+
delta = u1 - u0
|
|
95
|
+
u0 = u1
|
|
96
|
+
k = 1 / u1
|
|
97
|
+
big_w = math.pow(moments[0] / math.gamma(u1 + 1), k)
|
|
98
|
+
|
|
99
|
+
return WeibullParams(k=k, W=big_w)
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
def get_params_by_mean_and_coev(f1: float, coev: float) -> WeibullParams:
|
|
103
|
+
"""
|
|
104
|
+
Subselect parameters of Weibull distribution by the given mean and coefficient of variation.
|
|
105
|
+
Args:
|
|
106
|
+
f1 (float): The first parameter of the Weibull distribution.
|
|
107
|
+
coev (float): The coefficient of variation.
|
|
108
|
+
Returns:
|
|
109
|
+
WeibullParams
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
f = [0, 0, 0]
|
|
113
|
+
alpha = 1 / (coev ** 2)
|
|
114
|
+
f[0] = f1
|
|
115
|
+
f[1] = pow(f[0], 2) * (pow(coev, 2) + 1)
|
|
116
|
+
f[2] = f[1] * f[0] * (1.0 + 2 / alpha)
|
|
117
|
+
|
|
118
|
+
return Weibull.get_params(f)
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def get_tail(params: WeibullParams, t: float) -> float:
|
|
122
|
+
"""
|
|
123
|
+
Calculate the tail probability of a Weibull distribution at a given value.
|
|
124
|
+
Args:
|
|
125
|
+
params (WeibullParams): The parameters of Weibull distribution
|
|
126
|
+
t: The value at which to calculate the tail probability.
|
|
127
|
+
"""
|
|
128
|
+
k = params.k
|
|
129
|
+
big_w = params.W
|
|
130
|
+
|
|
131
|
+
return math.exp(-math.pow(t, k) / big_w)
|
|
132
|
+
|
|
133
|
+
@staticmethod
|
|
134
|
+
def get_cdf(params: WeibullParams, t: float) -> float:
|
|
135
|
+
"""
|
|
136
|
+
Calculate the cumulative distribution function (CDF) of a Weibull distribution for a given set of values.
|
|
137
|
+
Args:
|
|
138
|
+
params (WeibullParams): The parameters of Weibull distribution
|
|
139
|
+
t: The value at which to calculate the cdf probability.
|
|
140
|
+
|
|
141
|
+
"""
|
|
142
|
+
k = params.k
|
|
143
|
+
big_w = params.W
|
|
144
|
+
|
|
145
|
+
return 1.0 - math.exp(-math.pow(t, k) / big_w)
|
|
146
|
+
|
|
147
|
+
|
|
23
148
|
class NormalDistribution(Distribution):
|
|
24
149
|
"""
|
|
25
150
|
Gaussian distribution. Generates random numbers from a normal (Gaussian) distribution.
|
|
@@ -6,6 +6,8 @@ import math
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
|
|
8
8
|
from most_queue.rand_distribution import H2Distribution
|
|
9
|
+
from most_queue.theory.utils.transforms import lst_exp
|
|
10
|
+
from scipy.misc import derivative
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
class MGnCalc:
|
|
@@ -163,7 +165,7 @@ class MGnCalc:
|
|
|
163
165
|
"""
|
|
164
166
|
return [prob.real for prob in self.p]
|
|
165
167
|
|
|
166
|
-
def get_w(self) -> list[float]:
|
|
168
|
+
def get_w(self, derivate=False) -> list[float]:
|
|
167
169
|
"""
|
|
168
170
|
Get the waiting time moments
|
|
169
171
|
"""
|
|
@@ -173,6 +175,12 @@ class MGnCalc:
|
|
|
173
175
|
|
|
174
176
|
w = [0.0] * 3
|
|
175
177
|
|
|
178
|
+
if derivate:
|
|
179
|
+
for i in range(3):
|
|
180
|
+
w[i] = derivative(self._calc_w_lst, 0,
|
|
181
|
+
dx=1e-3 / self.b[0], n=i + 1, order=9)
|
|
182
|
+
return np.array([-w[0], w[1].real, -w[2]])
|
|
183
|
+
|
|
176
184
|
for j in range(1, len(self.p) - self.n):
|
|
177
185
|
w[0] += j * self.p[self.n + j]
|
|
178
186
|
for j in range(2, len(self.p) - self.n):
|
|
@@ -191,6 +199,7 @@ class MGnCalc:
|
|
|
191
199
|
"""
|
|
192
200
|
Get the sojourn time moments
|
|
193
201
|
"""
|
|
202
|
+
|
|
194
203
|
w = self.get_w()
|
|
195
204
|
b0 = self.b[0]
|
|
196
205
|
b1 = self.b[1]
|
|
@@ -407,3 +416,54 @@ class MGnCalc:
|
|
|
407
416
|
output[i, i] = self.l + (num - i) * self.mu[0] + i * self.mu[1]
|
|
408
417
|
|
|
409
418
|
return output
|
|
419
|
+
|
|
420
|
+
def _calc_up_probs(self, from_level):
|
|
421
|
+
|
|
422
|
+
b_matrix = self.B[from_level]
|
|
423
|
+
low_level_size = self.cols[from_level - 1]
|
|
424
|
+
high_level_size = self.cols[from_level]
|
|
425
|
+
|
|
426
|
+
probs = np.zeros((high_level_size, low_level_size), dtype=self.dt)
|
|
427
|
+
|
|
428
|
+
for i in range(high_level_size):
|
|
429
|
+
for j in range(low_level_size):
|
|
430
|
+
if from_level != 1:
|
|
431
|
+
probs[i, j] = b_matrix[i, j] / sum(b_matrix[i, :])
|
|
432
|
+
else:
|
|
433
|
+
probs[i, j] = b_matrix[i, 0] / sum(b_matrix[i, :])
|
|
434
|
+
|
|
435
|
+
return probs
|
|
436
|
+
|
|
437
|
+
def _get_key_numbers(self, level):
|
|
438
|
+
key_numbers = []
|
|
439
|
+
if level >= self.n:
|
|
440
|
+
for i in range(level + 1):
|
|
441
|
+
key_numbers.append((self.n - i, i))
|
|
442
|
+
else:
|
|
443
|
+
for i in range(level + 1):
|
|
444
|
+
key_numbers.append((level - i, i))
|
|
445
|
+
return np.array(key_numbers, dtype=self.dt)
|
|
446
|
+
|
|
447
|
+
def _calc_w_lst(self, s):
|
|
448
|
+
|
|
449
|
+
w = 0
|
|
450
|
+
|
|
451
|
+
key_numbers = self._get_key_numbers(self.n)
|
|
452
|
+
|
|
453
|
+
a = np.array(
|
|
454
|
+
[lst_exp(key_numbers[j][0] * self.mu[0] + key_numbers[j][1] * self.mu[1], s) for j in
|
|
455
|
+
range(self.n + 1)])
|
|
456
|
+
|
|
457
|
+
up_transition_mrx = self._calc_up_probs(self.n+1) # (n + 1 x n + 1)
|
|
458
|
+
|
|
459
|
+
for k in range(self.n, self.N):
|
|
460
|
+
|
|
461
|
+
Pa = np.linalg.matrix_power(
|
|
462
|
+
up_transition_mrx * a, k - self.n) # n+1 x n+1
|
|
463
|
+
|
|
464
|
+
Ys = [self.Y[k][0, i] for i in range(self.n + 1)]
|
|
465
|
+
aPa = np.dot(Pa, a)
|
|
466
|
+
for i in range(self.n + 1):
|
|
467
|
+
w += Ys[i] * aPa[i]
|
|
468
|
+
|
|
469
|
+
return w
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def lst_residual(lst_original: callable, b1: float, s: float) -> float:
|
|
5
|
+
"""
|
|
6
|
+
Calculate the Laplace-Stieltjes transform of a residual distribution.
|
|
7
|
+
"""
|
|
8
|
+
return (1-lst_original(s))/(b1*s)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_b_residual(b_original: list[float]) -> list[float]:
|
|
12
|
+
"""
|
|
13
|
+
Calculate the initial moments E[X^k] for k=0,1,...,n-1 of a residual distribution.
|
|
14
|
+
b_res1 = E[X^2]/(2*E[X])
|
|
15
|
+
"""
|
|
16
|
+
b_res = np.zeros(len(b_original)-1)
|
|
17
|
+
for i in range(len(b_original)-1):
|
|
18
|
+
b_res[i] = b_original[i+1]/((i+2)*b_original[0])
|
|
19
|
+
return b_res
|
|
@@ -15,6 +15,7 @@ from most_queue.general.tables import probs_print, times_print
|
|
|
15
15
|
from most_queue.rand_distribution import GammaDistribution
|
|
16
16
|
from most_queue.sim.base import QsSim
|
|
17
17
|
from most_queue.theory.fifo.mgn_takahasi import MGnCalc
|
|
18
|
+
import numpy as np
|
|
18
19
|
|
|
19
20
|
ARRIVAL_RATE = 1.0
|
|
20
21
|
NUM_OF_JOBS = 300000
|
|
@@ -45,6 +46,7 @@ def test_mgn_tt():
|
|
|
45
46
|
# get numerical calculation results
|
|
46
47
|
p_tt = tt.get_p()
|
|
47
48
|
v_tt = tt.get_v()
|
|
49
|
+
|
|
48
50
|
tt_time = time.process_time() - tt_start
|
|
49
51
|
# also can find out how many iterations were required
|
|
50
52
|
num_of_iter = tt.num_of_iter_
|
|
@@ -87,7 +89,8 @@ def test_mgn_tt():
|
|
|
87
89
|
|
|
88
90
|
times_print(v_sim, v_tt, False)
|
|
89
91
|
|
|
90
|
-
assert
|
|
92
|
+
assert np.allclose(v_sim, v_tt, rtol=5e-1), "The results of the simulation and Takahasi-Takami method do not match!"
|
|
93
|
+
|
|
91
94
|
|
|
92
95
|
|
|
93
96
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Testing the Takahasi-Takami method for calculating an M/H2/n queue
|
|
3
|
+
|
|
4
|
+
When the coefficient of variation of service time is less than 1,
|
|
5
|
+
the parameters of the approximating H2 distribution
|
|
6
|
+
are complex, which does not prevent obtaining meaningful results.
|
|
7
|
+
|
|
8
|
+
For verification, simulation is used.
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
import math
|
|
12
|
+
|
|
13
|
+
from most_queue.general.tables import print_mrx
|
|
14
|
+
from most_queue.theory.fifo.mgn_takahasi import MGnCalc
|
|
15
|
+
|
|
16
|
+
ARRIVAL_RATE = 1.0
|
|
17
|
+
NUM_OF_JOBS = 300000
|
|
18
|
+
NUM_OF_CHANNELS = 3
|
|
19
|
+
UTILIZATION = 0.7
|
|
20
|
+
SERVICE_TIME_CV = 1.2
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_calc_up_probs():
|
|
24
|
+
"""
|
|
25
|
+
Testing the Takahasi-Takami method calculation of up-probabilities
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
# calculate initial moments of service time based
|
|
29
|
+
# on the given average and coefficient of variation
|
|
30
|
+
b = [0.0] * 3
|
|
31
|
+
alpha = 1 / (SERVICE_TIME_CV ** 2)
|
|
32
|
+
b[0] = NUM_OF_CHANNELS * UTILIZATION / \
|
|
33
|
+
ARRIVAL_RATE # average service time
|
|
34
|
+
b[1] = math.pow(b[0], 2) * (math.pow(SERVICE_TIME_CV, 2) + 1)
|
|
35
|
+
b[2] = b[1] * b[0] * (1.0 + 2 / alpha)
|
|
36
|
+
|
|
37
|
+
# run Takahasi-Takami method
|
|
38
|
+
tt = MGnCalc(NUM_OF_CHANNELS, ARRIVAL_RATE, b)
|
|
39
|
+
tt.run()
|
|
40
|
+
|
|
41
|
+
for i in range(1, NUM_OF_CHANNELS+2):
|
|
42
|
+
probs_mrx = tt._calc_up_probs(i)
|
|
43
|
+
|
|
44
|
+
print_mrx(probs_mrx)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
test_calc_up_probs()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Test Weibull distribution
|
|
3
|
+
"""
|
|
4
|
+
import matplotlib.pyplot as plt
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from most_queue.rand_distribution import Weibull
|
|
8
|
+
|
|
9
|
+
if __name__ == "__main__":
|
|
10
|
+
|
|
11
|
+
MEAN = 1.0
|
|
12
|
+
coevs = [1.0, 2.1, 3.2]
|
|
13
|
+
|
|
14
|
+
fig, ax = plt.subplots()
|
|
15
|
+
|
|
16
|
+
for coev in coevs:
|
|
17
|
+
params = Weibull.get_params_by_mean_and_coev(MEAN, coev)
|
|
18
|
+
|
|
19
|
+
print(
|
|
20
|
+
f"Weibull params at CV= {coev:1.3f}: k = {params.k:1.3f} W = {params.W:1.3f}")
|
|
21
|
+
ts = np.linspace(0, 3 * coevs[len(coevs)-1], 100)
|
|
22
|
+
dfr = [Weibull.get_tail(params, t) for t in ts]
|
|
23
|
+
|
|
24
|
+
ax.plot(ts, dfr, label=f"$\\nu$ = {coev:1.1f}")
|
|
25
|
+
|
|
26
|
+
ax.set_xlabel('t')
|
|
27
|
+
ax.set_ylabel('Tail')
|
|
28
|
+
plt.legend()
|
|
29
|
+
plt.show()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
accuracy: 1e-10
|
|
2
|
+
arrival_rate:
|
|
3
|
+
positive: 1.0
|
|
4
|
+
negative: 0.5
|
|
5
|
+
num_of_jobs: 300000
|
|
6
|
+
service:
|
|
7
|
+
cv:
|
|
8
|
+
base: 1.2
|
|
9
|
+
min: 0.3
|
|
10
|
+
max: 3
|
|
11
|
+
num_points: 20
|
|
12
|
+
channels:
|
|
13
|
+
base: 3
|
|
14
|
+
min: 1
|
|
15
|
+
max: 10
|
|
16
|
+
utilization:
|
|
17
|
+
base: 0.7
|
|
18
|
+
min: 0.1
|
|
19
|
+
max: 0.9
|
|
20
|
+
num_points: 20
|
|
21
|
+
|