mdpsolver 0.9.9__tar.gz → 0.10.0__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.
- mdpsolver-0.9.9/README.md → mdpsolver-0.10.0/PKG-INFO +20 -22
- mdpsolver-0.9.9/src/mdpsolver.egg-info/PKG-INFO → mdpsolver-0.10.0/README.md +2 -39
- mdpsolver-0.10.0/pyproject.toml +40 -0
- {mdpsolver-0.9.9 → mdpsolver-0.10.0}/src/mdpsolver/model.py +53 -31
- mdpsolver-0.10.0/tests/example_model.py +139 -0
- mdpsolver-0.10.0/tests/rewards_example2.csv +403 -0
- mdpsolver-0.10.0/tests/test1.py +717 -0
- mdpsolver-0.10.0/tests/test2.py +94 -0
- mdpsolver-0.9.9/tests/test2.py → mdpsolver-0.10.0/tests/test2_pip.py +10 -7
- mdpsolver-0.10.0/tests/transitions_example2.csv +41205 -0
- mdpsolver-0.9.9/PKG-INFO +0 -170
- mdpsolver-0.9.9/pyproject.toml +0 -31
- mdpsolver-0.9.9/setup.cfg +0 -4
- mdpsolver-0.9.9/src/mdpsolver/problems/__pycache__/cbmaux.cpython-310.pyc +0 -0
- mdpsolver-0.9.9/src/mdpsolver/problems/__pycache__/tbmaux.cpython-310.pyc +0 -0
- mdpsolver-0.9.9/src/mdpsolver/problems/cbmaux.py +0 -40
- mdpsolver-0.9.9/src/mdpsolver/problems/tbmaux.py +0 -40
- mdpsolver-0.9.9/src/mdpsolver/solvermodule.cp310-win_amd64.pyd +0 -0
- mdpsolver-0.9.9/src/mdpsolver/solvermodule.cp311-win_amd64.pyd +0 -0
- mdpsolver-0.9.9/src/mdpsolver/solvermodule.cp312-win_amd64.pyd +0 -0
- mdpsolver-0.9.9/src/mdpsolver/solvermodule.cp313-win_amd64.pyd +0 -0
- mdpsolver-0.9.9/src/mdpsolver/solvermodule.cpython-310-x86_64-linux-gnu.so +0 -0
- mdpsolver-0.9.9/src/mdpsolver/solvermodule.cpython-311-x86_64-linux-gnu.so +0 -0
- mdpsolver-0.9.9/src/mdpsolver/solvermodule.cpython-312-x86_64-linux-gnu.so +0 -0
- mdpsolver-0.9.9/src/mdpsolver/solvermodule.cpython-313-x86_64-linux-gnu.so +0 -0
- mdpsolver-0.9.9/src/mdpsolver.egg-info/SOURCES.txt +0 -24
- mdpsolver-0.9.9/src/mdpsolver.egg-info/dependency_links.txt +0 -1
- mdpsolver-0.9.9/src/mdpsolver.egg-info/top_level.txt +0 -1
- {mdpsolver-0.9.9 → mdpsolver-0.10.0}/LICENSE +0 -0
- {mdpsolver-0.9.9 → mdpsolver-0.10.0}/MANIFEST.in +0 -0
- {mdpsolver-0.9.9 → mdpsolver-0.10.0}/src/mdpsolver/__init__.py +0 -0
- mdpsolver-0.9.9/tests/test1.py → mdpsolver-0.10.0/tests/test1_pip.py +1 -1
|
@@ -1,12 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: mdpsolver
|
|
3
|
+
Version: 0.10.0
|
|
4
|
+
Summary: A fast solver for Markov Decision Processes
|
|
5
|
+
Author-Email: Anders Reenberg Andersen <andersra@live.dk>, Jesper Fink Andersen <jesperfinkandersen@gmail.com>
|
|
6
|
+
Classifier: Development Status :: 4 - Beta
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
10
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
11
|
+
Classifier: Operating System :: MacOS
|
|
12
|
+
Project-URL: Homepage, https://github.com/areenberg/MDPSolver
|
|
13
|
+
Project-URL: Issues, https://github.com/areenberg/MDPSolver/issues
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Provides-Extra: test
|
|
16
|
+
Requires-Dist: numpy; extra == "test"
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
2
18
|
|
|
3
|
-
|
|
19
|
+
# MDPSolver
|
|
4
20
|
|
|
5
21
|
MDPSolver is a Python package for large Markov Decision Processes (MDPs) with infinite-horizons.
|
|
6
22
|
|
|
7
23
|
## Features
|
|
8
24
|
|
|
9
|
-
* Fast solver: Our C++-based solver is substantially faster than other MDP packages available for Python. See details in the documentation.
|
|
25
|
+
* Fast solver: Our C++-based solver is substantially faster than other CPU-based MDP packages available for Python. See details in the documentation.
|
|
10
26
|
* Two optimality criteria: *Discounted* and *Average* reward.
|
|
11
27
|
* Three optimization algorithms: *Value iteration*, *Policy iteration*, and *Modified policy iteration*.
|
|
12
28
|
* Three value-update methods: *Standard*, *Gauss–Seidel*, and *Successive over-relaxation*.
|
|
@@ -15,25 +31,7 @@ MDPSolver is a Python package for large Markov Decision Processes (MDPs) with in
|
|
|
15
31
|
|
|
16
32
|
# Installation
|
|
17
33
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
Install directly from PyPI with:
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
pip install mdpsolver
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
MDPSolver works *out of the box* on Ubuntu 22 and newer.
|
|
27
|
-
|
|
28
|
-
### GLIBC not found
|
|
29
|
-
|
|
30
|
-
Some users will encounter the `version 'GLIBC_2.32' not found` error when attempting to import MDPSolver in Python. In this case, it might help to manually compile and replace the SO-file for the optimization module in the MDPSolver package. See the steps on how to solve the issue in the [documentation](https://github.com/areenberg/MDPSolver/wiki#how-to-install).
|
|
31
|
-
|
|
32
|
-
## Windows
|
|
33
|
-
|
|
34
|
-
Requires [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/) (17.9) with MSVC C++ compiler and libraries installed.
|
|
35
|
-
|
|
36
|
-
After installing Visual Studio (incl. MSVC C++ compiler and libraries), install directly from PyPI with:
|
|
34
|
+
Prebuilt wheels are available for **Linux**, **Windows**, and **macOS (14+)** across Python 3.10–3.14. Install directly from PyPI with:
|
|
37
35
|
|
|
38
36
|
```
|
|
39
37
|
pip install mdpsolver
|
|
@@ -1,29 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: mdpsolver
|
|
3
|
-
Version: 0.9.9
|
|
4
|
-
Summary: A fast solver for Markov Decision Processes
|
|
5
|
-
Author-email: Anders Reenberg Andersen <andersra@live.dk>, Jesper Fink Andersen <jesperfinkandersen@gmail.com>
|
|
6
|
-
Project-URL: Homepage, https://github.com/areenberg/MDPSolver
|
|
7
|
-
Project-URL: Issues, https://github.com/areenberg/MDPSolver/issues
|
|
8
|
-
Classifier: Development Status :: 3 - Alpha
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Operating System :: Microsoft :: Windows
|
|
12
|
-
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
-
Requires-Python: >=3.10
|
|
14
|
-
Description-Content-Type: text/markdown
|
|
15
|
-
License-File: LICENSE
|
|
16
|
-
Dynamic: license-file
|
|
17
|
-
|
|
18
1
|
# MDPSolver
|
|
19
2
|
|
|
20
|
-
<img src="https://github.com/areenberg/MDPSolver/blob/anders_development/Images/MDPSolver_logo_3.png" alt="Logo" width="180">
|
|
21
|
-
|
|
22
3
|
MDPSolver is a Python package for large Markov Decision Processes (MDPs) with infinite-horizons.
|
|
23
4
|
|
|
24
5
|
## Features
|
|
25
6
|
|
|
26
|
-
* Fast solver: Our C++-based solver is substantially faster than other MDP packages available for Python. See details in the documentation.
|
|
7
|
+
* Fast solver: Our C++-based solver is substantially faster than other CPU-based MDP packages available for Python. See details in the documentation.
|
|
27
8
|
* Two optimality criteria: *Discounted* and *Average* reward.
|
|
28
9
|
* Three optimization algorithms: *Value iteration*, *Policy iteration*, and *Modified policy iteration*.
|
|
29
10
|
* Three value-update methods: *Standard*, *Gauss–Seidel*, and *Successive over-relaxation*.
|
|
@@ -32,25 +13,7 @@ MDPSolver is a Python package for large Markov Decision Processes (MDPs) with in
|
|
|
32
13
|
|
|
33
14
|
# Installation
|
|
34
15
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
Install directly from PyPI with:
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
pip install mdpsolver
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
MDPSolver works *out of the box* on Ubuntu 22 and newer.
|
|
44
|
-
|
|
45
|
-
### GLIBC not found
|
|
46
|
-
|
|
47
|
-
Some users will encounter the `version 'GLIBC_2.32' not found` error when attempting to import MDPSolver in Python. In this case, it might help to manually compile and replace the SO-file for the optimization module in the MDPSolver package. See the steps on how to solve the issue in the [documentation](https://github.com/areenberg/MDPSolver/wiki#how-to-install).
|
|
48
|
-
|
|
49
|
-
## Windows
|
|
50
|
-
|
|
51
|
-
Requires [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/) (17.9) with MSVC C++ compiler and libraries installed.
|
|
52
|
-
|
|
53
|
-
After installing Visual Studio (incl. MSVC C++ compiler and libraries), install directly from PyPI with:
|
|
16
|
+
Prebuilt wheels are available for **Linux**, **Windows**, and **macOS (14+)** across Python 3.10–3.14. Install directly from PyPI with:
|
|
54
17
|
|
|
55
18
|
```
|
|
56
19
|
pip install mdpsolver
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["scikit-build-core>=0.10", "pybind11>=2.13"]
|
|
3
|
+
build-backend = "scikit_build_core.build"
|
|
4
|
+
|
|
5
|
+
[tool.scikit-build]
|
|
6
|
+
# The CMake project lives outside Python/, next to the rest of the C++ sources.
|
|
7
|
+
cmake.source-dir = "../CPP_Source_Code"
|
|
8
|
+
build-dir = "build/{wheel_tag}"
|
|
9
|
+
# CMakeLists.txt installs the extension to DESTINATION mdpsolver itself,
|
|
10
|
+
# so wheel.install-dir stays at the default (wheel root) here.
|
|
11
|
+
sdist.include = ["src/mdpsolver/*.py"]
|
|
12
|
+
|
|
13
|
+
[tool.scikit-build.cmake.define]
|
|
14
|
+
CMAKE_BUILD_TYPE = "Release"
|
|
15
|
+
|
|
16
|
+
[project]
|
|
17
|
+
name = "mdpsolver"
|
|
18
|
+
version = "0.10.0"
|
|
19
|
+
authors = [
|
|
20
|
+
{ name="Anders Reenberg Andersen", email="andersra@live.dk" },
|
|
21
|
+
{ name="Jesper Fink Andersen", email="jesperfinkandersen@gmail.com" },
|
|
22
|
+
]
|
|
23
|
+
description = "A fast solver for Markov Decision Processes"
|
|
24
|
+
readme = "README.md"
|
|
25
|
+
requires-python = ">=3.10"
|
|
26
|
+
classifiers = [
|
|
27
|
+
"Development Status :: 4 - Beta",
|
|
28
|
+
"Programming Language :: Python :: 3",
|
|
29
|
+
"License :: OSI Approved :: MIT License",
|
|
30
|
+
"Operating System :: Microsoft :: Windows",
|
|
31
|
+
"Operating System :: POSIX :: Linux",
|
|
32
|
+
"Operating System :: MacOS"
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
test = ["numpy"]
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://github.com/areenberg/MDPSolver"
|
|
40
|
+
Issues = "https://github.com/areenberg/MDPSolver/issues"
|
|
@@ -6,9 +6,9 @@ and solve Markov Decision Processes (MDPs). It provides methods to configure the
|
|
|
6
6
|
solve it, and extract the resulting policy and value vectors.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
+
import sys
|
|
9
10
|
from mdpsolver import solvermodule
|
|
10
11
|
|
|
11
|
-
|
|
12
12
|
class model:
|
|
13
13
|
"""
|
|
14
14
|
Creates an MDPSolver object.
|
|
@@ -27,19 +27,19 @@ class model:
|
|
|
27
27
|
|
|
28
28
|
def solve(
|
|
29
29
|
self,
|
|
30
|
-
algorithm="mpi",
|
|
31
|
-
tolerance=1e-3,
|
|
32
|
-
update="standard",
|
|
33
|
-
criterion="discounted",
|
|
34
|
-
parIterLim=100,
|
|
35
|
-
SORrelaxation=1.0,
|
|
36
|
-
initPolicy=list(),
|
|
37
|
-
initValueVector=list(),
|
|
38
|
-
verbose=False,
|
|
39
|
-
postProcessing=True,
|
|
40
|
-
makeFinalCheck=True,
|
|
41
|
-
parallel=True,
|
|
42
|
-
):
|
|
30
|
+
algorithm: str = "mpi",
|
|
31
|
+
tolerance: float = 1e-3,
|
|
32
|
+
update: str = "standard",
|
|
33
|
+
criterion: str = "discounted",
|
|
34
|
+
parIterLim: int = 100,
|
|
35
|
+
SORrelaxation: float = 1.0,
|
|
36
|
+
initPolicy: list = list(),
|
|
37
|
+
initValueVector: list = list(),
|
|
38
|
+
verbose: bool = False,
|
|
39
|
+
postProcessing: bool = True,
|
|
40
|
+
makeFinalCheck: bool = True,
|
|
41
|
+
parallel: bool = True,
|
|
42
|
+
) -> None:
|
|
43
43
|
"""
|
|
44
44
|
Derive an epsilon-optimal policy for the selected MDP model.
|
|
45
45
|
|
|
@@ -60,6 +60,20 @@ class model:
|
|
|
60
60
|
Returns:
|
|
61
61
|
None
|
|
62
62
|
"""
|
|
63
|
+
|
|
64
|
+
if not (algorithm == "mpi" or algorithm == "pi" or algorithm == "vi"):
|
|
65
|
+
sys.exit("Error: Algorithm type not recognized. Select either: 'mpi', 'pi', or 'vi'.")
|
|
66
|
+
if tolerance <= 0.0:
|
|
67
|
+
sys.exit("Error: The tolerance needs to be a positive number.")
|
|
68
|
+
if not (update == "standard" or update == "gs" or update == "sor"):
|
|
69
|
+
sys.exit("Error: Update method not recognized. Select either: 'standard', 'gs', or 'sor'.")
|
|
70
|
+
if not (criterion == "discounted" or criterion == "average"):
|
|
71
|
+
sys.exit("Error: Optimality criterion not recognized. Select either: 'discounted' or 'average'.")
|
|
72
|
+
if parIterLim <= 0 and algorithm == "mpi":
|
|
73
|
+
sys.exit("Error: The partial evaluation limit needs to be a positive number.")
|
|
74
|
+
if (SORrelaxation <= 0.0 or SORrelaxation >= 2.0) and update == "sor":
|
|
75
|
+
sys.exit("Error: The relaxation parameter needs to be between 0.0 and 2.0 (i.e. 0 < SORrelaxation < 2).")
|
|
76
|
+
|
|
63
77
|
self.mdl.solve(
|
|
64
78
|
algorithm=algorithm,
|
|
65
79
|
tolerance=tolerance,
|
|
@@ -75,7 +89,7 @@ class model:
|
|
|
75
89
|
parallel=parallel,
|
|
76
90
|
)
|
|
77
91
|
|
|
78
|
-
def getRuntime(self):
|
|
92
|
+
def getRuntime(self) -> float:
|
|
79
93
|
"""
|
|
80
94
|
Get the runtime of the last solver execution.
|
|
81
95
|
|
|
@@ -84,15 +98,15 @@ class model:
|
|
|
84
98
|
"""
|
|
85
99
|
return self.mdl.getRuntime()
|
|
86
100
|
|
|
87
|
-
def printPolicy(self):
|
|
101
|
+
def printPolicy(self) -> None:
|
|
88
102
|
"""Print the entire policy to the terminal."""
|
|
89
103
|
self.mdl.printPolicy()
|
|
90
104
|
|
|
91
|
-
def printValueVector(self):
|
|
105
|
+
def printValueVector(self) -> None:
|
|
92
106
|
"""Print the entire value vector to the terminal."""
|
|
93
107
|
self.mdl.printValueVector()
|
|
94
108
|
|
|
95
|
-
def getAction(self, stateIndex=0):
|
|
109
|
+
def getAction(self, stateIndex: int = 0) -> int:
|
|
96
110
|
"""
|
|
97
111
|
Get the action from the optimized policy for a specific state.
|
|
98
112
|
|
|
@@ -104,7 +118,7 @@ class model:
|
|
|
104
118
|
"""
|
|
105
119
|
return self.mdl.getAction(stateIndex=stateIndex)
|
|
106
120
|
|
|
107
|
-
def getValue(self, stateIndex=0):
|
|
121
|
+
def getValue(self, stateIndex: int = 0) -> float:
|
|
108
122
|
"""
|
|
109
123
|
Get the value from the optimized value vector for a specific state.
|
|
110
124
|
|
|
@@ -116,7 +130,7 @@ class model:
|
|
|
116
130
|
"""
|
|
117
131
|
return self.mdl.getValue(stateIndex=stateIndex)
|
|
118
132
|
|
|
119
|
-
def getPolicy(self):
|
|
133
|
+
def getPolicy(self) -> list:
|
|
120
134
|
"""
|
|
121
135
|
Get the entire optimized policy.
|
|
122
136
|
|
|
@@ -134,7 +148,7 @@ class model:
|
|
|
134
148
|
"""
|
|
135
149
|
return self.mdl.getValueVector()
|
|
136
150
|
|
|
137
|
-
def saveToFile(self, fileName="result.csv", type="policy"):
|
|
151
|
+
def saveToFile(self, fileName: str = "result.csv", type: str = "policy") -> None:
|
|
138
152
|
"""
|
|
139
153
|
Save the optimized policy or value vector to a file.
|
|
140
154
|
|
|
@@ -145,20 +159,24 @@ class model:
|
|
|
145
159
|
Returns:
|
|
146
160
|
None
|
|
147
161
|
"""
|
|
162
|
+
|
|
163
|
+
if not (type == "policy" or type == "value"):
|
|
164
|
+
sys.exit("Error: Type not recognized. Select either: 'policy' or 'value'.")
|
|
165
|
+
|
|
148
166
|
return self.mdl.saveToFile(fileName=fileName, type=type)
|
|
149
167
|
|
|
150
168
|
def mdp(
|
|
151
169
|
self,
|
|
152
|
-
discount=0.99,
|
|
153
|
-
rewards=list(),
|
|
154
|
-
rewardsElementwise=list(),
|
|
155
|
-
rewardsFromFile="rewards.csv",
|
|
156
|
-
tranMatWithZeros=list(),
|
|
157
|
-
tranMatElementwise=list(),
|
|
158
|
-
tranMatProbs=list(),
|
|
159
|
-
tranMatColumns=list(),
|
|
160
|
-
tranMatFromFile="transitions.csv",
|
|
161
|
-
):
|
|
170
|
+
discount: float = 0.99,
|
|
171
|
+
rewards: list = list(),
|
|
172
|
+
rewardsElementwise: list = list(),
|
|
173
|
+
rewardsFromFile: str = "rewards.csv",
|
|
174
|
+
tranMatWithZeros: list = list(),
|
|
175
|
+
tranMatElementwise: list = list(),
|
|
176
|
+
tranMatProbs: list = list(),
|
|
177
|
+
tranMatColumns: list = list(),
|
|
178
|
+
tranMatFromFile: str = "transitions.csv",
|
|
179
|
+
) -> None:
|
|
162
180
|
"""
|
|
163
181
|
Define the generic MDP model.
|
|
164
182
|
|
|
@@ -176,6 +194,10 @@ class model:
|
|
|
176
194
|
Returns:
|
|
177
195
|
None
|
|
178
196
|
"""
|
|
197
|
+
|
|
198
|
+
if discount <= 0.0 or discount >= 1.0:
|
|
199
|
+
sys.exit("Error: The discount needs to be in the interval between 0.0 and 1.0 (i.e. 0 < discount < 1).")
|
|
200
|
+
|
|
179
201
|
self.mdl.mdp(
|
|
180
202
|
discount=discount,
|
|
181
203
|
rewards=rewards,
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
# Create transition probability matrix and rewards for the 'mdpsolver' examples.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# -----------------------------
|
|
8
|
+
# FUNCTIONS
|
|
9
|
+
# -----------------------------
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def exitDist(startK, arrRate, serRate, tol=1e-9):
|
|
13
|
+
# calculate distribution over states observed by
|
|
14
|
+
# the next arrival assuming the system currently
|
|
15
|
+
# contains 'startK' customers.
|
|
16
|
+
|
|
17
|
+
g = [i * serRate / (i * serRate + arrRate) for i in range(startK, -1, -1)]
|
|
18
|
+
d = [arrRate / (i * serRate + arrRate) for i in range(startK, -1, -1)]
|
|
19
|
+
|
|
20
|
+
Dmat = np.diag(d)
|
|
21
|
+
Zmat = np.zeros((len(g), len(d)))
|
|
22
|
+
Imat = np.eye(len(g))
|
|
23
|
+
Gmat = np.zeros((len(g), len(g)))
|
|
24
|
+
for i in range(startK):
|
|
25
|
+
Gmat[i, i + 1] = g[i]
|
|
26
|
+
mat = np.block([[Gmat, Dmat], [Zmat, Imat]])
|
|
27
|
+
p = np.zeros((1, (startK + 1) * 2))
|
|
28
|
+
p[0, 0] = 1
|
|
29
|
+
|
|
30
|
+
while np.sum(p[0, : startK + 1]) >= tol:
|
|
31
|
+
p = np.matmul(p, mat)
|
|
32
|
+
|
|
33
|
+
return p[0, startK + 1 :]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def tranMat(arrRate1, arrRate2, serRate, capacity, fileName):
|
|
37
|
+
# calculate transition probabilities and
|
|
38
|
+
# and save them in a file
|
|
39
|
+
|
|
40
|
+
ns = capacity + 1
|
|
41
|
+
arrRate = arrRate1 + arrRate2
|
|
42
|
+
pc1 = arrRate1 / arrRate
|
|
43
|
+
pc2 = 1 - pc1
|
|
44
|
+
|
|
45
|
+
if os.path.exists(fileName):
|
|
46
|
+
os.remove(fileName)
|
|
47
|
+
with open(fileName, "a") as file:
|
|
48
|
+
file.write(f"stateFrom,action,stateTo,probability\n")
|
|
49
|
+
for sidx in range(ns): # stateFrom (customer type 1)
|
|
50
|
+
for aidx in range(2):
|
|
51
|
+
if aidx == 0: # reject
|
|
52
|
+
if sidx > 0:
|
|
53
|
+
dist = exitDist(sidx, arrRate, serRate)
|
|
54
|
+
else:
|
|
55
|
+
dist = np.array([1])
|
|
56
|
+
dist1 = pc1 * dist
|
|
57
|
+
dist2 = pc2 * dist
|
|
58
|
+
for jidx in range(sidx + 1):
|
|
59
|
+
out = [sidx, aidx, jidx, dist1[sidx - jidx]]
|
|
60
|
+
str_out = ",".join(str(num) for num in out)
|
|
61
|
+
file.write(str_out + "\n")
|
|
62
|
+
for jidx in range(ns, ns + sidx + 1):
|
|
63
|
+
out = [sidx, aidx, jidx, dist2[sidx - (jidx - ns)]]
|
|
64
|
+
str_out = ",".join(str(num) for num in out)
|
|
65
|
+
file.write(str_out + "\n")
|
|
66
|
+
elif aidx == 1 and sidx < capacity: # accept
|
|
67
|
+
startK = sidx + 1
|
|
68
|
+
dist = exitDist(startK, arrRate, serRate)
|
|
69
|
+
dist1 = pc1 * dist
|
|
70
|
+
dist2 = pc2 * dist
|
|
71
|
+
for jidx in range(startK + 1):
|
|
72
|
+
out = [sidx, aidx, jidx, dist1[startK - jidx]]
|
|
73
|
+
str_out = ",".join(str(num) for num in out)
|
|
74
|
+
file.write(str_out + "\n")
|
|
75
|
+
for jidx in range(ns, ns + startK + 1):
|
|
76
|
+
out = [sidx, aidx, jidx, dist2[startK - (jidx - ns)]]
|
|
77
|
+
str_out = ",".join(str(num) for num in out)
|
|
78
|
+
file.write(str_out + "\n")
|
|
79
|
+
|
|
80
|
+
for sidx in range(ns): # stateFrom (customer type 2)
|
|
81
|
+
for aidx in range(2):
|
|
82
|
+
if aidx == 0: # reject
|
|
83
|
+
if sidx > 0:
|
|
84
|
+
dist = exitDist(sidx, arrRate, serRate)
|
|
85
|
+
else:
|
|
86
|
+
dist = np.array([1])
|
|
87
|
+
dist1 = pc1 * dist
|
|
88
|
+
dist2 = pc2 * dist
|
|
89
|
+
for jidx in range(sidx + 1):
|
|
90
|
+
out = [sidx + ns, aidx, jidx, dist1[sidx - jidx]]
|
|
91
|
+
str_out = ",".join(str(num) for num in out)
|
|
92
|
+
file.write(str_out + "\n")
|
|
93
|
+
for jidx in range(ns, ns + sidx + 1):
|
|
94
|
+
out = [sidx + ns, aidx, jidx, dist2[sidx - (jidx - ns)]]
|
|
95
|
+
str_out = ",".join(str(num) for num in out)
|
|
96
|
+
file.write(str_out + "\n")
|
|
97
|
+
elif aidx == 1 and sidx < capacity: # accept
|
|
98
|
+
startK = sidx + 1
|
|
99
|
+
dist = exitDist(startK, arrRate, serRate)
|
|
100
|
+
dist1 = pc1 * dist
|
|
101
|
+
dist2 = pc2 * dist
|
|
102
|
+
for jidx in range(startK + 1):
|
|
103
|
+
out = [sidx + ns, aidx, jidx, dist1[startK - jidx]]
|
|
104
|
+
str_out = ",".join(str(num) for num in out)
|
|
105
|
+
file.write(str_out + "\n")
|
|
106
|
+
for jidx in range(ns, ns + startK + 1):
|
|
107
|
+
out = [sidx + ns, aidx, jidx, dist2[startK - (jidx - ns)]]
|
|
108
|
+
str_out = ",".join(str(num) for num in out)
|
|
109
|
+
file.write(str_out + "\n")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def rewards(capacity, rewardCust1, rewardCust2, fileName):
|
|
113
|
+
|
|
114
|
+
ns = capacity + 1
|
|
115
|
+
|
|
116
|
+
if os.path.exists(fileName):
|
|
117
|
+
os.remove(fileName)
|
|
118
|
+
with open(fileName, "a") as file:
|
|
119
|
+
file.write(f"stateFrom,action,reward\n")
|
|
120
|
+
for sidx in range(ns): # stateFrom (customer type 1)
|
|
121
|
+
for aidx in range(2):
|
|
122
|
+
if aidx == 0:
|
|
123
|
+
out = [sidx, aidx, 0]
|
|
124
|
+
str_out = ",".join(str(num) for num in out)
|
|
125
|
+
file.write(str_out + "\n")
|
|
126
|
+
elif aidx == 1 and sidx < capacity:
|
|
127
|
+
out = [sidx, aidx, rewardCust1]
|
|
128
|
+
str_out = ",".join(str(num) for num in out)
|
|
129
|
+
file.write(str_out + "\n")
|
|
130
|
+
for sidx in range(ns): # stateFrom (customer type 2)
|
|
131
|
+
for aidx in range(2):
|
|
132
|
+
if aidx == 0:
|
|
133
|
+
out = [sidx + ns, aidx, 0]
|
|
134
|
+
str_out = ",".join(str(num) for num in out)
|
|
135
|
+
file.write(str_out + "\n")
|
|
136
|
+
elif aidx == 1 and sidx < capacity:
|
|
137
|
+
out = [sidx + ns, aidx, rewardCust2]
|
|
138
|
+
str_out = ",".join(str(num) for num in out)
|
|
139
|
+
file.write(str_out + "\n")
|