most-queue 1.61__tar.gz → 1.62__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.61 → most_queue-1.62}/PKG-INFO +8 -5
- {most_queue-1.61 → most_queue-1.62}/README.md +7 -4
- most_queue-1.62/assets/1.gif +0 -0
- most_queue-1.62/assets/2.gif +0 -0
- most_queue-1.62/assets/3.gif +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/general/tables.py +2 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/misc/flow_sum.py +3 -3
- {most_queue-1.61 → most_queue-1.62}/most_queue/rand_distribution.py +2 -1
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/base.py +38 -18
- most_queue-1.62/most_queue/sim/networks/network.py +181 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/priority.py +18 -15
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/utils/tasks.py +10 -5
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/fifo/ek_d_n.py +1 -1
- most_queue-1.62/most_queue/theory/networks/open_network.py +126 -0
- most_queue-1.61/most_queue/theory/networks/open_network.py → most_queue-1.62/most_queue/theory/networks/open_network_prty.py +1 -1
- most_queue-1.62/most_queue/theory/networks/opt/transition.py +330 -0
- most_queue-1.62/most_queue/theory/networks/opt/transition_approx.py +132 -0
- most_queue-1.62/most_queue/theory/networks/opt/transition_plus.py +162 -0
- most_queue-1.62/most_queue/theory/utils/utilization_approx.py +62 -0
- {most_queue-1.61 → most_queue-1.62}/pyproject.toml +1 -1
- {most_queue-1.61 → most_queue-1.62}/setup.py +1 -1
- {most_queue-1.61 → most_queue-1.62}/tests/cold_warm_delay_params.yaml +0 -1
- most_queue-1.62/tests/default_params.yaml +35 -0
- {most_queue-1.61 → most_queue-1.62}/tests/test_base_qs_sim.py +26 -8
- {most_queue-1.61 → most_queue-1.62}/tests/test_batch.py +22 -9
- {most_queue-1.61 → most_queue-1.62}/tests/test_ek_d_n.py +27 -10
- {most_queue-1.61 → most_queue-1.62}/tests/test_engset.py +36 -10
- most_queue-1.62/tests/test_fj_delta.py +85 -0
- most_queue-1.61/tests/test_fj_im.py → most_queue-1.62/tests/test_fj_sim.py +45 -28
- {most_queue-1.61 → most_queue-1.62}/tests/test_gi_m_1_calc.py +26 -36
- {most_queue-1.61 → most_queue-1.62}/tests/test_gi_m_n_calc.py +32 -31
- most_queue-1.62/tests/test_impatience.py +68 -0
- {most_queue-1.61 → most_queue-1.62}/tests/test_m_d_n_calc.py +27 -9
- {most_queue-1.61 → most_queue-1.62}/tests/test_m_h2_h2warm.py +41 -18
- {most_queue-1.61 → most_queue-1.62}/tests/test_m_ph_n_prty.py +40 -33
- most_queue-1.62/tests/test_mg1_calc.py +80 -0
- {most_queue-1.61 → most_queue-1.62}/tests/test_mg1_disaster.py +36 -13
- {most_queue-1.61 → most_queue-1.62}/tests/test_mg1_rcs.py +24 -10
- {most_queue-1.61 → most_queue-1.62}/tests/test_mg1_warmup.py +29 -13
- {most_queue-1.61 → most_queue-1.62}/tests/test_mgn_disaster.py +33 -7
- {most_queue-1.61 → most_queue-1.62}/tests/test_mgn_rcs.py +34 -8
- most_queue-1.62/tests/test_mgn_tt.py +118 -0
- most_queue-1.61/tests/test_mgn_with_h2_delay_cold_warm_one_shot.py → most_queue-1.62/tests/test_mgn_with_h2_delay_cold_warm.py +66 -18
- {most_queue-1.61 → most_queue-1.62}/tests/test_mmn_h2cold_h2warm.py +55 -21
- {most_queue-1.61 → most_queue-1.62}/tests/test_mmn_prty_pnz_approx.py +43 -17
- {most_queue-1.61 → most_queue-1.62}/tests/test_network_im_prty.py +44 -21
- most_queue-1.62/tests/test_network_no_prty.py +77 -0
- most_queue-1.62/tests/test_network_opt.py +51 -0
- most_queue-1.62/tests/test_network_opt_approx.py +42 -0
- most_queue-1.62/tests/test_network_opt_plus.py +49 -0
- most_queue-1.62/tests/units/test_v1_on_channels.py +54 -0
- most_queue-1.62/tests/units/test_v1_utlization_approx.py +10 -0
- most_queue-1.62/tests/units/v1_on_channels.png +0 -0
- most_queue-1.62/tests/units/v1_on_utilization_approx.png +0 -0
- {most_queue-1.61 → most_queue-1.62}/tutorials/network_with_priorities.ipynb +17 -17
- {most_queue-1.61 → most_queue-1.62}/tutorials/queue_sim.ipynb +3 -3
- most_queue-1.62/works/vacations/__init__.py +0 -0
- most_queue-1.61/tests/test_fj_delta.py +0 -66
- most_queue-1.61/tests/test_impatience.py +0 -47
- most_queue-1.61/tests/test_mg1_calc.py +0 -104
- most_queue-1.61/tests/test_mgn_tt.py +0 -97
- most_queue-1.61/tests/test_mmn3_pnz_cox_approx.py +0 -104
- {most_queue-1.61 → most_queue-1.62}/.gitignore +0 -0
- {most_queue-1.61 → most_queue-1.62}/LICENSE +0 -0
- {most_queue-1.61 → most_queue-1.62}/assets/queue_long.png +0 -0
- {most_queue-1.61 → most_queue-1.62}/deploy.txt +0 -0
- {most_queue-1.61 → most_queue-1.62}/docs/Makefile +0 -0
- {most_queue-1.61 → most_queue-1.62}/docs/make.bat +0 -0
- {most_queue-1.61 → most_queue-1.62}/docs/source/conf.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/docs/source/index.rst +0 -0
- {most_queue-1.61 → most_queue-1.62}/docs/source/modules.rst +0 -0
- {most_queue-1.61 → most_queue-1.62}/docs/source/most_queue.rst +0 -0
- {most_queue-1.61 → most_queue-1.62}/docs/source/most_queue.sim.rst +0 -0
- {most_queue-1.61 → most_queue-1.62}/docs/source/most_queue.theory.rst +0 -0
- {most_queue-1.61 → most_queue-1.62}/googleb31d3dccb40f969f.html +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/general/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/general/distribution_params.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/general/interfaces.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/general/plots.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/misc/approx_cdf_make.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/misc/calc_v_pls.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/misc/compare_fj_calc.py +0 -0
- /most_queue-1.61/tests/test_mgn_with_h2_delay_cold_warm.py → /most_queue-1.62/most_queue/misc/run_mgn_with_h2_delay_cold_warm.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/misc/vacations_paper_utils.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/batch.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/finite_source.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/flow_sum.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/fork_join.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/fork_join_delta.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/impatient.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/negative.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/networks/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/networks/priority_network.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/utils/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/utils/distribution_utils.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/utils/exceptions.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/utils/phase.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/utils/qs_queue.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/utils/servers.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/utils/stats_update.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/sim/vacations.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/batch/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/batch/mm1.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/closed/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/closed/engset.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/fifo/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/fifo/gi_m_1.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/fifo/gi_m_n.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/fifo/m_d_n.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/fifo/mg1.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/fifo/mgn_takahasi.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/fifo/mmnr.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/fork_join/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/fork_join/m_m_n.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/fork_join/split_join.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/impatience/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/impatience/mm1.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/negative/mg1_disasters.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/negative/mg1_rcs.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/negative/mgn_disaster.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/negative/mgn_rcs.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/negative/structs.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/networks/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/networks/network_viewer.py +0 -0
- {most_queue-1.61/most_queue/theory/priority → most_queue-1.62/most_queue/theory/networks/opt}/__init__.py +0 -0
- {most_queue-1.61/most_queue/theory/priority/non_preemptive → most_queue-1.62/most_queue/theory/priority}/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/priority/mgn_invar_approx.py +0 -0
- {most_queue-1.61/most_queue/theory/priority/preemptive → most_queue-1.62/most_queue/theory/priority/non_preemptive}/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/priority/non_preemptive/mg1.py +0 -0
- {most_queue-1.61/most_queue/theory/utils → most_queue-1.62/most_queue/theory/priority/preemptive}/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/priority/preemptive/m_ph_n_busy_approx.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/priority/preemptive/mg1.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/priority/preemptive/mmn_2cls_pr_busy_approx.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/priority/preemptive/mmn_3cls_busy_approx.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/r_example.gexf +0 -0
- {most_queue-1.61/most_queue/theory/vacations → most_queue-1.62/most_queue/theory/utils}/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/utils/binom_probs.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/utils/busy_periods.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/utils/conditional.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/utils/conv.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/utils/diff5dots.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/utils/flow_sum.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/utils/passage_time.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/utils/q_poisson_arrival_calc.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/utils/residual.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/utils/student_stat.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/utils/transforms.py +0 -0
- {most_queue-1.61/tests → most_queue-1.62/most_queue/theory/vacations}/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/vacations/m_h2_h2warm.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/vacations/mg1_warm_calc.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/vacations/mgn_with_h2_delay_cold_warm.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/most_queue/theory/vacations/mmn_with_h2_cold_and_h2_warmup.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/requirements.txt +0 -0
- {most_queue-1.61/works → most_queue-1.62/tests}/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/tests/test_qs_sim.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/tests/test_qs_sim_prty.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/tests/units/h2_params_cv_greater_than_exp.png +0 -0
- {most_queue-1.61 → most_queue-1.62}/tests/units/h2_params_cv_less_than_exp.png +0 -0
- {most_queue-1.61 → most_queue-1.62}/tests/units/test_busy_moments_calc.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/tests/units/test_conditionals.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/tests/units/test_h2_params_cv.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/tests/units/test_queue_types.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/tests/units/test_tt_up_probs.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/tests/units/test_weibull.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/tutorials/m_h2_h2warm.ipynb +0 -0
- {most_queue-1.61 → most_queue-1.62}/tutorials/mgn_takahasi_takami.ipynb +0 -0
- {most_queue-1.61 → most_queue-1.62}/tutorials/priority_queue.ipynb +0 -0
- {most_queue-1.61/works/negative_queues → most_queue-1.62/works}/__init__.py +0 -0
- {most_queue-1.61/works/vacations → most_queue-1.62/works/negative_queues}/__init__.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/works/negative_queues/base_parameters.yaml +0 -0
- {most_queue-1.61 → most_queue-1.62}/works/negative_queues/work_mgn_negatives.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/works/vacations/base_parameters.yaml +0 -0
- {most_queue-1.61 → most_queue-1.62}/works/vacations/channels.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/works/vacations/cooling.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/works/vacations/cooling_delay.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/works/vacations/main.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/works/vacations/run_one_calc_vs_sim.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/works/vacations/service.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/works/vacations/utilization.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/works/vacations/utils.py +0 -0
- {most_queue-1.61 → most_queue-1.62}/works/vacations/warmup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: most_queue
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.62
|
|
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>
|
|
@@ -41,7 +41,7 @@ Description-Content-Type: text/markdown
|
|
|
41
41
|
|
|
42
42
|
# Queueing Systems: Simulation & Numerical Methods 🔄
|
|
43
43
|
|
|
44
|
-

|
|
45
45
|
|
|
46
46
|
A Python package for simulating and analyzing queueing systems (QS) and networks.
|
|
47
47
|
|
|
@@ -129,8 +129,8 @@ Most_queue consists of two main parts:
|
|
|
129
129
|
|
|
130
130
|
| # | Kendall Notations | Description | Example | Tutorial |
|
|
131
131
|
|-----|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|-------------------|
|
|
132
|
-
| 1. | M/M/c/Fork-Join | Solving for Fork-Join queueing system | [link](https://github.com/xabarov/most-queue/blob/main/tests/
|
|
133
|
-
| 2. | M/G/c/Split-Join | Solving for Split-Join queueing system | [link](https://github.com/xabarov/most-queue/blob/main/tests/
|
|
132
|
+
| 1. | M/M/c/Fork-Join | Solving for Fork-Join queueing system | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_fj_sim.py) | |
|
|
133
|
+
| 2. | M/G/c/Split-Join | Solving for Split-Join queueing system | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_fj_sim.py) | |
|
|
134
134
|
|
|
135
135
|
|
|
136
136
|
### Others
|
|
@@ -139,7 +139,10 @@ Most_queue consists of two main parts:
|
|
|
139
139
|
| 1. | M<sup>x</sup>/M/1 | Solving for the of M<sup>x</sup>/M/1 QS with batch arrival | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_batch.py) | |
|
|
140
140
|
| 2. | 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) | |
|
|
141
141
|
| 3. | M/M/1/N | Solving for the Engset model for M/M/1 with a finite number of sources. | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_engset.py) | |
|
|
142
|
-
| 4. |
|
|
142
|
+
| 4. | Queuing Network | Numerical calculation of queuing network | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_network_no_prty.py) | |
|
|
143
|
+
| 5. | Queuing Network with Priorities | Numerical calculation of queuing network with priorities in nodes | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_network_sim_prty.py) | [link](https://github.com/xabarov/most-queue/blob/main/tutorials/network_with_priorities.ipynb) |
|
|
144
|
+
| 6. | Queuing Network Optimization | Optimization of queuing network transition matrix | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_network_opt.py) | |
|
|
145
|
+
|
|
143
146
|
|
|
144
147
|
---
|
|
145
148
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Queueing Systems: Simulation & Numerical Methods 🔄
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|
|
|
5
5
|
A Python package for simulating and analyzing queueing systems (QS) and networks.
|
|
6
6
|
|
|
@@ -88,8 +88,8 @@ Most_queue consists of two main parts:
|
|
|
88
88
|
|
|
89
89
|
| # | Kendall Notations | Description | Example | Tutorial |
|
|
90
90
|
|-----|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|-------------------|
|
|
91
|
-
| 1. | M/M/c/Fork-Join | Solving for Fork-Join queueing system | [link](https://github.com/xabarov/most-queue/blob/main/tests/
|
|
92
|
-
| 2. | M/G/c/Split-Join | Solving for Split-Join queueing system | [link](https://github.com/xabarov/most-queue/blob/main/tests/
|
|
91
|
+
| 1. | M/M/c/Fork-Join | Solving for Fork-Join queueing system | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_fj_sim.py) | |
|
|
92
|
+
| 2. | M/G/c/Split-Join | Solving for Split-Join queueing system | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_fj_sim.py) | |
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
### Others
|
|
@@ -98,7 +98,10 @@ Most_queue consists of two main parts:
|
|
|
98
98
|
| 1. | M<sup>x</sup>/M/1 | Solving for the of M<sup>x</sup>/M/1 QS with batch arrival | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_batch.py) | |
|
|
99
99
|
| 2. | 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
|
| 3. | M/M/1/N | Solving for the Engset model for M/M/1 with a finite number of sources. | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_engset.py) | |
|
|
101
|
-
| 4. |
|
|
101
|
+
| 4. | Queuing Network | Numerical calculation of queuing network | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_network_no_prty.py) | |
|
|
102
|
+
| 5. | Queuing Network with Priorities | Numerical calculation of queuing network with priorities in nodes | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_network_sim_prty.py) | [link](https://github.com/xabarov/most-queue/blob/main/tutorials/network_with_priorities.ipynb) |
|
|
103
|
+
| 6. | Queuing Network Optimization | Optimization of queuing network transition matrix | [link](https://github.com/xabarov/most-queue/blob/main/tests/test_network_opt.py) | |
|
|
104
|
+
|
|
102
105
|
|
|
103
106
|
---
|
|
104
107
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import matplotlib
|
|
2
2
|
import matplotlib.pyplot as plt
|
|
3
3
|
|
|
4
|
-
from most_queue.theory.utils.flow_sum import SummatorNumeric
|
|
5
4
|
from most_queue.rand_distribution import GammaDistribution
|
|
6
5
|
from most_queue.sim.flow_sum import FlowSumSim
|
|
6
|
+
from most_queue.theory.utils.flow_sum import SummatorNumeric
|
|
7
7
|
|
|
8
8
|
matplotlib.use('TkAgg')
|
|
9
9
|
|
|
@@ -19,7 +19,7 @@ def test():
|
|
|
19
19
|
mean = 1 # среднее каждого потока
|
|
20
20
|
num_of_jobs = 400000 # количество заявок для ИМ
|
|
21
21
|
is_semi = False # True, если необходимо использовать метод семиинвариантов вместо H2
|
|
22
|
-
|
|
22
|
+
distr_sim = "Gamma" # распределение, используемое для ИМ
|
|
23
23
|
|
|
24
24
|
# число суммируемых потоков
|
|
25
25
|
ns = [x + 2 for x in range(n_nums - 1)]
|
|
@@ -38,7 +38,7 @@ def test():
|
|
|
38
38
|
# i - кол-во суммируемых потоков, j - номер начального момента
|
|
39
39
|
|
|
40
40
|
# ИМ
|
|
41
|
-
s_sim = FlowSumSim(a, distr=
|
|
41
|
+
s_sim = FlowSumSim(a, distr=distr_sim, num_of_jobs=num_of_jobs)
|
|
42
42
|
# в s_sim._flows[i][j] содержатся начальные моменты суммируемых потокоы,
|
|
43
43
|
s_sim.sum_flows()
|
|
44
44
|
# i - кол-во суммируемых потоков, j - номер начального момента
|
|
@@ -931,7 +931,8 @@ class ErlangDistribution(Distribution):
|
|
|
931
931
|
@staticmethod
|
|
932
932
|
def get_params_by_mean_and_coev(f1: float, coev: float) -> ErlangParams:
|
|
933
933
|
"""
|
|
934
|
-
Method selects the parameters of the Erlang distribution
|
|
934
|
+
Method selects the parameters of the Erlang distribution
|
|
935
|
+
by mean and coefficient of variation.
|
|
935
936
|
"""
|
|
936
937
|
f = [0, 0]
|
|
937
938
|
f[0] = f1
|
|
@@ -105,7 +105,8 @@ class QsSim:
|
|
|
105
105
|
|
|
106
106
|
self.is_set_source_params = True
|
|
107
107
|
|
|
108
|
-
self.source = create_distribution(
|
|
108
|
+
self.source = create_distribution(
|
|
109
|
+
params, kendall_notation, self.generator)
|
|
109
110
|
|
|
110
111
|
self.arrival_time = self.source.generate()
|
|
111
112
|
|
|
@@ -137,14 +138,17 @@ class QsSim:
|
|
|
137
138
|
self.server_kendall_notation,
|
|
138
139
|
self.server_params, self.n)
|
|
139
140
|
|
|
140
|
-
def send_task_to_channel(self, is_warm_start=False):
|
|
141
|
+
def send_task_to_channel(self, is_warm_start=False, tsk=None):
|
|
141
142
|
"""
|
|
142
143
|
Sends a job to the service channel
|
|
143
144
|
"""
|
|
145
|
+
|
|
146
|
+
if tsk is None:
|
|
147
|
+
tsk = Task(self.ttek)
|
|
148
|
+
tsk.wait_time = 0
|
|
149
|
+
|
|
144
150
|
for s in self.servers:
|
|
145
151
|
if s.is_free:
|
|
146
|
-
tsk = Task(self.ttek)
|
|
147
|
-
tsk.wait_time = 0
|
|
148
152
|
self.taked += 1
|
|
149
153
|
self.refresh_w_stat(tsk.wait_time)
|
|
150
154
|
self.zero_wait_arrivals_num += 1
|
|
@@ -159,42 +163,53 @@ class QsSim:
|
|
|
159
163
|
|
|
160
164
|
break
|
|
161
165
|
|
|
162
|
-
def send_task_to_queue(self):
|
|
166
|
+
def send_task_to_queue(self, new_tsk=None):
|
|
163
167
|
"""
|
|
164
168
|
Send Task to Queue
|
|
165
169
|
"""
|
|
166
|
-
|
|
170
|
+
|
|
171
|
+
if new_tsk is None:
|
|
167
172
|
new_tsk = Task(self.ttek)
|
|
168
173
|
new_tsk.start_waiting_time = self.ttek
|
|
174
|
+
|
|
175
|
+
if self.buffer is None: # queue length is not specified, i.e. infinite queue
|
|
176
|
+
|
|
169
177
|
self.queue.append(new_tsk)
|
|
170
178
|
else:
|
|
171
179
|
if self.queue.size() < self.buffer:
|
|
172
|
-
new_tsk = Task(self.ttek)
|
|
173
|
-
new_tsk.start_waiting_time = self.ttek
|
|
174
180
|
self.queue.append(new_tsk)
|
|
175
181
|
else:
|
|
176
182
|
self.dropped += 1
|
|
177
183
|
self.in_sys -= 1
|
|
178
184
|
|
|
179
|
-
def arrival(self):
|
|
185
|
+
def arrival(self, moment=None, ts=None):
|
|
180
186
|
"""
|
|
181
187
|
Actions upon arrival of the job by the QS.
|
|
182
188
|
"""
|
|
183
|
-
|
|
189
|
+
|
|
184
190
|
self.arrived += 1
|
|
185
191
|
self.p[self.in_sys] += self.arrival_time - self.ttek
|
|
186
192
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
193
|
+
if moment:
|
|
194
|
+
self.ttek = moment
|
|
195
|
+
ts.arr_time = moment
|
|
196
|
+
ts.wait_time = 0
|
|
197
|
+
ts.start_waiting_time = -1
|
|
198
|
+
ts.time_to_end_service = 0
|
|
199
|
+
|
|
200
|
+
else:
|
|
201
|
+
self.ttek = self.arrival_time
|
|
202
|
+
self.arrival_time = self.ttek + self.source.generate()
|
|
190
203
|
|
|
204
|
+
self.in_sys += 1
|
|
205
|
+
|
|
191
206
|
if self.free_channels == 0:
|
|
192
|
-
self.send_task_to_queue()
|
|
207
|
+
self.send_task_to_queue(new_tsk=ts)
|
|
193
208
|
|
|
194
209
|
else: # there are free channels:
|
|
195
|
-
self.send_task_to_channel()
|
|
210
|
+
self.send_task_to_channel(tsk=ts)
|
|
196
211
|
|
|
197
|
-
def serving(self, c):
|
|
212
|
+
def serving(self, c, is_network=False):
|
|
198
213
|
"""
|
|
199
214
|
Actions upon receipt of a service job with - channel number
|
|
200
215
|
"""
|
|
@@ -219,9 +234,12 @@ class QsSim:
|
|
|
219
234
|
self.refresh_busy_stat(self.ttek - self.start_busy)
|
|
220
235
|
|
|
221
236
|
if self.queue.size() != 0:
|
|
222
|
-
self.send_head_of_queue_to_channel(c)
|
|
237
|
+
self.send_head_of_queue_to_channel(c, is_network=is_network)
|
|
238
|
+
|
|
239
|
+
if is_network:
|
|
240
|
+
return end_ts
|
|
223
241
|
|
|
224
|
-
def send_head_of_queue_to_channel(self, channel_num):
|
|
242
|
+
def send_head_of_queue_to_channel(self, channel_num, is_network=False):
|
|
225
243
|
"""
|
|
226
244
|
Send first Task (head of queue) to Channel
|
|
227
245
|
"""
|
|
@@ -232,6 +250,8 @@ class QsSim:
|
|
|
232
250
|
|
|
233
251
|
self.taked += 1
|
|
234
252
|
que_ts.wait_time += self.ttek - que_ts.start_waiting_time
|
|
253
|
+
if is_network:
|
|
254
|
+
que_ts.wait_network += self.ttek - que_ts.start_waiting_time
|
|
235
255
|
self.refresh_w_stat(que_ts.wait_time)
|
|
236
256
|
|
|
237
257
|
self.servers[channel_num].start_service(que_ts, self.ttek)
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Simulation of a priority network with priorities and multiple channels.
|
|
3
|
+
"""
|
|
4
|
+
import math
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from colorama import Fore, Style, init
|
|
8
|
+
from tqdm import tqdm
|
|
9
|
+
|
|
10
|
+
from most_queue.rand_distribution import ExpDistribution
|
|
11
|
+
from most_queue.sim.base import QsSim
|
|
12
|
+
from most_queue.sim.utils.tasks import Task
|
|
13
|
+
|
|
14
|
+
init()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class NetworkSimulator:
|
|
18
|
+
"""
|
|
19
|
+
Simulation of network with multiple channels in each node.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, arrival_rate: float, R: np.matrix, n: list[int],
|
|
23
|
+
serv_params):
|
|
24
|
+
"""
|
|
25
|
+
arrival_rate: arrival rate of tasks.
|
|
26
|
+
|
|
27
|
+
R: routing matrix
|
|
28
|
+
n: list of number of channels in each node.
|
|
29
|
+
|
|
30
|
+
serv_params: list of dictionaries with service parameters for each node
|
|
31
|
+
[m][dict(type, params)]
|
|
32
|
+
where m - node number,
|
|
33
|
+
type - distribution type, params - distribution parameters.
|
|
34
|
+
"""
|
|
35
|
+
self.arrival_time = arrival_rate
|
|
36
|
+
self.R = R
|
|
37
|
+
self.n_num = len(n) # number of nodes
|
|
38
|
+
self.nodes = n # n[i] - number of channels in node i
|
|
39
|
+
|
|
40
|
+
self.serv_params = serv_params
|
|
41
|
+
|
|
42
|
+
self.qs = []
|
|
43
|
+
|
|
44
|
+
for m in range(self.n_num):
|
|
45
|
+
self.qs.append(QsSim(n[m]))
|
|
46
|
+
self.qs[m].set_servers(serv_params[m]['params'], kendall_notation=serv_params[m]['type'])
|
|
47
|
+
|
|
48
|
+
self.source = ExpDistribution(self.arrival_time)
|
|
49
|
+
self.arrival_time = self.source.generate()
|
|
50
|
+
self.v_network = [0.0] * 3
|
|
51
|
+
self.w_network = [0.0] * 3
|
|
52
|
+
|
|
53
|
+
self.ttek = 0
|
|
54
|
+
self.total = 0
|
|
55
|
+
self.served = 0
|
|
56
|
+
self.in_sys = 0
|
|
57
|
+
self.arrived = 0
|
|
58
|
+
|
|
59
|
+
def choose_next_node(self, current_node):
|
|
60
|
+
"""
|
|
61
|
+
Choose the next node for a task based on the current node
|
|
62
|
+
:param current_node: The current node of the task.
|
|
63
|
+
:return: The index of the next node.
|
|
64
|
+
"""
|
|
65
|
+
sum_p = 0
|
|
66
|
+
p = np.random.rand()
|
|
67
|
+
for i in range(self.R.shape[0]):
|
|
68
|
+
sum_p += self.R[current_node + 1, i]
|
|
69
|
+
if sum_p > p:
|
|
70
|
+
return i
|
|
71
|
+
return 0
|
|
72
|
+
|
|
73
|
+
def refresh_v_stat(self, new_a):
|
|
74
|
+
"""
|
|
75
|
+
Refresh sojourn time statistics
|
|
76
|
+
:param new_a: The new arrival time.
|
|
77
|
+
"""
|
|
78
|
+
factor = (1.0 - (1.0 / self.served))
|
|
79
|
+
a_pow = [math.pow(new_a, i + 1) for i in range(3)]
|
|
80
|
+
for i in range(3):
|
|
81
|
+
self.v_network[i] = self.v_network[i] * \
|
|
82
|
+
factor + a_pow[i] / self.served
|
|
83
|
+
|
|
84
|
+
def refresh_w_stat(self, new_a):
|
|
85
|
+
"""
|
|
86
|
+
Refresh waiting time statistics
|
|
87
|
+
:param new_a: The new arrival time.
|
|
88
|
+
|
|
89
|
+
"""
|
|
90
|
+
factor = (1.0 - (1.0 / self.served))
|
|
91
|
+
a_pow = [math.pow(new_a, i + 1) for i in range(3)]
|
|
92
|
+
for i in range(3):
|
|
93
|
+
self.w_network[i] = self.w_network[i] * \
|
|
94
|
+
factor + a_pow[i] / self.served
|
|
95
|
+
|
|
96
|
+
def run_one_step(self):
|
|
97
|
+
"""
|
|
98
|
+
Run one step of the simulation.
|
|
99
|
+
"""
|
|
100
|
+
num_of_serv_ch_earlier = -1 # номер канала узла, мин время до окончания обслуживания
|
|
101
|
+
num_of_node_earlier = -1 # номер узла, в котором раньше всех закончится обслуживание
|
|
102
|
+
arrival_earlier = 1e10 # момент прибытия ближайшего
|
|
103
|
+
serving_earlier = 1e10 # момент ближайшего обслуживания
|
|
104
|
+
|
|
105
|
+
if self.arrival_time < arrival_earlier:
|
|
106
|
+
arrival_earlier = self.arrival_time
|
|
107
|
+
|
|
108
|
+
for node in range(self.n_num):
|
|
109
|
+
for c in range(self.nodes[node]):
|
|
110
|
+
if self.qs[node].servers[c].time_to_end_service < serving_earlier:
|
|
111
|
+
serving_earlier = self.qs[node].servers[c].time_to_end_service
|
|
112
|
+
num_of_serv_ch_earlier = c
|
|
113
|
+
num_of_node_earlier = node
|
|
114
|
+
|
|
115
|
+
if arrival_earlier < serving_earlier:
|
|
116
|
+
self.on_arrival(arrival_earlier)
|
|
117
|
+
else:
|
|
118
|
+
self.on_serving(serving_earlier,
|
|
119
|
+
num_of_serv_ch_earlier, num_of_node_earlier)
|
|
120
|
+
|
|
121
|
+
def on_arrival(self, arrival_earlier):
|
|
122
|
+
"""
|
|
123
|
+
Handle arrival event
|
|
124
|
+
"""
|
|
125
|
+
self.ttek = arrival_earlier
|
|
126
|
+
self.arrived += 1
|
|
127
|
+
self.in_sys += 1
|
|
128
|
+
|
|
129
|
+
self.arrival_time = self.ttek + self.source.generate()
|
|
130
|
+
|
|
131
|
+
next_node = self.choose_next_node(-1)
|
|
132
|
+
|
|
133
|
+
ts = Task(self.ttek, is_network=True)
|
|
134
|
+
|
|
135
|
+
self.qs[next_node].arrival(self.ttek, ts)
|
|
136
|
+
|
|
137
|
+
def on_serving(self, serving_earlier, num_of_serv_ch_earlier, num_of_node_earlier):
|
|
138
|
+
"""
|
|
139
|
+
Handle serving event
|
|
140
|
+
"""
|
|
141
|
+
self.ttek = serving_earlier
|
|
142
|
+
ts = self.qs[num_of_node_earlier].serving(
|
|
143
|
+
num_of_serv_ch_earlier, True)
|
|
144
|
+
|
|
145
|
+
next_node = self.choose_next_node(num_of_node_earlier)
|
|
146
|
+
|
|
147
|
+
if next_node == self.n_num:
|
|
148
|
+
self.served += 1
|
|
149
|
+
self.in_sys -= 1
|
|
150
|
+
|
|
151
|
+
self.refresh_v_stat(self.ttek - ts.arr_network)
|
|
152
|
+
self.refresh_w_stat(ts.wait_network)
|
|
153
|
+
|
|
154
|
+
else:
|
|
155
|
+
self.qs[next_node].arrival(self.ttek, ts)
|
|
156
|
+
|
|
157
|
+
def run(self, job_served, is_real_served=True):
|
|
158
|
+
"""
|
|
159
|
+
Run simulation
|
|
160
|
+
"""
|
|
161
|
+
if is_real_served:
|
|
162
|
+
last_percent = 0
|
|
163
|
+
|
|
164
|
+
with tqdm(total=100) as pbar:
|
|
165
|
+
while self.served < job_served:
|
|
166
|
+
self.run_one_step()
|
|
167
|
+
percent = int(100*(self.served/job_served))
|
|
168
|
+
if last_percent != percent:
|
|
169
|
+
last_percent = percent
|
|
170
|
+
pbar.update(1)
|
|
171
|
+
pbar.set_description(Fore.MAGENTA + '\rJob served: ' +
|
|
172
|
+
Fore.YELLOW + f'{self.served}/{job_served}' + Fore.LIGHTGREEN_EX)
|
|
173
|
+
else:
|
|
174
|
+
print(Fore.GREEN + '\rStart simulation')
|
|
175
|
+
print(Style.RESET_ALL)
|
|
176
|
+
|
|
177
|
+
for _ in tqdm(range(job_served)):
|
|
178
|
+
self.run_one_step()
|
|
179
|
+
|
|
180
|
+
print(Fore.GREEN + '\rSimulation is finished')
|
|
181
|
+
print(Style.RESET_ALL)
|
|
@@ -60,12 +60,9 @@ class PriorityQueueSimulator:
|
|
|
60
60
|
|
|
61
61
|
# probability of states of the system (number of requests in it j):
|
|
62
62
|
self.p = []
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
self.queue
|
|
66
|
-
else:
|
|
67
|
-
for _ in range(self.k):
|
|
68
|
-
self.queue.append([])
|
|
63
|
+
|
|
64
|
+
for _ in range(self.k):
|
|
65
|
+
self.queue.append([])
|
|
69
66
|
|
|
70
67
|
for _ in range(self.k):
|
|
71
68
|
self.busy.append([0, 0, 0])
|
|
@@ -369,12 +366,12 @@ class PriorityQueueSimulator:
|
|
|
369
366
|
"""
|
|
370
367
|
if not self.buffer: # no buffer, infinite queue length
|
|
371
368
|
new_tsk.start_waiting_time = self.ttek
|
|
372
|
-
self.queue.append(new_tsk)
|
|
369
|
+
self.queue[k].append(new_tsk)
|
|
373
370
|
else:
|
|
374
371
|
|
|
375
372
|
if len(self.queue) < self.buffer:
|
|
376
373
|
new_tsk.start_waiting_time = self.ttek
|
|
377
|
-
self.queue.append(new_tsk)
|
|
374
|
+
self.queue[k].append(new_tsk)
|
|
378
375
|
else:
|
|
379
376
|
self.dropped[k] += 1
|
|
380
377
|
self.in_sys[k] -= 1
|
|
@@ -473,13 +470,14 @@ class PriorityQueueSimulator:
|
|
|
473
470
|
self.refresh_w_stat(k, end_ts.wait_time)
|
|
474
471
|
self.in_sys[k] -= 1
|
|
475
472
|
|
|
476
|
-
if len(self.queue[k]) == 0 and self.free_channels == 1:
|
|
477
|
-
if self.in_sys[k] == self.n - 1 and self.class_busy_started != -1:
|
|
478
|
-
# End of busy period
|
|
479
|
-
self.busy_moments[k] += 1
|
|
480
|
-
self.refresh_busy_stat(k, self.ttek - self.start_busy)
|
|
481
473
|
|
|
482
474
|
if self.prty_type != "No":
|
|
475
|
+
if len(self.queue[k]) == 0 and self.free_channels == 1:
|
|
476
|
+
if self.in_sys[k] == self.n - 1 and self.class_busy_started != -1:
|
|
477
|
+
# End of busy period
|
|
478
|
+
self.busy_moments[k] += 1
|
|
479
|
+
self.refresh_busy_stat(k, self.ttek - self.start_busy)
|
|
480
|
+
|
|
483
481
|
|
|
484
482
|
start_number = 0
|
|
485
483
|
if self.prty_type == "PR" or self.prty_type == "RS" or self.prty_type == "RW":
|
|
@@ -507,10 +505,15 @@ class PriorityQueueSimulator:
|
|
|
507
505
|
self.free_channels -= 1
|
|
508
506
|
break
|
|
509
507
|
else:
|
|
508
|
+
if len(self.queue[0]) == 0 and self.free_channels == 1:
|
|
509
|
+
if self.in_sys == self.n - 1 and self.class_busy_started != -1:
|
|
510
|
+
# End of busy period
|
|
511
|
+
self.busy_moments += 1
|
|
512
|
+
self.refresh_busy_stat(0, self.ttek - self.start_busy)
|
|
510
513
|
# one queue
|
|
511
|
-
if len(self.queue) != 0:
|
|
514
|
+
if len(self.queue[0]) != 0:
|
|
512
515
|
|
|
513
|
-
que_ts = self.queue.pop(0)
|
|
516
|
+
que_ts = self.queue[0].pop(0)
|
|
514
517
|
|
|
515
518
|
if self.free_channels == 1 and k != end_ts.k:
|
|
516
519
|
self.start_busy[k] = self.ttek
|
|
@@ -10,10 +10,15 @@ class Task:
|
|
|
10
10
|
"""
|
|
11
11
|
id = 0
|
|
12
12
|
|
|
13
|
-
def __init__(self, arr_time):
|
|
13
|
+
def __init__(self, arr_time, is_network=False):
|
|
14
14
|
"""
|
|
15
15
|
:param arr_time: Момент прибытия в СМО
|
|
16
16
|
"""
|
|
17
|
+
|
|
18
|
+
if is_network:
|
|
19
|
+
self.arr_network = arr_time
|
|
20
|
+
self.wait_network = 0
|
|
21
|
+
|
|
17
22
|
self.arr_time = arr_time
|
|
18
23
|
|
|
19
24
|
self.start_waiting_time = 0
|
|
@@ -115,8 +120,8 @@ class ImpatientTask(Task):
|
|
|
115
120
|
A task that can leave the queue if it has not been served by a server within a certain time.
|
|
116
121
|
"""
|
|
117
122
|
|
|
118
|
-
def __init__(self, arr_time, moment_to_leave):
|
|
119
|
-
super().__init__(arr_time)
|
|
123
|
+
def __init__(self, arr_time, moment_to_leave, is_network=False):
|
|
124
|
+
super().__init__(arr_time, is_network)
|
|
120
125
|
self.moment_to_leave = moment_to_leave
|
|
121
126
|
|
|
122
127
|
def __str__(self):
|
|
@@ -132,8 +137,8 @@ class ImpatientTaskWithRepairs(ImpatientTask):
|
|
|
132
137
|
Tracking if the task arrived in repair mode or not.
|
|
133
138
|
"""
|
|
134
139
|
|
|
135
|
-
def __init__(self, arr_time, moment_to_leave, arrive_in_repair_mode=False):
|
|
136
|
-
super().__init__(arr_time, moment_to_leave)
|
|
140
|
+
def __init__(self, arr_time, moment_to_leave, arrive_in_repair_mode=False, is_network=False):
|
|
141
|
+
super().__init__(arr_time, moment_to_leave, is_network)
|
|
137
142
|
self.arrive_in_repair_mode = arrive_in_repair_mode
|
|
138
143
|
self.end_repair_time = 1e16
|
|
139
144
|
self.is_end_repair = False
|
|
@@ -16,7 +16,7 @@ class EkDn:
|
|
|
16
16
|
|
|
17
17
|
def __init__(self, erlang_params: ErlangParams, b, n, e=1e-12, p_num=100):
|
|
18
18
|
"""
|
|
19
|
-
|
|
19
|
+
erlang_params - parameters of the Erlang input request distribution
|
|
20
20
|
b - service time in a channel
|
|
21
21
|
n - number of channels
|
|
22
22
|
e - accuracy of calculations
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Calculates queueing network.
|
|
3
|
+
"""
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from most_queue.rand_distribution import GammaDistribution
|
|
7
|
+
from most_queue.theory.fifo.mgn_takahasi import MGnCalc
|
|
8
|
+
from most_queue.theory.fifo.mmnr import MMnrCalc
|
|
9
|
+
from most_queue.theory.utils.diff5dots import diff5dots
|
|
10
|
+
from most_queue.theory.utils.transforms import lst_gamma
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class OpenNetworkCalc:
|
|
14
|
+
"""
|
|
15
|
+
Calculates queueing network.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, R: np.matrix, b: list[list[float]],
|
|
19
|
+
n: list[int], arrival_rate: float):
|
|
20
|
+
"""
|
|
21
|
+
R: routing matrix
|
|
22
|
+
b: list of theoretical moments of service time distribution for each node.
|
|
23
|
+
n: list of number of channels in each node.
|
|
24
|
+
L: arrival intensitiy.
|
|
25
|
+
"""
|
|
26
|
+
self.R = R
|
|
27
|
+
self.b = b
|
|
28
|
+
self.n = n
|
|
29
|
+
self.arrival_rate = arrival_rate
|
|
30
|
+
|
|
31
|
+
def balance_equation(self, L, R):
|
|
32
|
+
"""
|
|
33
|
+
Calc the balance equation for the network.
|
|
34
|
+
"""
|
|
35
|
+
# Create copies to avoid modifying original matrices
|
|
36
|
+
L = np.array(L)
|
|
37
|
+
R = np.array(R)
|
|
38
|
+
|
|
39
|
+
# Identify null columns using vectorized operation
|
|
40
|
+
null_mask = np.all(np.abs(R) < 1e-6, axis=0)
|
|
41
|
+
_null_numbers = np.where(null_mask)[0]
|
|
42
|
+
|
|
43
|
+
# Remove null columns and corresponding rows
|
|
44
|
+
R_nonull = R[:, ~null_mask]
|
|
45
|
+
R_nonull = R_nonull[~null_mask, :]
|
|
46
|
+
|
|
47
|
+
n_rows_mod, n_cols_mod = R_nonull.shape
|
|
48
|
+
|
|
49
|
+
# Calculate b and Q matrices using efficient indexing
|
|
50
|
+
if n_rows_mod > 0:
|
|
51
|
+
b = np.dot(L, R_nonull[0, :-1])
|
|
52
|
+
Q = R_nonull[1:, :-1]
|
|
53
|
+
A = np.eye(n_cols_mod - 1) - Q.T
|
|
54
|
+
intensities = np.linalg.solve(A, b)
|
|
55
|
+
else:
|
|
56
|
+
intensities = np.array([], dtype=np.float64)
|
|
57
|
+
|
|
58
|
+
# Create output array with zeros for null columns
|
|
59
|
+
l_out = np.zeros(R.shape[1] - 1, dtype=np.float64)
|
|
60
|
+
|
|
61
|
+
# Fill non-null columns
|
|
62
|
+
_valid_indices = np.arange(len(intensities))
|
|
63
|
+
l_out[~null_mask[:-1]] = intensities.flatten()
|
|
64
|
+
|
|
65
|
+
return l_out
|
|
66
|
+
|
|
67
|
+
def run(self, is_markovian=False):
|
|
68
|
+
"""
|
|
69
|
+
Run the simulation and calculate the results.
|
|
70
|
+
"""
|
|
71
|
+
res = {}
|
|
72
|
+
|
|
73
|
+
nodes = len(self.n)
|
|
74
|
+
res['loads'] = [0.0] * nodes
|
|
75
|
+
res['v'] = []
|
|
76
|
+
|
|
77
|
+
intensities = self.balance_equation(self.arrival_rate, self.R)
|
|
78
|
+
|
|
79
|
+
res['v_node'] = []
|
|
80
|
+
for i in range(nodes):
|
|
81
|
+
node_arrival_rate = intensities[i]
|
|
82
|
+
b1_node = self.b[i][0]
|
|
83
|
+
|
|
84
|
+
res['loads'][i] = node_arrival_rate * b1_node / self.n[i]
|
|
85
|
+
|
|
86
|
+
if is_markovian:
|
|
87
|
+
mmnr_calc = MMnrCalc(l=node_arrival_rate, mu=1/b1_node, n=self.n[i], r=100)
|
|
88
|
+
res['v_node'].append(mmnr_calc.get_v())
|
|
89
|
+
else:
|
|
90
|
+
mgn_calc = MGnCalc(n=self.n[i], l=node_arrival_rate, b=self.b[i])
|
|
91
|
+
mgn_calc.run()
|
|
92
|
+
res['v_node'].append(mgn_calc.get_v())
|
|
93
|
+
|
|
94
|
+
h = 0.0001
|
|
95
|
+
s = [h * (i + 1) for i in range(4)]
|
|
96
|
+
|
|
97
|
+
I = np.eye(nodes)
|
|
98
|
+
N = np.zeros((nodes, nodes))
|
|
99
|
+
P = self.R[0, :nodes].reshape(1, -1)
|
|
100
|
+
T = self.R[1:, nodes].reshape(-1, 1)
|
|
101
|
+
Q = self.R[1:, :nodes]
|
|
102
|
+
|
|
103
|
+
gamma_mu_alpha = [GammaDistribution.get_params(
|
|
104
|
+
[res['v_node'][i][0], res['v_node'][i][1]]) for i in range(nodes)]
|
|
105
|
+
|
|
106
|
+
g_PLS = []
|
|
107
|
+
for i in range(4):
|
|
108
|
+
N = np.diag([lst_gamma(
|
|
109
|
+
gamma_mu_alpha[j], s[i]) for j in range(nodes)])
|
|
110
|
+
|
|
111
|
+
G = np.dot(N, Q)
|
|
112
|
+
FF = I - G
|
|
113
|
+
F = np.linalg.inv(FF)
|
|
114
|
+
F = np.dot(P, np.dot(F, np.dot(N, T)))
|
|
115
|
+
g_PLS.append(F[0, 0])
|
|
116
|
+
|
|
117
|
+
res['v'] = diff5dots(g_PLS, h)
|
|
118
|
+
res['v'][0] = -res['v'][0]
|
|
119
|
+
res['v'][2] = -res['v'][2]
|
|
120
|
+
|
|
121
|
+
res['intensities'] = intensities
|
|
122
|
+
res['v'] = [float(v) for v in res['v']]
|
|
123
|
+
res['loads'] = [float(l) for l in res['loads']]
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
return res
|