mdpsolver 0.10.3__tar.gz → 0.12.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.12.0/.gitignore +27 -0
- mdpsolver-0.12.0/CPP_Source_Code/CBMmodel.cpp +388 -0
- mdpsolver-0.12.0/CPP_Source_Code/CBMmodel.h +114 -0
- mdpsolver-0.12.0/CPP_Source_Code/CMakeLists.txt +25 -0
- mdpsolver-0.12.0/CPP_Source_Code/GeneralMDPmodel.cpp +146 -0
- mdpsolver-0.12.0/CPP_Source_Code/GeneralMDPmodel.h +100 -0
- mdpsolver-0.12.0/CPP_Source_Code/ModelType.cpp +1 -0
- mdpsolver-0.12.0/CPP_Source_Code/ModelType.h +53 -0
- mdpsolver-0.12.0/CPP_Source_Code/ModifiedPolicyIteration.cpp +1181 -0
- mdpsolver-0.12.0/CPP_Source_Code/ModifiedPolicyIteration.h +115 -0
- mdpsolver-0.12.0/CPP_Source_Code/ModuleInterface.cpp +1514 -0
- mdpsolver-0.12.0/CPP_Source_Code/ModuleInterface.h +233 -0
- mdpsolver-0.12.0/CPP_Source_Code/Policy.cpp +52 -0
- mdpsolver-0.12.0/CPP_Source_Code/Policy.h +66 -0
- mdpsolver-0.12.0/CPP_Source_Code/PythonModule.cpp +75 -0
- mdpsolver-0.12.0/CPP_Source_Code/Rewards.cpp +52 -0
- mdpsolver-0.12.0/CPP_Source_Code/Rewards.h +78 -0
- mdpsolver-0.12.0/CPP_Source_Code/TBMmodel.cpp +249 -0
- mdpsolver-0.12.0/CPP_Source_Code/TBMmodel.h +106 -0
- mdpsolver-0.12.0/CPP_Source_Code/TransitionMatrix.cpp +98 -0
- mdpsolver-0.12.0/CPP_Source_Code/TransitionMatrix.h +137 -0
- mdpsolver-0.12.0/CPP_Source_Code/ValueVector.cpp +52 -0
- mdpsolver-0.12.0/CPP_Source_Code/ValueVector.h +64 -0
- mdpsolver-0.12.0/PKG-INFO +194 -0
- mdpsolver-0.12.0/Python/src/mdpsolver/__init__.py +1 -0
- mdpsolver-0.12.0/Python/src/mdpsolver/model.py +523 -0
- {mdpsolver-0.10.3 → mdpsolver-0.12.0/Python}/tests/knownsolutions.py +21 -0
- {mdpsolver-0.10.3 → mdpsolver-0.12.0/Python}/tests/loadmdpsolver.py +3 -2
- mdpsolver-0.12.0/Python/tests/test_arrays.py +357 -0
- mdpsolver-0.12.0/Python/tests/test_checkmodel.py +279 -0
- mdpsolver-0.12.0/Python/tests/test_imports.py +861 -0
- {mdpsolver-0.10.3 → mdpsolver-0.12.0/Python}/tests/test_large.py +11 -6
- {mdpsolver-0.10.3 → mdpsolver-0.12.0/Python}/tests/test_mpi.py +30 -16
- mdpsolver-0.12.0/Python/tests/test_order.py +278 -0
- mdpsolver-0.12.0/Python/tests/test_output.py +265 -0
- {mdpsolver-0.10.3 → mdpsolver-0.12.0/Python}/tests/test_pi.py +30 -16
- {mdpsolver-0.10.3 → mdpsolver-0.12.0/Python}/tests/test_random.py +7 -3
- {mdpsolver-0.10.3 → mdpsolver-0.12.0/Python}/tests/test_reuse.py +34 -27
- mdpsolver-0.12.0/Python/tests/test_threads.py +222 -0
- {mdpsolver-0.10.3 → mdpsolver-0.12.0/Python}/tests/test_vi.py +59 -16
- mdpsolver-0.12.0/README.md +175 -0
- {mdpsolver-0.10.3 → mdpsolver-0.12.0}/pyproject.toml +23 -4
- mdpsolver-0.10.3/MANIFEST.in +0 -3
- mdpsolver-0.10.3/PKG-INFO +0 -151
- mdpsolver-0.10.3/README.md +0 -133
- mdpsolver-0.10.3/src/mdpsolver/__init__.py +0 -1
- mdpsolver-0.10.3/src/mdpsolver/model.py +0 -261
- mdpsolver-0.10.3/tests/test_imports.py +0 -491
- {mdpsolver-0.10.3 → mdpsolver-0.12.0}/LICENSE +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/.vs
|
|
2
|
+
/VisualStudioProject
|
|
3
|
+
.vscode/
|
|
4
|
+
.claude/
|
|
5
|
+
.DS_Store
|
|
6
|
+
Python/.DS_Store
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
__pycache__/
|
|
10
|
+
*.pyc
|
|
11
|
+
|
|
12
|
+
Python/src/mdpsolver/problems/
|
|
13
|
+
build/
|
|
14
|
+
dist/
|
|
15
|
+
wheelhouse/
|
|
16
|
+
Dockerfile
|
|
17
|
+
|
|
18
|
+
CompilerNotes.txt
|
|
19
|
+
*.exe
|
|
20
|
+
*egg-info
|
|
21
|
+
*.Rhistory
|
|
22
|
+
Benchmark/results/
|
|
23
|
+
|
|
24
|
+
# Compiled extension modules are built by CI (cibuildwheel) / local build
|
|
25
|
+
# scripts, not committed to the repo.
|
|
26
|
+
*.pyd
|
|
27
|
+
*.so
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2026 Anders Reenberg Andersen and Jesper Fink Andersen
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
* copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
* SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
#include <iostream>
|
|
27
|
+
#include <fstream> //to import component probabilities
|
|
28
|
+
#include <string> //
|
|
29
|
+
#include <sstream> //
|
|
30
|
+
#include <math.h>
|
|
31
|
+
#include <assert.h>
|
|
32
|
+
#include <exception> //for exiting if probabilities cannot be loaded
|
|
33
|
+
#include <algorithm>
|
|
34
|
+
#include <valarray> //for min and max function
|
|
35
|
+
#include "CBMmodel.h"
|
|
36
|
+
|
|
37
|
+
using namespace std;
|
|
38
|
+
|
|
39
|
+
CBMmodel::CBMmodel(double discount,
|
|
40
|
+
int components,
|
|
41
|
+
int stages,
|
|
42
|
+
string importProbPath,
|
|
43
|
+
double preventiveCost,
|
|
44
|
+
double correctiveCost,
|
|
45
|
+
double setupCost,
|
|
46
|
+
double failurePenalty,
|
|
47
|
+
int kOfN): //default constructor
|
|
48
|
+
N(components),
|
|
49
|
+
L(stages-1),
|
|
50
|
+
discount(discount),
|
|
51
|
+
numberOfStates(intPow(stages,components)), //unsigned INT_MAX is 2147483647
|
|
52
|
+
numberOfActions(intPow(2,components)),
|
|
53
|
+
cp(preventiveCost),
|
|
54
|
+
cc(correctiveCost),
|
|
55
|
+
cs(setupCost),
|
|
56
|
+
p(failurePenalty),
|
|
57
|
+
kN(kOfN),
|
|
58
|
+
importProbs(!importProbPath.empty()),
|
|
59
|
+
pCompMat(components,vector<double>(stages)),
|
|
60
|
+
pFailCompMat(components, vector<double>(stages)),
|
|
61
|
+
sidxMat(numberOfStates, vector<int>(components)),
|
|
62
|
+
aidxMat(numberOfActions, vector<int>(components))
|
|
63
|
+
{
|
|
64
|
+
//set K-out-of-N
|
|
65
|
+
if (kN<=0||kN>N){
|
|
66
|
+
kN=N;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//import component probabilities
|
|
70
|
+
if (importProbs) {
|
|
71
|
+
importComponentProbs(importProbPath);
|
|
72
|
+
}
|
|
73
|
+
// calculate tail probabilities
|
|
74
|
+
for (int i = 0; i < N; ++i) {
|
|
75
|
+
pFailCompMat[i][0] = pCompMat[i][L];
|
|
76
|
+
for (int j = 1; j <= L; ++j) {
|
|
77
|
+
pFailCompMat[i][j] = pFailCompMat[i][j - 1] + pCompMat[i][L-j];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//initialize sidxMat
|
|
81
|
+
int sidx_temp,s_i;
|
|
82
|
+
for (int sidx = 0; sidx < numberOfStates; ++sidx) {
|
|
83
|
+
sidx_temp = sidx;
|
|
84
|
+
for (int i = 0; i < N; ++i) {
|
|
85
|
+
s_i = sidx_temp % (L+1);
|
|
86
|
+
sidxMat[sidx][i] = s_i;
|
|
87
|
+
sidx_temp /= (L+1);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//initialize aidxMat
|
|
91
|
+
int aidx_temp, a_i;
|
|
92
|
+
for (int aidx = 0; aidx < numberOfActions; ++aidx) {
|
|
93
|
+
aidx_temp = aidx;
|
|
94
|
+
for (int i = 0; i < N; ++i) {
|
|
95
|
+
a_i = aidx_temp % 2;
|
|
96
|
+
aidxMat[aidx][i] = a_i;
|
|
97
|
+
aidx_temp /= 2;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
CBMmodel::CBMmodel(double discount,
|
|
103
|
+
int components,
|
|
104
|
+
int stages,
|
|
105
|
+
vector<vector<double>> pcm,
|
|
106
|
+
double preventiveCost,
|
|
107
|
+
double correctiveCost,
|
|
108
|
+
double setupCost,
|
|
109
|
+
double failurePenalty,
|
|
110
|
+
int kOfN): //default constructor
|
|
111
|
+
N(components),
|
|
112
|
+
L(stages-1),
|
|
113
|
+
discount(discount),
|
|
114
|
+
numberOfStates(intPow(stages,components)), //unsigned INT_MAX is 2147483647
|
|
115
|
+
numberOfActions(intPow(2,components)),
|
|
116
|
+
cp(preventiveCost),
|
|
117
|
+
cc(correctiveCost),
|
|
118
|
+
cs(setupCost),
|
|
119
|
+
p(failurePenalty),
|
|
120
|
+
kN(kOfN),
|
|
121
|
+
pCompMat(pcm),
|
|
122
|
+
pFailCompMat(components, vector<double>(stages)),
|
|
123
|
+
sidxMat(numberOfStates, vector<int>(components)),
|
|
124
|
+
aidxMat(numberOfActions, vector<int>(components))
|
|
125
|
+
{
|
|
126
|
+
//set K-out-of-N
|
|
127
|
+
if (kN<=0||kN>N){
|
|
128
|
+
kN=N;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// calculate tail probabilities
|
|
132
|
+
for (int i = 0; i < N; ++i) {
|
|
133
|
+
pFailCompMat[i][0] = pCompMat[i][L];
|
|
134
|
+
for (int j = 1; j <= L; ++j) {
|
|
135
|
+
pFailCompMat[i][j] = pFailCompMat[i][j - 1] + pCompMat[i][L-j];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//initialize sidxMat
|
|
139
|
+
int sidx_temp,s_i;
|
|
140
|
+
for (int sidx = 0; sidx < numberOfStates; ++sidx) {
|
|
141
|
+
sidx_temp = sidx;
|
|
142
|
+
for (int i = 0; i < N; ++i) {
|
|
143
|
+
s_i = sidx_temp % (L+1);
|
|
144
|
+
sidxMat[sidx][i] = s_i;
|
|
145
|
+
sidx_temp /= (L+1);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//initialize aidxMat
|
|
149
|
+
int aidx_temp, a_i;
|
|
150
|
+
for (int aidx = 0; aidx < numberOfActions; ++aidx) {
|
|
151
|
+
aidx_temp = aidx;
|
|
152
|
+
for (int i = 0; i < N; ++i) {
|
|
153
|
+
a_i = aidx_temp % 2;
|
|
154
|
+
aidxMat[aidx][i] = a_i;
|
|
155
|
+
aidx_temp /= 2;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
CBMmodel::CBMmodel(const CBMmodel& orig) {
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
CBMmodel::~CBMmodel() {
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
//class functions
|
|
168
|
+
double CBMmodel::reward(int &sidx, int &aidx) {
|
|
169
|
+
//reward function
|
|
170
|
+
r = 0;
|
|
171
|
+
set_up = false;
|
|
172
|
+
fail_count = 0;
|
|
173
|
+
for(int i = 0; i < N; ++i) {
|
|
174
|
+
s_i = sidxMat[sidx][i];//i'th component state
|
|
175
|
+
a_i = aidxMat[aidx][i];
|
|
176
|
+
if (a_i==1) {
|
|
177
|
+
set_up = true;
|
|
178
|
+
if (s_i==L) {
|
|
179
|
+
++fail_count;
|
|
180
|
+
r += cc;
|
|
181
|
+
} else {
|
|
182
|
+
r += cp;
|
|
183
|
+
}
|
|
184
|
+
} else if (s_i==L) {
|
|
185
|
+
++fail_count;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
r += set_up*cs + ((N-fail_count) < kN)*p;
|
|
189
|
+
return r;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
double CBMmodel::transProb(int &sidx, int &aidx, int &jidx) {
|
|
193
|
+
//transition probability function
|
|
194
|
+
|
|
195
|
+
//int step;
|
|
196
|
+
prob = 1;
|
|
197
|
+
for (int i = 0; i<N; ++i) {
|
|
198
|
+
j_i = sidxMat[jidx][i]; //i'th component state
|
|
199
|
+
s_i = sidxMat[sidx][i];
|
|
200
|
+
a_i = aidxMat[aidx][i];
|
|
201
|
+
if (a_i == 0 && j_i<s_i) { // impossible transitions
|
|
202
|
+
prob *= 0;
|
|
203
|
+
} else if (a_i == 0 && j_i >= s_i) { //no replacement
|
|
204
|
+
step = j_i - s_i;
|
|
205
|
+
if (j_i < L) {
|
|
206
|
+
prob *= pCompMat[i][step];
|
|
207
|
+
} else {
|
|
208
|
+
prob *= pFailCompMat[i][s_i];
|
|
209
|
+
}
|
|
210
|
+
} else { //replacement
|
|
211
|
+
prob *= pCompMat[i][j_i];
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
psj = prob; //set stored transition probability
|
|
215
|
+
return prob;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
void CBMmodel::updateTransProbNextState(int sidx, int aidx, int jidx) {
|
|
219
|
+
//void CBMmodel::updateTransProbNextStateOptimized(int sidx, int aidx, int jidx) {
|
|
220
|
+
//updates psj and nextState, which are assumed to match.
|
|
221
|
+
//That is, input jidx should be nextState.
|
|
222
|
+
|
|
223
|
+
int step;
|
|
224
|
+
for (int i = 0; i<N; ++i) {
|
|
225
|
+
j_i = sidxMat[jidx][i]; //i'th component state
|
|
226
|
+
s_i = sidxMat[sidx][i];
|
|
227
|
+
a_i = aidxMat[aidx][i];
|
|
228
|
+
|
|
229
|
+
//assert(a_i == 1 || (a_i == 0 && j_i >= s_i));//check valid transition
|
|
230
|
+
|
|
231
|
+
if (a_i == 0) {
|
|
232
|
+
step = j_i - s_i;
|
|
233
|
+
} else {
|
|
234
|
+
step = j_i;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (j_i<L) {
|
|
238
|
+
nextState += intPow(L + 1, i); //increment i'th component by one
|
|
239
|
+
//psj /= pCompMat[i][step]; //psj should be divided by what was previously used to calc component transition
|
|
240
|
+
if (j_i + 1 < L) {
|
|
241
|
+
psj *= pCompMat[i][step + 1] / pCompMat[i][step]; // still lower than L after increment
|
|
242
|
+
} else {
|
|
243
|
+
if (a_i == 0) {
|
|
244
|
+
psj *= pFailCompMat[i][s_i] / pCompMat[i][step];
|
|
245
|
+
} else {
|
|
246
|
+
psj *= pCompMat[i][j_i + 1] / pCompMat[i][step]; //going from 0 to L here
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
break; //we are done
|
|
250
|
+
} else {
|
|
251
|
+
nextState -= step * intPow(L + 1, i); //reset back to s_i or 0
|
|
252
|
+
//here j_i=L so psj was formely multiplied with a fail probability
|
|
253
|
+
if (a_i == 0) { //went from s_i to L
|
|
254
|
+
psj /= pFailCompMat[i][s_i];
|
|
255
|
+
if (s_i < L) {
|
|
256
|
+
psj *= pCompMat[i][0];
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
psj *= pCompMat[i][0] / pCompMat[i][L];
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
int CBMmodel::postDecisionIdx(int &sidx, int &aidx) {
|
|
266
|
+
//int CBMmodel::postDecisionIdxOptimized(int sidx, int aidx) {
|
|
267
|
+
//state index right after replacement, which is
|
|
268
|
+
//assumed instantaneous so components are set to age 0
|
|
269
|
+
pdidx = sidx;
|
|
270
|
+
|
|
271
|
+
for (int i = 0; i<N; ++i) {
|
|
272
|
+
s_i = sidxMat[sidx][i];
|
|
273
|
+
a_i = aidxMat[aidx][i];
|
|
274
|
+
if (a_i == 1) {
|
|
275
|
+
pdidx -= (s_i)*intPow(L + 1, i); // sets it to 0
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
nextState = pdidx; //store as the "first" next state
|
|
279
|
+
return pdidx;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
void CBMmodel::updateNextState(int &sidx, int &aidx, int &jidx) {
|
|
284
|
+
//increment one component's deterioration level.
|
|
285
|
+
if (jidx != -1) {
|
|
286
|
+
nextState = jidx;
|
|
287
|
+
} else {
|
|
288
|
+
jidx = nextState; // default jidx value is current nextState
|
|
289
|
+
}
|
|
290
|
+
done = false;
|
|
291
|
+
for (int i = 0; i<N; ++i) {
|
|
292
|
+
j_i = sidxMat[jidx][i]; //i'th component state
|
|
293
|
+
s_i = sidxMat[sidx][i];
|
|
294
|
+
a_i = aidxMat[aidx][i];
|
|
295
|
+
|
|
296
|
+
if (!done && j_i<L) { //non-replacements
|
|
297
|
+
nextState += intPow(L + 1, i);
|
|
298
|
+
done = true;
|
|
299
|
+
} else if (!done) {
|
|
300
|
+
if (a_i == 0) {
|
|
301
|
+
nextState -= (j_i - s_i)*intPow(L + 1, i); //reset back to s_i
|
|
302
|
+
} else {
|
|
303
|
+
nextState -= (j_i)*intPow(L + 1, i); //reset back to 0
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
int CBMmodel::intPow(int a, int b) {
|
|
311
|
+
int i = 1;
|
|
312
|
+
for(int j = 1; j <= b; ++j) i *= a;
|
|
313
|
+
return i;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
void CBMmodel::importComponentProbs(string path) {
|
|
317
|
+
string line;
|
|
318
|
+
ifstream inputFile (path);
|
|
319
|
+
try {
|
|
320
|
+
if(!inputFile.is_open()) {
|
|
321
|
+
throw path;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
catch (string path) {
|
|
325
|
+
cout << "Exception: UNABLE TO OPEN FILE: " + path + "\n";
|
|
326
|
+
exit(EXIT_FAILURE);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
int i = 0;
|
|
330
|
+
int j = 0;
|
|
331
|
+
string element;
|
|
332
|
+
while( getline(inputFile, line) ) {
|
|
333
|
+
istringstream lineStream(line);
|
|
334
|
+
// read every element from the line that is separated by commas
|
|
335
|
+
// and put it into pCompMat
|
|
336
|
+
j = 0;
|
|
337
|
+
while( getline(lineStream, element, ',') ){
|
|
338
|
+
pCompMat [i][j] = stod(element);
|
|
339
|
+
//cout << i << " " << j << " " << element << endl;
|
|
340
|
+
++j;
|
|
341
|
+
}
|
|
342
|
+
++i;
|
|
343
|
+
}
|
|
344
|
+
inputFile.close();
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
double CBMmodel::getDiscount(){
|
|
348
|
+
return discount;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
int CBMmodel::getNumberOfStates(){
|
|
352
|
+
return numberOfStates;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
void CBMmodel::updateNumberOfActions(int &sidx){
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
int CBMmodel::getNumberOfActions(){
|
|
359
|
+
return numberOfActions;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
int * CBMmodel::getNextState(){
|
|
363
|
+
return &nextState;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
double CBMmodel::getPsj(){
|
|
367
|
+
return psj;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
int CBMmodel::getColumnIdx(int &sidx, int &aidx, int &cidx){
|
|
371
|
+
return 0;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
int CBMmodel::getNumberOfJumps(int &sidx, int &aidx){
|
|
375
|
+
return 0;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
int CBMmodel::getNumberOfActions(int &sidx){
|
|
379
|
+
return 0;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
//int CBMmodel::getPolicy(int sidx){
|
|
383
|
+
// return policy[sidx];
|
|
384
|
+
//}
|
|
385
|
+
//
|
|
386
|
+
//void CBMmodel::assignPolicy(int sidx, int action){
|
|
387
|
+
// policy[sidx] = action;
|
|
388
|
+
//}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2026 Anders Reenberg Andersen and Jesper Fink Andersen
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
* copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
* SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
#ifndef CBMMODEL_H
|
|
27
|
+
#define CBMMODEL_H
|
|
28
|
+
|
|
29
|
+
#include "ModelType.h"
|
|
30
|
+
#include <vector>
|
|
31
|
+
#include <string>
|
|
32
|
+
|
|
33
|
+
using namespace std;
|
|
34
|
+
|
|
35
|
+
class CBMmodel : public ModelType{
|
|
36
|
+
public:
|
|
37
|
+
|
|
38
|
+
//constructor and destructor
|
|
39
|
+
CBMmodel() {}; //dummy-constructor
|
|
40
|
+
CBMmodel(double discount=0.99,
|
|
41
|
+
int components=2,
|
|
42
|
+
int stages=10,
|
|
43
|
+
string importProbPath="pCompMat.csv",
|
|
44
|
+
double preventiveCost=-5,
|
|
45
|
+
double correctiveCost=-11,
|
|
46
|
+
double setupCost=-4,
|
|
47
|
+
double failurePenalty=-300,
|
|
48
|
+
int kOfN=-1);
|
|
49
|
+
CBMmodel(double discount=0.99,
|
|
50
|
+
int components=2,
|
|
51
|
+
int stages=10,
|
|
52
|
+
vector<vector<double>> pcm={},
|
|
53
|
+
double preventiveCost=-5,
|
|
54
|
+
double correctiveCost=-11,
|
|
55
|
+
double setupCost=-4,
|
|
56
|
+
double failurePenalty=-300,
|
|
57
|
+
int kOfN=-1);
|
|
58
|
+
CBMmodel(const CBMmodel& orig);
|
|
59
|
+
virtual ~CBMmodel();
|
|
60
|
+
|
|
61
|
+
//general MDP parameters
|
|
62
|
+
int N;
|
|
63
|
+
int L;
|
|
64
|
+
double discount;
|
|
65
|
+
int numberOfStates;
|
|
66
|
+
int numberOfActions;
|
|
67
|
+
//vector<int> policy;
|
|
68
|
+
//transition and reward parameters
|
|
69
|
+
double cp; //preventive replacement cost
|
|
70
|
+
double cc; //corrective replacement cost
|
|
71
|
+
double cs; //setup cost
|
|
72
|
+
double p; //system failure penalty
|
|
73
|
+
int kN; // k-out-of-N system, meaning system works iff k components work
|
|
74
|
+
bool importProbs;
|
|
75
|
+
vector<vector<double>> pCompMat; //component transition probs.
|
|
76
|
+
vector<vector<double>> pFailCompMat; //sum of element in pCompMat
|
|
77
|
+
//auxiliary variables
|
|
78
|
+
int nextState; //next state to process
|
|
79
|
+
double psj; //transition probability from state s to j
|
|
80
|
+
int s_i, a_i, j_i;
|
|
81
|
+
vector<vector<int>> sidxMat; // (sidx,i)'th element contains s_i for state index sidx
|
|
82
|
+
vector<vector<int>> aidxMat; // (aidx,i)'th element contains a_i for action index aidx
|
|
83
|
+
|
|
84
|
+
// METHODS
|
|
85
|
+
|
|
86
|
+
//GENERIC METHODS
|
|
87
|
+
double reward(int &sidx, int &aidx) override;
|
|
88
|
+
double transProb(int &sidx, int &aidx, int &jidx) override;
|
|
89
|
+
void updateNextState(int &sidx, int &aidx, int &jidx) override;
|
|
90
|
+
int postDecisionIdx(int &sidx, int &aidx) override;
|
|
91
|
+
double getDiscount() override;
|
|
92
|
+
int getNumberOfStates() override;
|
|
93
|
+
void updateNumberOfActions(int &sidx) override;
|
|
94
|
+
int getNumberOfActions() override;
|
|
95
|
+
int getNumberOfActions(int &sidx) override;
|
|
96
|
+
int * getNextState() override;
|
|
97
|
+
double getPsj() override;
|
|
98
|
+
int getNumberOfJumps(int &sidx, int &aidx) override; //not used
|
|
99
|
+
int getColumnIdx(int &sidx, int &aidx, int &cidx) override; //not used
|
|
100
|
+
|
|
101
|
+
//SPECIAL METHODS
|
|
102
|
+
void updateTransProbNextState(int, int, int);
|
|
103
|
+
int intPow(int, int);
|
|
104
|
+
void importComponentProbs(string path);
|
|
105
|
+
|
|
106
|
+
private:
|
|
107
|
+
|
|
108
|
+
double r,prob;
|
|
109
|
+
bool set_up,done;
|
|
110
|
+
int fail_count,step,pdidx;
|
|
111
|
+
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
#endif /* CBMMODEL_H */
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.15)
|
|
2
|
+
|
|
3
|
+
project(solvermodule LANGUAGES CXX)
|
|
4
|
+
|
|
5
|
+
# pybind11 now comes from PyPI (declared as a build-time dependency in
|
|
6
|
+
# Python/pyproject.toml) instead of being vendored as a subdirectory.
|
|
7
|
+
find_package(pybind11 CONFIG REQUIRED)
|
|
8
|
+
|
|
9
|
+
file(GLOB SOURCES "*.cpp")
|
|
10
|
+
|
|
11
|
+
pybind11_add_module(solvermodule ${SOURCES})
|
|
12
|
+
|
|
13
|
+
set_target_properties(solvermodule PROPERTIES CXX_STANDARD 14 CXX_STANDARD_REQUIRED ON)
|
|
14
|
+
|
|
15
|
+
# Find OpenMP package
|
|
16
|
+
find_package(OpenMP)
|
|
17
|
+
if(OpenMP_CXX_FOUND)
|
|
18
|
+
# Set compiler options for LLVM OpenMP
|
|
19
|
+
target_compile_options(solvermodule PRIVATE "$<$<CXX_COMPILER_ID:MSVC>:/openmp:llvm>")
|
|
20
|
+
# Link OpenMP flags to the target
|
|
21
|
+
target_link_libraries(solvermodule PUBLIC OpenMP::OpenMP_CXX)
|
|
22
|
+
endif()
|
|
23
|
+
|
|
24
|
+
# Install the compiled extension into the mdpsolver package directory of the wheel.
|
|
25
|
+
install(TARGETS solvermodule DESTINATION mdpsolver)
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2026 Anders Reenberg Andersen and Jesper Fink Andersen
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
* copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
* SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
#include "GeneralMDPmodel.h"
|
|
26
|
+
#include <limits>
|
|
27
|
+
|
|
28
|
+
GeneralMDPmodel::GeneralMDPmodel(Rewards * rw, TransitionMatrix * tm, double discount):
|
|
29
|
+
rewards(rw),
|
|
30
|
+
tranMat(tm),
|
|
31
|
+
discount(discount)
|
|
32
|
+
{
|
|
33
|
+
initialize();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
GeneralMDPmodel::GeneralMDPmodel(const GeneralMDPmodel& orig) {
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
GeneralMDPmodel::~GeneralMDPmodel() {
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
void GeneralMDPmodel::initialize(){
|
|
44
|
+
tranMat->fillTables(csr);
|
|
45
|
+
numberOfStates=csr.numberOfStates;
|
|
46
|
+
cidx=0;
|
|
47
|
+
|
|
48
|
+
//The tables need one reward per pair of the transition probabilities. In a well-formed
|
|
49
|
+
//model the rewards have the same numbers of actions, and so the same numbering, and
|
|
50
|
+
//their array is used as it is. Otherwise (which checkModel() reports) a copy numbered
|
|
51
|
+
//like the pairs is made, so that the solver reads no memory outside the rewards.
|
|
52
|
+
bool aligned = rewards->numberOfRows() >= numberOfStates;
|
|
53
|
+
for (int sidx=0; aligned && sidx<numberOfStates; sidx++){
|
|
54
|
+
aligned = rewards->numberOfActions(sidx) == tranMat->numberOfActions(sidx);
|
|
55
|
+
}
|
|
56
|
+
if (aligned){
|
|
57
|
+
csr.reward = rewards->data();
|
|
58
|
+
}else{
|
|
59
|
+
alignedRewards.assign(csr.stateStart[numberOfStates], numeric_limits<double>::quiet_NaN());
|
|
60
|
+
for (int sidx=0; sidx<numberOfStates && sidx<rewards->numberOfRows(); sidx++){
|
|
61
|
+
for (int aidx=0; aidx<tranMat->numberOfActions(sidx) && aidx<rewards->numberOfActions(sidx); aidx++){
|
|
62
|
+
alignedRewards[pair(sidx,aidx)] = rewards->getReward(sidx,aidx);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
csr.reward = alignedRewards.data();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
double GeneralMDPmodel::reward(int &sidx, int &aidx){
|
|
70
|
+
//calculates and returns the reward of taking action
|
|
71
|
+
//aidx when in current state sidx
|
|
72
|
+
|
|
73
|
+
return csr.reward[pair(sidx,aidx)];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
double GeneralMDPmodel::transProb(int &sidx, int &aidx, int &jidx){
|
|
77
|
+
//returns the jidx-th non-zero transition probability of taking
|
|
78
|
+
//action aidx in state sidx (jidx counts the non-zero probabilities)
|
|
79
|
+
|
|
80
|
+
return probability(entry(sidx,aidx,jidx));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
int GeneralMDPmodel::getNumberOfJumps(int &sidx, int &aidx){
|
|
84
|
+
int64_t i = pair(sidx,aidx);
|
|
85
|
+
return (int)(csr.pairStart[i+1] - csr.pairStart[i]);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
void GeneralMDPmodel::updateNextState(int &sidx, int &aidx, int &jidx){
|
|
89
|
+
//updates the next possible state, nextState, and the associated
|
|
90
|
+
//transition probability, psj.
|
|
91
|
+
int nJumps = getNumberOfJumps(sidx,aidx);
|
|
92
|
+
while (csr.column[entry(sidx,aidx,cidx)]!=jidx){ //this will in many cases immediately evaluate to False
|
|
93
|
+
cidx++;
|
|
94
|
+
if (cidx==nJumps){ //to make sure cidx is always feasible
|
|
95
|
+
cidx=0;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
cidx++; //move one additional step
|
|
99
|
+
if (cidx==nJumps){
|
|
100
|
+
cidx=0;
|
|
101
|
+
}
|
|
102
|
+
nextState = csr.column[entry(sidx,aidx,cidx)];
|
|
103
|
+
psj = probability(entry(sidx,aidx,cidx));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
int GeneralMDPmodel::getColumnIdx(int &sidx, int &aidx, int &cidx){
|
|
107
|
+
return csr.column[entry(sidx,aidx,cidx)];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
int GeneralMDPmodel::postDecisionIdx(int &sidx, int &aidx){
|
|
111
|
+
//derives the first new/next state that is possible
|
|
112
|
+
//to reach from the current state sidx.
|
|
113
|
+
//both returns the value of the first new state, and
|
|
114
|
+
//stores it in the variable nextState.
|
|
115
|
+
cidx=0;
|
|
116
|
+
nextState = csr.column[entry(sidx,aidx,cidx)];
|
|
117
|
+
return nextState;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
double GeneralMDPmodel::getDiscount(){
|
|
121
|
+
return discount;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
int GeneralMDPmodel::getNumberOfStates(){
|
|
125
|
+
return numberOfStates;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
void GeneralMDPmodel::updateNumberOfActions(int &sidx){
|
|
129
|
+
numberOfActions=(int)(csr.stateStart[sidx+1] - csr.stateStart[sidx]);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
int GeneralMDPmodel::getNumberOfActions(){
|
|
133
|
+
return numberOfActions;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
int GeneralMDPmodel::getNumberOfActions(int &sidx){
|
|
137
|
+
return (int)(csr.stateStart[sidx+1] - csr.stateStart[sidx]);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
int * GeneralMDPmodel::getNextState(){
|
|
141
|
+
return &nextState;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
double GeneralMDPmodel::getPsj(){
|
|
145
|
+
return psj;
|
|
146
|
+
}
|