diff --git a/resources/3rdparty/CMakeLists.txt b/resources/3rdparty/CMakeLists.txt index d1da5f3dfe..c3d34fa354 100644 --- a/resources/3rdparty/CMakeLists.txt +++ b/resources/3rdparty/CMakeLists.txt @@ -294,7 +294,7 @@ include(${STORM_3RDPARTY_SOURCE_DIR}/include_cudd.cmake) ############################################################# set(STORM_HAVE_CARL OFF) -set(CARL_MINVERSION "14.23") +set(CARL_MINVERSION "14.26") set(CARL_C14VERSION "14") if (NOT STORM_FORCE_SHIPPED_CARL) if (NOT "${STORM_CARL_DIR_HINT}" STREQUAL "") diff --git a/resources/examples/testfiles/idtmc/brp-16-2.drn b/resources/examples/testfiles/idtmc/brp-16-2.drn new file mode 100644 index 0000000000..23816c779d --- /dev/null +++ b/resources/examples/testfiles/idtmc/brp-16-2.drn @@ -0,0 +1,2041 @@ +// Exported by storm +// Original model type: DTMC +@type: DTMC +@parameters + +@reward_models + +@nr_states +613 +@nr_choices +613 +@model +state 0 init + action 0 + 1 : [1, 1] +state 1 + action 0 + 2 : [0.97, 0.99] + 3 : [0.01, 0.03] +state 2 + action 0 + 4 : [1, 1] +state 3 + action 0 + 5 : [1, 1] +state 4 + action 0 + 6 : [1, 1] +state 5 + action 0 + 7 : [0.97, 0.99] + 8 : [0.01, 0.03] +state 6 + action 0 + 9 : [1, 1] +state 7 + action 0 + 10 : [1, 1] +state 8 + action 0 + 11 : [1, 1] +state 9 + action 0 + 12 : [0.98, 1] + 13 : [0.0001, 0.02] +state 10 + action 0 + 14 : [1, 1] +state 11 + action 0 + 15 : [0.97, 0.99] + 16 : [0.01, 0.03] +state 12 + action 0 + 17 : [1, 1] +state 13 + action 0 + 18 : [1, 1] +state 14 + action 0 + 19 : [1, 1] +state 15 + action 0 + 20 : [1, 1] +state 16 + action 0 + 21 : [1, 1] +state 17 + action 0 + 22 : [1, 1] +state 18 + action 0 + 23 : [0.97, 0.99] + 24 : [0.01, 0.03] +state 19 + action 0 + 25 : [0.98, 1] + 26 : [0.0001, 0.02] +state 20 + action 0 + 27 : [1, 1] +state 21 + action 0 + 28 : [1, 1] +state 22 + action 0 + 29 : [0.97, 0.99] + 30 : [0.01, 0.03] +state 23 + action 0 + 31 : [1, 1] +state 24 + action 0 + 32 : [1, 1] +state 25 + action 0 + 33 : [1, 1] +state 26 + action 0 + 32 : [1, 1] +state 27 + action 0 + 34 : [1, 1] +state 28 target + action 0 + 28 : [1, 1] +state 29 + action 0 + 35 : [1, 1] +state 30 + action 0 + 36 : [1, 1] +state 31 + action 0 + 25 : [0.98, 1] + 26 : [0.0001, 0.02] +state 32 + action 0 + 37 : [0.97, 0.99] + 38 : [0.01, 0.03] +state 33 + action 0 + 39 : [1, 1] +state 34 + action 0 + 40 : [0.98, 1] + 41 : [0.0001, 0.02] +state 35 + action 0 + 42 : [1, 1] +state 36 + action 0 + 43 : [0.97, 0.99] + 44 : [0.01, 0.03] +state 37 + action 0 + 45 : [1, 1] +state 38 + action 0 + 46 : [1, 1] +state 39 + action 0 + 29 : [0.97, 0.99] + 30 : [0.01, 0.03] +state 40 + action 0 + 47 : [1, 1] +state 41 + action 0 + 46 : [1, 1] +state 42 + action 0 + 48 : [0.98, 1] + 49 : [0.0001, 0.02] +state 43 + action 0 + 50 : [1, 1] +state 44 + action 0 + 51 : [1, 1] +state 45 + action 0 + 40 : [0.98, 1] + 41 : [0.0001, 0.02] +state 46 + action 0 + 52 : [1, 1] +state 47 + action 0 + 53 : [1, 1] +state 48 + action 0 + 54 : [1, 1] +state 49 + action 0 + 55 : [1, 1] +state 50 + action 0 + 56 : [1, 1] +state 51 + action 0 + 57 : [0.97, 0.99] + 58 : [0.01, 0.03] +state 52 target + action 0 + 52 : [1, 1] +state 53 + action 0 + 29 : [0.97, 0.99] + 30 : [0.01, 0.03] +state 54 + action 0 + 59 : [1, 1] +state 55 + action 0 + 60 : [0.97, 0.99] + 61 : [0.01, 0.03] +state 56 + action 0 + 62 : [0.98, 1] + 63 : [0.0001, 0.02] +state 57 + action 0 + 64 : [1, 1] +state 58 + action 0 + 65 : [1, 1] +state 59 + action 0 + 66 : [0.97, 0.99] + 67 : [0.01, 0.03] +state 60 + action 0 + 68 : [1, 1] +state 61 + action 0 + 69 : [1, 1] +state 62 + action 0 + 70 : [1, 1] +state 63 + action 0 + 69 : [1, 1] +state 64 + action 0 + 71 : [1, 1] +state 65 + action 0 + 72 : [1, 1] +state 66 + action 0 + 73 : [1, 1] +state 67 + action 0 + 74 : [1, 1] +state 68 + action 0 + 62 : [0.98, 1] + 63 : [0.0001, 0.02] +state 69 + action 0 + 75 : [0.97, 0.99] + 76 : [0.01, 0.03] +state 70 + action 0 + 77 : [1, 1] +state 71 + action 0 + 78 : [0.98, 1] + 79 : [0.0001, 0.02] +state 72 target + action 0 + 72 : [1, 1] +state 73 + action 0 + 80 : [1, 1] +state 74 + action 0 + 81 : [0.97, 0.99] + 82 : [0.01, 0.03] +state 75 + action 0 + 83 : [1, 1] +state 76 + action 0 + 84 : [1, 1] +state 77 + action 0 + 66 : [0.97, 0.99] + 67 : [0.01, 0.03] +state 78 + action 0 + 85 : [1, 1] +state 79 + action 0 + 84 : [1, 1] +state 80 + action 0 + 86 : [0.98, 1] + 87 : [0.0001, 0.02] +state 81 + action 0 + 88 : [1, 1] +state 82 + action 0 + 89 : [1, 1] +state 83 + action 0 + 78 : [0.98, 1] + 79 : [0.0001, 0.02] +state 84 + action 0 + 90 : [1, 1] +state 85 + action 0 + 91 : [1, 1] +state 86 + action 0 + 92 : [1, 1] +state 87 + action 0 + 93 : [1, 1] +state 88 + action 0 + 94 : [1, 1] +state 89 + action 0 + 95 : [0.97, 0.99] + 96 : [0.01, 0.03] +state 90 target + action 0 + 90 : [1, 1] +state 91 + action 0 + 66 : [0.97, 0.99] + 67 : [0.01, 0.03] +state 92 + action 0 + 97 : [1, 1] +state 93 + action 0 + 98 : [0.97, 0.99] + 99 : [0.01, 0.03] +state 94 + action 0 + 100 : [0.98, 1] + 101 : [0.0001, 0.02] +state 95 + action 0 + 102 : [1, 1] +state 96 + action 0 + 103 : [1, 1] +state 97 + action 0 + 104 : [0.97, 0.99] + 105 : [0.01, 0.03] +state 98 + action 0 + 106 : [1, 1] +state 99 + action 0 + 107 : [1, 1] +state 100 + action 0 + 108 : [1, 1] +state 101 + action 0 + 107 : [1, 1] +state 102 + action 0 + 109 : [1, 1] +state 103 + action 0 + 110 : [1, 1] +state 104 + action 0 + 111 : [1, 1] +state 105 + action 0 + 112 : [1, 1] +state 106 + action 0 + 100 : [0.98, 1] + 101 : [0.0001, 0.02] +state 107 + action 0 + 113 : [0.97, 0.99] + 114 : [0.01, 0.03] +state 108 + action 0 + 115 : [1, 1] +state 109 + action 0 + 116 : [0.98, 1] + 117 : [0.0001, 0.02] +state 110 target + action 0 + 110 : [1, 1] +state 111 + action 0 + 118 : [1, 1] +state 112 + action 0 + 119 : [0.97, 0.99] + 120 : [0.01, 0.03] +state 113 + action 0 + 121 : [1, 1] +state 114 + action 0 + 122 : [1, 1] +state 115 + action 0 + 104 : [0.97, 0.99] + 105 : [0.01, 0.03] +state 116 + action 0 + 123 : [1, 1] +state 117 + action 0 + 122 : [1, 1] +state 118 + action 0 + 124 : [0.98, 1] + 125 : [0.0001, 0.02] +state 119 + action 0 + 126 : [1, 1] +state 120 + action 0 + 127 : [1, 1] +state 121 + action 0 + 116 : [0.98, 1] + 117 : [0.0001, 0.02] +state 122 + action 0 + 128 : [1, 1] +state 123 + action 0 + 129 : [1, 1] +state 124 + action 0 + 130 : [1, 1] +state 125 + action 0 + 131 : [1, 1] +state 126 + action 0 + 132 : [1, 1] +state 127 + action 0 + 133 : [0.97, 0.99] + 134 : [0.01, 0.03] +state 128 target + action 0 + 128 : [1, 1] +state 129 + action 0 + 104 : [0.97, 0.99] + 105 : [0.01, 0.03] +state 130 + action 0 + 135 : [1, 1] +state 131 + action 0 + 136 : [0.97, 0.99] + 137 : [0.01, 0.03] +state 132 + action 0 + 138 : [0.98, 1] + 139 : [0.0001, 0.02] +state 133 + action 0 + 140 : [1, 1] +state 134 + action 0 + 141 : [1, 1] +state 135 + action 0 + 142 : [0.97, 0.99] + 143 : [0.01, 0.03] +state 136 + action 0 + 144 : [1, 1] +state 137 + action 0 + 145 : [1, 1] +state 138 + action 0 + 146 : [1, 1] +state 139 + action 0 + 145 : [1, 1] +state 140 + action 0 + 147 : [1, 1] +state 141 + action 0 + 148 : [1, 1] +state 142 + action 0 + 149 : [1, 1] +state 143 + action 0 + 150 : [1, 1] +state 144 + action 0 + 138 : [0.98, 1] + 139 : [0.0001, 0.02] +state 145 + action 0 + 151 : [0.97, 0.99] + 152 : [0.01, 0.03] +state 146 + action 0 + 153 : [1, 1] +state 147 + action 0 + 154 : [0.98, 1] + 155 : [0.0001, 0.02] +state 148 target + action 0 + 148 : [1, 1] +state 149 + action 0 + 156 : [1, 1] +state 150 + action 0 + 157 : [0.97, 0.99] + 158 : [0.01, 0.03] +state 151 + action 0 + 159 : [1, 1] +state 152 + action 0 + 160 : [1, 1] +state 153 + action 0 + 142 : [0.97, 0.99] + 143 : [0.01, 0.03] +state 154 + action 0 + 161 : [1, 1] +state 155 + action 0 + 160 : [1, 1] +state 156 + action 0 + 162 : [0.98, 1] + 163 : [0.0001, 0.02] +state 157 + action 0 + 164 : [1, 1] +state 158 + action 0 + 165 : [1, 1] +state 159 + action 0 + 154 : [0.98, 1] + 155 : [0.0001, 0.02] +state 160 + action 0 + 166 : [1, 1] +state 161 + action 0 + 167 : [1, 1] +state 162 + action 0 + 168 : [1, 1] +state 163 + action 0 + 169 : [1, 1] +state 164 + action 0 + 170 : [1, 1] +state 165 + action 0 + 171 : [0.97, 0.99] + 172 : [0.01, 0.03] +state 166 target + action 0 + 166 : [1, 1] +state 167 + action 0 + 142 : [0.97, 0.99] + 143 : [0.01, 0.03] +state 168 + action 0 + 173 : [1, 1] +state 169 + action 0 + 174 : [0.97, 0.99] + 175 : [0.01, 0.03] +state 170 + action 0 + 176 : [0.98, 1] + 177 : [0.0001, 0.02] +state 171 + action 0 + 178 : [1, 1] +state 172 + action 0 + 179 : [1, 1] +state 173 + action 0 + 180 : [0.97, 0.99] + 181 : [0.01, 0.03] +state 174 + action 0 + 182 : [1, 1] +state 175 + action 0 + 183 : [1, 1] +state 176 + action 0 + 184 : [1, 1] +state 177 + action 0 + 183 : [1, 1] +state 178 + action 0 + 185 : [1, 1] +state 179 + action 0 + 186 : [1, 1] +state 180 + action 0 + 187 : [1, 1] +state 181 + action 0 + 188 : [1, 1] +state 182 + action 0 + 176 : [0.98, 1] + 177 : [0.0001, 0.02] +state 183 + action 0 + 189 : [0.97, 0.99] + 190 : [0.01, 0.03] +state 184 + action 0 + 191 : [1, 1] +state 185 + action 0 + 192 : [0.98, 1] + 193 : [0.0001, 0.02] +state 186 target + action 0 + 186 : [1, 1] +state 187 + action 0 + 194 : [1, 1] +state 188 + action 0 + 195 : [0.97, 0.99] + 196 : [0.01, 0.03] +state 189 + action 0 + 197 : [1, 1] +state 190 + action 0 + 198 : [1, 1] +state 191 + action 0 + 180 : [0.97, 0.99] + 181 : [0.01, 0.03] +state 192 + action 0 + 199 : [1, 1] +state 193 + action 0 + 198 : [1, 1] +state 194 + action 0 + 200 : [0.98, 1] + 201 : [0.0001, 0.02] +state 195 + action 0 + 202 : [1, 1] +state 196 + action 0 + 203 : [1, 1] +state 197 + action 0 + 192 : [0.98, 1] + 193 : [0.0001, 0.02] +state 198 + action 0 + 204 : [1, 1] +state 199 + action 0 + 205 : [1, 1] +state 200 + action 0 + 206 : [1, 1] +state 201 + action 0 + 207 : [1, 1] +state 202 + action 0 + 208 : [1, 1] +state 203 + action 0 + 209 : [0.97, 0.99] + 210 : [0.01, 0.03] +state 204 target + action 0 + 204 : [1, 1] +state 205 + action 0 + 180 : [0.97, 0.99] + 181 : [0.01, 0.03] +state 206 + action 0 + 211 : [1, 1] +state 207 + action 0 + 212 : [0.97, 0.99] + 213 : [0.01, 0.03] +state 208 + action 0 + 214 : [0.98, 1] + 215 : [0.0001, 0.02] +state 209 + action 0 + 216 : [1, 1] +state 210 + action 0 + 217 : [1, 1] +state 211 + action 0 + 218 : [0.97, 0.99] + 219 : [0.01, 0.03] +state 212 + action 0 + 220 : [1, 1] +state 213 + action 0 + 221 : [1, 1] +state 214 + action 0 + 222 : [1, 1] +state 215 + action 0 + 221 : [1, 1] +state 216 + action 0 + 223 : [1, 1] +state 217 + action 0 + 224 : [1, 1] +state 218 + action 0 + 225 : [1, 1] +state 219 + action 0 + 226 : [1, 1] +state 220 + action 0 + 214 : [0.98, 1] + 215 : [0.0001, 0.02] +state 221 + action 0 + 227 : [0.97, 0.99] + 228 : [0.01, 0.03] +state 222 + action 0 + 229 : [1, 1] +state 223 + action 0 + 230 : [0.98, 1] + 231 : [0.0001, 0.02] +state 224 target + action 0 + 224 : [1, 1] +state 225 + action 0 + 232 : [1, 1] +state 226 + action 0 + 233 : [0.97, 0.99] + 234 : [0.01, 0.03] +state 227 + action 0 + 235 : [1, 1] +state 228 + action 0 + 236 : [1, 1] +state 229 + action 0 + 218 : [0.97, 0.99] + 219 : [0.01, 0.03] +state 230 + action 0 + 237 : [1, 1] +state 231 + action 0 + 236 : [1, 1] +state 232 + action 0 + 238 : [0.98, 1] + 239 : [0.0001, 0.02] +state 233 + action 0 + 240 : [1, 1] +state 234 + action 0 + 241 : [1, 1] +state 235 + action 0 + 230 : [0.98, 1] + 231 : [0.0001, 0.02] +state 236 + action 0 + 242 : [1, 1] +state 237 + action 0 + 243 : [1, 1] +state 238 + action 0 + 244 : [1, 1] +state 239 + action 0 + 245 : [1, 1] +state 240 + action 0 + 246 : [1, 1] +state 241 + action 0 + 247 : [0.97, 0.99] + 248 : [0.01, 0.03] +state 242 target + action 0 + 242 : [1, 1] +state 243 + action 0 + 218 : [0.97, 0.99] + 219 : [0.01, 0.03] +state 244 + action 0 + 249 : [1, 1] +state 245 + action 0 + 250 : [0.97, 0.99] + 251 : [0.01, 0.03] +state 246 + action 0 + 252 : [0.98, 1] + 253 : [0.0001, 0.02] +state 247 + action 0 + 254 : [1, 1] +state 248 + action 0 + 255 : [1, 1] +state 249 + action 0 + 256 : [0.97, 0.99] + 257 : [0.01, 0.03] +state 250 + action 0 + 258 : [1, 1] +state 251 + action 0 + 259 : [1, 1] +state 252 + action 0 + 260 : [1, 1] +state 253 + action 0 + 259 : [1, 1] +state 254 + action 0 + 261 : [1, 1] +state 255 + action 0 + 262 : [1, 1] +state 256 + action 0 + 263 : [1, 1] +state 257 + action 0 + 264 : [1, 1] +state 258 + action 0 + 252 : [0.98, 1] + 253 : [0.0001, 0.02] +state 259 + action 0 + 265 : [0.97, 0.99] + 266 : [0.01, 0.03] +state 260 + action 0 + 267 : [1, 1] +state 261 + action 0 + 268 : [0.98, 1] + 269 : [0.0001, 0.02] +state 262 target + action 0 + 262 : [1, 1] +state 263 + action 0 + 270 : [1, 1] +state 264 + action 0 + 271 : [0.97, 0.99] + 272 : [0.01, 0.03] +state 265 + action 0 + 273 : [1, 1] +state 266 + action 0 + 274 : [1, 1] +state 267 + action 0 + 256 : [0.97, 0.99] + 257 : [0.01, 0.03] +state 268 + action 0 + 275 : [1, 1] +state 269 + action 0 + 274 : [1, 1] +state 270 + action 0 + 276 : [0.98, 1] + 277 : [0.0001, 0.02] +state 271 + action 0 + 278 : [1, 1] +state 272 + action 0 + 279 : [1, 1] +state 273 + action 0 + 268 : [0.98, 1] + 269 : [0.0001, 0.02] +state 274 + action 0 + 280 : [1, 1] +state 275 + action 0 + 281 : [1, 1] +state 276 + action 0 + 282 : [1, 1] +state 277 + action 0 + 283 : [1, 1] +state 278 + action 0 + 284 : [1, 1] +state 279 + action 0 + 285 : [0.97, 0.99] + 286 : [0.01, 0.03] +state 280 target + action 0 + 280 : [1, 1] +state 281 + action 0 + 256 : [0.97, 0.99] + 257 : [0.01, 0.03] +state 282 + action 0 + 287 : [1, 1] +state 283 + action 0 + 288 : [0.97, 0.99] + 289 : [0.01, 0.03] +state 284 + action 0 + 290 : [0.98, 1] + 291 : [0.0001, 0.02] +state 285 + action 0 + 292 : [1, 1] +state 286 + action 0 + 293 : [1, 1] +state 287 + action 0 + 294 : [0.97, 0.99] + 295 : [0.01, 0.03] +state 288 + action 0 + 296 : [1, 1] +state 289 + action 0 + 297 : [1, 1] +state 290 + action 0 + 298 : [1, 1] +state 291 + action 0 + 297 : [1, 1] +state 292 + action 0 + 299 : [1, 1] +state 293 + action 0 + 300 : [1, 1] +state 294 + action 0 + 301 : [1, 1] +state 295 + action 0 + 302 : [1, 1] +state 296 + action 0 + 290 : [0.98, 1] + 291 : [0.0001, 0.02] +state 297 + action 0 + 303 : [0.97, 0.99] + 304 : [0.01, 0.03] +state 298 + action 0 + 305 : [1, 1] +state 299 + action 0 + 306 : [0.98, 1] + 307 : [0.0001, 0.02] +state 300 target + action 0 + 300 : [1, 1] +state 301 + action 0 + 308 : [1, 1] +state 302 + action 0 + 309 : [0.97, 0.99] + 310 : [0.01, 0.03] +state 303 + action 0 + 311 : [1, 1] +state 304 + action 0 + 312 : [1, 1] +state 305 + action 0 + 294 : [0.97, 0.99] + 295 : [0.01, 0.03] +state 306 + action 0 + 313 : [1, 1] +state 307 + action 0 + 312 : [1, 1] +state 308 + action 0 + 314 : [0.98, 1] + 315 : [0.0001, 0.02] +state 309 + action 0 + 316 : [1, 1] +state 310 + action 0 + 317 : [1, 1] +state 311 + action 0 + 306 : [0.98, 1] + 307 : [0.0001, 0.02] +state 312 + action 0 + 318 : [1, 1] +state 313 + action 0 + 319 : [1, 1] +state 314 + action 0 + 320 : [1, 1] +state 315 + action 0 + 321 : [1, 1] +state 316 + action 0 + 322 : [1, 1] +state 317 + action 0 + 323 : [0.97, 0.99] + 324 : [0.01, 0.03] +state 318 target + action 0 + 318 : [1, 1] +state 319 + action 0 + 294 : [0.97, 0.99] + 295 : [0.01, 0.03] +state 320 + action 0 + 325 : [1, 1] +state 321 + action 0 + 326 : [0.97, 0.99] + 327 : [0.01, 0.03] +state 322 + action 0 + 328 : [0.98, 1] + 329 : [0.0001, 0.02] +state 323 + action 0 + 330 : [1, 1] +state 324 + action 0 + 331 : [1, 1] +state 325 + action 0 + 332 : [0.97, 0.99] + 333 : [0.01, 0.03] +state 326 + action 0 + 334 : [1, 1] +state 327 + action 0 + 335 : [1, 1] +state 328 + action 0 + 336 : [1, 1] +state 329 + action 0 + 335 : [1, 1] +state 330 + action 0 + 337 : [1, 1] +state 331 + action 0 + 338 : [1, 1] +state 332 + action 0 + 339 : [1, 1] +state 333 + action 0 + 340 : [1, 1] +state 334 + action 0 + 328 : [0.98, 1] + 329 : [0.0001, 0.02] +state 335 + action 0 + 341 : [0.97, 0.99] + 342 : [0.01, 0.03] +state 336 + action 0 + 343 : [1, 1] +state 337 + action 0 + 344 : [0.98, 1] + 345 : [0.0001, 0.02] +state 338 target + action 0 + 338 : [1, 1] +state 339 + action 0 + 346 : [1, 1] +state 340 + action 0 + 347 : [0.97, 0.99] + 348 : [0.01, 0.03] +state 341 + action 0 + 349 : [1, 1] +state 342 + action 0 + 350 : [1, 1] +state 343 + action 0 + 332 : [0.97, 0.99] + 333 : [0.01, 0.03] +state 344 + action 0 + 351 : [1, 1] +state 345 + action 0 + 350 : [1, 1] +state 346 + action 0 + 352 : [0.98, 1] + 353 : [0.0001, 0.02] +state 347 + action 0 + 354 : [1, 1] +state 348 + action 0 + 355 : [1, 1] +state 349 + action 0 + 344 : [0.98, 1] + 345 : [0.0001, 0.02] +state 350 + action 0 + 356 : [1, 1] +state 351 + action 0 + 357 : [1, 1] +state 352 + action 0 + 358 : [1, 1] +state 353 + action 0 + 359 : [1, 1] +state 354 + action 0 + 360 : [1, 1] +state 355 + action 0 + 361 : [0.97, 0.99] + 362 : [0.01, 0.03] +state 356 target + action 0 + 356 : [1, 1] +state 357 + action 0 + 332 : [0.97, 0.99] + 333 : [0.01, 0.03] +state 358 + action 0 + 363 : [1, 1] +state 359 + action 0 + 364 : [0.97, 0.99] + 365 : [0.01, 0.03] +state 360 + action 0 + 366 : [0.98, 1] + 367 : [0.0001, 0.02] +state 361 + action 0 + 368 : [1, 1] +state 362 + action 0 + 369 : [1, 1] +state 363 + action 0 + 370 : [0.97, 0.99] + 371 : [0.01, 0.03] +state 364 + action 0 + 372 : [1, 1] +state 365 + action 0 + 373 : [1, 1] +state 366 + action 0 + 374 : [1, 1] +state 367 + action 0 + 373 : [1, 1] +state 368 + action 0 + 375 : [1, 1] +state 369 + action 0 + 376 : [1, 1] +state 370 + action 0 + 377 : [1, 1] +state 371 + action 0 + 378 : [1, 1] +state 372 + action 0 + 366 : [0.98, 1] + 367 : [0.0001, 0.02] +state 373 + action 0 + 379 : [0.97, 0.99] + 380 : [0.01, 0.03] +state 374 + action 0 + 381 : [1, 1] +state 375 + action 0 + 382 : [0.98, 1] + 383 : [0.0001, 0.02] +state 376 target + action 0 + 376 : [1, 1] +state 377 + action 0 + 384 : [1, 1] +state 378 + action 0 + 385 : [0.97, 0.99] + 386 : [0.01, 0.03] +state 379 + action 0 + 387 : [1, 1] +state 380 + action 0 + 388 : [1, 1] +state 381 + action 0 + 370 : [0.97, 0.99] + 371 : [0.01, 0.03] +state 382 + action 0 + 389 : [1, 1] +state 383 + action 0 + 388 : [1, 1] +state 384 + action 0 + 390 : [0.98, 1] + 391 : [0.0001, 0.02] +state 385 + action 0 + 392 : [1, 1] +state 386 + action 0 + 393 : [1, 1] +state 387 + action 0 + 382 : [0.98, 1] + 383 : [0.0001, 0.02] +state 388 + action 0 + 394 : [1, 1] +state 389 + action 0 + 395 : [1, 1] +state 390 + action 0 + 396 : [1, 1] +state 391 + action 0 + 397 : [1, 1] +state 392 + action 0 + 398 : [1, 1] +state 393 + action 0 + 399 : [0.97, 0.99] + 400 : [0.01, 0.03] +state 394 target + action 0 + 394 : [1, 1] +state 395 + action 0 + 370 : [0.97, 0.99] + 371 : [0.01, 0.03] +state 396 + action 0 + 401 : [1, 1] +state 397 + action 0 + 402 : [0.97, 0.99] + 403 : [0.01, 0.03] +state 398 + action 0 + 404 : [0.98, 1] + 405 : [0.0001, 0.02] +state 399 + action 0 + 406 : [1, 1] +state 400 + action 0 + 407 : [1, 1] +state 401 + action 0 + 408 : [0.97, 0.99] + 409 : [0.01, 0.03] +state 402 + action 0 + 410 : [1, 1] +state 403 + action 0 + 411 : [1, 1] +state 404 + action 0 + 412 : [1, 1] +state 405 + action 0 + 411 : [1, 1] +state 406 + action 0 + 413 : [1, 1] +state 407 + action 0 + 414 : [1, 1] +state 408 + action 0 + 415 : [1, 1] +state 409 + action 0 + 416 : [1, 1] +state 410 + action 0 + 404 : [0.98, 1] + 405 : [0.0001, 0.02] +state 411 + action 0 + 417 : [0.97, 0.99] + 418 : [0.01, 0.03] +state 412 + action 0 + 419 : [1, 1] +state 413 + action 0 + 420 : [0.98, 1] + 421 : [0.0001, 0.02] +state 414 target + action 0 + 414 : [1, 1] +state 415 + action 0 + 422 : [1, 1] +state 416 + action 0 + 423 : [0.97, 0.99] + 424 : [0.01, 0.03] +state 417 + action 0 + 425 : [1, 1] +state 418 + action 0 + 426 : [1, 1] +state 419 + action 0 + 408 : [0.97, 0.99] + 409 : [0.01, 0.03] +state 420 + action 0 + 427 : [1, 1] +state 421 + action 0 + 426 : [1, 1] +state 422 + action 0 + 428 : [0.98, 1] + 429 : [0.0001, 0.02] +state 423 + action 0 + 430 : [1, 1] +state 424 + action 0 + 431 : [1, 1] +state 425 + action 0 + 420 : [0.98, 1] + 421 : [0.0001, 0.02] +state 426 + action 0 + 432 : [1, 1] +state 427 + action 0 + 433 : [1, 1] +state 428 + action 0 + 434 : [1, 1] +state 429 + action 0 + 435 : [1, 1] +state 430 + action 0 + 436 : [1, 1] +state 431 + action 0 + 437 : [0.97, 0.99] + 438 : [0.01, 0.03] +state 432 target + action 0 + 432 : [1, 1] +state 433 + action 0 + 408 : [0.97, 0.99] + 409 : [0.01, 0.03] +state 434 + action 0 + 439 : [1, 1] +state 435 + action 0 + 440 : [0.97, 0.99] + 441 : [0.01, 0.03] +state 436 + action 0 + 442 : [0.98, 1] + 443 : [0.0001, 0.02] +state 437 + action 0 + 444 : [1, 1] +state 438 + action 0 + 445 : [1, 1] +state 439 + action 0 + 446 : [0.97, 0.99] + 447 : [0.01, 0.03] +state 440 + action 0 + 448 : [1, 1] +state 441 + action 0 + 449 : [1, 1] +state 442 + action 0 + 450 : [1, 1] +state 443 + action 0 + 449 : [1, 1] +state 444 + action 0 + 451 : [1, 1] +state 445 + action 0 + 452 : [1, 1] +state 446 + action 0 + 453 : [1, 1] +state 447 + action 0 + 454 : [1, 1] +state 448 + action 0 + 442 : [0.98, 1] + 443 : [0.0001, 0.02] +state 449 + action 0 + 455 : [0.97, 0.99] + 456 : [0.01, 0.03] +state 450 + action 0 + 457 : [1, 1] +state 451 + action 0 + 458 : [0.98, 1] + 459 : [0.0001, 0.02] +state 452 target + action 0 + 452 : [1, 1] +state 453 + action 0 + 460 : [1, 1] +state 454 + action 0 + 461 : [0.97, 0.99] + 462 : [0.01, 0.03] +state 455 + action 0 + 463 : [1, 1] +state 456 + action 0 + 464 : [1, 1] +state 457 + action 0 + 446 : [0.97, 0.99] + 447 : [0.01, 0.03] +state 458 + action 0 + 465 : [1, 1] +state 459 + action 0 + 464 : [1, 1] +state 460 + action 0 + 466 : [0.98, 1] + 467 : [0.0001, 0.02] +state 461 + action 0 + 468 : [1, 1] +state 462 + action 0 + 469 : [1, 1] +state 463 + action 0 + 458 : [0.98, 1] + 459 : [0.0001, 0.02] +state 464 + action 0 + 470 : [1, 1] +state 465 + action 0 + 471 : [1, 1] +state 466 + action 0 + 472 : [1, 1] +state 467 + action 0 + 473 : [1, 1] +state 468 + action 0 + 474 : [1, 1] +state 469 + action 0 + 475 : [0.97, 0.99] + 476 : [0.01, 0.03] +state 470 target + action 0 + 470 : [1, 1] +state 471 + action 0 + 446 : [0.97, 0.99] + 447 : [0.01, 0.03] +state 472 + action 0 + 477 : [1, 1] +state 473 + action 0 + 478 : [0.97, 0.99] + 479 : [0.01, 0.03] +state 474 + action 0 + 480 : [0.98, 1] + 481 : [0.0001, 0.02] +state 475 + action 0 + 482 : [1, 1] +state 476 + action 0 + 483 : [1, 1] +state 477 + action 0 + 484 : [0.97, 0.99] + 485 : [0.01, 0.03] +state 478 + action 0 + 486 : [1, 1] +state 479 + action 0 + 487 : [1, 1] +state 480 + action 0 + 488 : [1, 1] +state 481 + action 0 + 487 : [1, 1] +state 482 + action 0 + 489 : [1, 1] +state 483 + action 0 + 490 : [1, 1] +state 484 + action 0 + 491 : [1, 1] +state 485 + action 0 + 492 : [1, 1] +state 486 + action 0 + 480 : [0.98, 1] + 481 : [0.0001, 0.02] +state 487 + action 0 + 493 : [0.97, 0.99] + 494 : [0.01, 0.03] +state 488 + action 0 + 495 : [1, 1] +state 489 + action 0 + 496 : [0.98, 1] + 497 : [0.0001, 0.02] +state 490 target + action 0 + 490 : [1, 1] +state 491 + action 0 + 498 : [1, 1] +state 492 + action 0 + 499 : [0.97, 0.99] + 500 : [0.01, 0.03] +state 493 + action 0 + 501 : [1, 1] +state 494 + action 0 + 502 : [1, 1] +state 495 + action 0 + 484 : [0.97, 0.99] + 485 : [0.01, 0.03] +state 496 + action 0 + 503 : [1, 1] +state 497 + action 0 + 502 : [1, 1] +state 498 + action 0 + 504 : [0.98, 1] + 505 : [0.0001, 0.02] +state 499 + action 0 + 506 : [1, 1] +state 500 + action 0 + 507 : [1, 1] +state 501 + action 0 + 496 : [0.98, 1] + 497 : [0.0001, 0.02] +state 502 + action 0 + 508 : [1, 1] +state 503 + action 0 + 509 : [1, 1] +state 504 + action 0 + 510 : [1, 1] +state 505 + action 0 + 511 : [1, 1] +state 506 + action 0 + 512 : [1, 1] +state 507 + action 0 + 513 : [0.97, 0.99] + 514 : [0.01, 0.03] +state 508 target + action 0 + 508 : [1, 1] +state 509 + action 0 + 484 : [0.97, 0.99] + 485 : [0.01, 0.03] +state 510 + action 0 + 515 : [1, 1] +state 511 + action 0 + 516 : [0.97, 0.99] + 517 : [0.01, 0.03] +state 512 + action 0 + 518 : [0.98, 1] + 519 : [0.0001, 0.02] +state 513 + action 0 + 520 : [1, 1] +state 514 + action 0 + 521 : [1, 1] +state 515 + action 0 + 522 : [0.97, 0.99] + 523 : [0.01, 0.03] +state 516 + action 0 + 524 : [1, 1] +state 517 + action 0 + 525 : [1, 1] +state 518 + action 0 + 526 : [1, 1] +state 519 + action 0 + 525 : [1, 1] +state 520 + action 0 + 527 : [1, 1] +state 521 + action 0 + 528 : [1, 1] +state 522 + action 0 + 529 : [1, 1] +state 523 + action 0 + 530 : [1, 1] +state 524 + action 0 + 518 : [0.98, 1] + 519 : [0.0001, 0.02] +state 525 + action 0 + 531 : [0.97, 0.99] + 532 : [0.01, 0.03] +state 526 + action 0 + 533 : [1, 1] +state 527 + action 0 + 534 : [0.98, 1] + 535 : [0.0001, 0.02] +state 528 target + action 0 + 528 : [1, 1] +state 529 + action 0 + 536 : [1, 1] +state 530 + action 0 + 537 : [0.97, 0.99] + 538 : [0.01, 0.03] +state 531 + action 0 + 539 : [1, 1] +state 532 + action 0 + 540 : [1, 1] +state 533 + action 0 + 522 : [0.97, 0.99] + 523 : [0.01, 0.03] +state 534 + action 0 + 541 : [1, 1] +state 535 + action 0 + 540 : [1, 1] +state 536 + action 0 + 542 : [0.98, 1] + 543 : [0.0001, 0.02] +state 537 + action 0 + 544 : [1, 1] +state 538 + action 0 + 545 : [1, 1] +state 539 + action 0 + 534 : [0.98, 1] + 535 : [0.0001, 0.02] +state 540 + action 0 + 546 : [1, 1] +state 541 + action 0 + 547 : [1, 1] +state 542 + action 0 + 548 : [1, 1] +state 543 + action 0 + 549 : [1, 1] +state 544 + action 0 + 550 : [1, 1] +state 545 + action 0 + 551 : [0.97, 0.99] + 552 : [0.01, 0.03] +state 546 target + action 0 + 546 : [1, 1] +state 547 + action 0 + 522 : [0.97, 0.99] + 523 : [0.01, 0.03] +state 548 + action 0 + 553 : [1, 1] +state 549 + action 0 + 554 : [0.97, 0.99] + 555 : [0.01, 0.03] +state 550 + action 0 + 556 : [0.98, 1] + 557 : [0.0001, 0.02] +state 551 + action 0 + 558 : [1, 1] +state 552 + action 0 + 559 : [1, 1] +state 553 + action 0 + 560 : [0.97, 0.99] + 561 : [0.01, 0.03] +state 554 + action 0 + 562 : [1, 1] +state 555 + action 0 + 563 : [1, 1] +state 556 + action 0 + 564 : [1, 1] +state 557 + action 0 + 563 : [1, 1] +state 558 + action 0 + 565 : [1, 1] +state 559 + action 0 + 566 : [1, 1] +state 560 + action 0 + 567 : [1, 1] +state 561 + action 0 + 568 : [1, 1] +state 562 + action 0 + 556 : [0.98, 1] + 557 : [0.0001, 0.02] +state 563 + action 0 + 569 : [0.97, 0.99] + 570 : [0.01, 0.03] +state 564 + action 0 + 571 : [1, 1] +state 565 + action 0 + 572 : [0.98, 1] + 573 : [0.0001, 0.02] +state 566 target + action 0 + 566 : [1, 1] +state 567 + action 0 + 574 : [1, 1] +state 568 + action 0 + 575 : [0.97, 0.99] + 576 : [0.01, 0.03] +state 569 + action 0 + 577 : [1, 1] +state 570 + action 0 + 578 : [1, 1] +state 571 + action 0 + 560 : [0.97, 0.99] + 561 : [0.01, 0.03] +state 572 + action 0 + 579 : [1, 1] +state 573 + action 0 + 578 : [1, 1] +state 574 + action 0 + 580 : [0.98, 1] + 581 : [0.0001, 0.02] +state 575 + action 0 + 582 : [1, 1] +state 576 + action 0 + 583 : [1, 1] +state 577 + action 0 + 572 : [0.98, 1] + 573 : [0.0001, 0.02] +state 578 + action 0 + 584 : [1, 1] +state 579 + action 0 + 585 : [1, 1] +state 580 + action 0 + 586 : [1, 1] +state 581 + action 0 + 587 : [1, 1] +state 582 + action 0 + 588 : [1, 1] +state 583 + action 0 + 589 : [0.97, 0.99] + 590 : [0.01, 0.03] +state 584 target + action 0 + 584 : [1, 1] +state 585 + action 0 + 560 : [0.97, 0.99] + 561 : [0.01, 0.03] +state 586 + action 0 + 591 : [1, 1] +state 587 + action 0 + 592 : [0.97, 0.99] + 593 : [0.01, 0.03] +state 588 + action 0 + 594 : [0.98, 1] + 595 : [0.0001, 0.02] +state 589 + action 0 + 596 : [1, 1] +state 590 + action 0 + 597 : [1, 1] +state 591 deadlock + action 0 + 591 : [1, 1] +state 592 + action 0 + 598 : [1, 1] +state 593 + action 0 + 599 : [1, 1] +state 594 + action 0 + 600 : [1, 1] +state 595 + action 0 + 599 : [1, 1] +state 596 + action 0 + 601 : [1, 1] +state 597 + action 0 + 602 : [1, 1] +state 598 + action 0 + 594 : [0.98, 1] + 595 : [0.0001, 0.02] +state 599 + action 0 + 603 : [0.97, 0.99] + 604 : [0.01, 0.03] +state 600 + action 0 + 605 : [1, 1] +state 601 + action 0 + 606 : [0.98, 1] + 607 : [0.0001, 0.02] +state 602 target + action 0 + 602 : [1, 1] +state 603 + action 0 + 608 : [1, 1] +state 604 + action 0 + 609 : [1, 1] +state 605 deadlock + action 0 + 605 : [1, 1] +state 606 + action 0 + 610 : [1, 1] +state 607 + action 0 + 609 : [1, 1] +state 608 + action 0 + 606 : [0.98, 1] + 607 : [0.0001, 0.02] +state 609 + action 0 + 611 : [1, 1] +state 610 + action 0 + 612 : [1, 1] +state 611 target + action 0 + 611 : [1, 1] +state 612 deadlock + action 0 + 612 : [1, 1] diff --git a/resources/examples/testfiles/imdp/brp-16-2.drn b/resources/examples/testfiles/imdp/brp-16-2.drn new file mode 100644 index 0000000000..a0cd8015de --- /dev/null +++ b/resources/examples/testfiles/imdp/brp-16-2.drn @@ -0,0 +1,2041 @@ +// Exported by storm +// Original model type: DTMC +@type: MDP +@parameters + +@reward_models + +@nr_states +613 +@nr_choices +613 +@model +state 0 init + action 0 + 1 : [1, 1] +state 1 + action 0 + 2 : [0.97, 0.99] + 3 : [0.01, 0.03] +state 2 + action 0 + 4 : [1, 1] +state 3 + action 0 + 5 : [1, 1] +state 4 + action 0 + 6 : [1, 1] +state 5 + action 0 + 7 : [0.97, 0.99] + 8 : [0.01, 0.03] +state 6 + action 0 + 9 : [1, 1] +state 7 + action 0 + 10 : [1, 1] +state 8 + action 0 + 11 : [1, 1] +state 9 + action 0 + 12 : [0.98, 1] + 13 : [0.0001, 0.02] +state 10 + action 0 + 14 : [1, 1] +state 11 + action 0 + 15 : [0.97, 0.99] + 16 : [0.01, 0.03] +state 12 + action 0 + 17 : [1, 1] +state 13 + action 0 + 18 : [1, 1] +state 14 + action 0 + 19 : [1, 1] +state 15 + action 0 + 20 : [1, 1] +state 16 + action 0 + 21 : [1, 1] +state 17 + action 0 + 22 : [1, 1] +state 18 + action 0 + 23 : [0.97, 0.99] + 24 : [0.01, 0.03] +state 19 + action 0 + 25 : [0.98, 1] + 26 : [0.0001, 0.02] +state 20 + action 0 + 27 : [1, 1] +state 21 + action 0 + 28 : [1, 1] +state 22 + action 0 + 29 : [0.97, 0.99] + 30 : [0.01, 0.03] +state 23 + action 0 + 31 : [1, 1] +state 24 + action 0 + 32 : [1, 1] +state 25 + action 0 + 33 : [1, 1] +state 26 + action 0 + 32 : [1, 1] +state 27 + action 0 + 34 : [1, 1] +state 28 target + action 0 + 28 : [1, 1] +state 29 + action 0 + 35 : [1, 1] +state 30 + action 0 + 36 : [1, 1] +state 31 + action 0 + 25 : [0.98, 1] + 26 : [0.0001, 0.02] +state 32 + action 0 + 37 : [0.97, 0.99] + 38 : [0.01, 0.03] +state 33 + action 0 + 39 : [1, 1] +state 34 + action 0 + 40 : [0.98, 1] + 41 : [0.0001, 0.02] +state 35 + action 0 + 42 : [1, 1] +state 36 + action 0 + 43 : [0.97, 0.99] + 44 : [0.01, 0.03] +state 37 + action 0 + 45 : [1, 1] +state 38 + action 0 + 46 : [1, 1] +state 39 + action 0 + 29 : [0.97, 0.99] + 30 : [0.01, 0.03] +state 40 + action 0 + 47 : [1, 1] +state 41 + action 0 + 46 : [1, 1] +state 42 + action 0 + 48 : [0.98, 1] + 49 : [0.0001, 0.02] +state 43 + action 0 + 50 : [1, 1] +state 44 + action 0 + 51 : [1, 1] +state 45 + action 0 + 40 : [0.98, 1] + 41 : [0.0001, 0.02] +state 46 + action 0 + 52 : [1, 1] +state 47 + action 0 + 53 : [1, 1] +state 48 + action 0 + 54 : [1, 1] +state 49 + action 0 + 55 : [1, 1] +state 50 + action 0 + 56 : [1, 1] +state 51 + action 0 + 57 : [0.97, 0.99] + 58 : [0.01, 0.03] +state 52 target + action 0 + 52 : [1, 1] +state 53 + action 0 + 29 : [0.97, 0.99] + 30 : [0.01, 0.03] +state 54 + action 0 + 59 : [1, 1] +state 55 + action 0 + 60 : [0.97, 0.99] + 61 : [0.01, 0.03] +state 56 + action 0 + 62 : [0.98, 1] + 63 : [0.0001, 0.02] +state 57 + action 0 + 64 : [1, 1] +state 58 + action 0 + 65 : [1, 1] +state 59 + action 0 + 66 : [0.97, 0.99] + 67 : [0.01, 0.03] +state 60 + action 0 + 68 : [1, 1] +state 61 + action 0 + 69 : [1, 1] +state 62 + action 0 + 70 : [1, 1] +state 63 + action 0 + 69 : [1, 1] +state 64 + action 0 + 71 : [1, 1] +state 65 + action 0 + 72 : [1, 1] +state 66 + action 0 + 73 : [1, 1] +state 67 + action 0 + 74 : [1, 1] +state 68 + action 0 + 62 : [0.98, 1] + 63 : [0.0001, 0.02] +state 69 + action 0 + 75 : [0.97, 0.99] + 76 : [0.01, 0.03] +state 70 + action 0 + 77 : [1, 1] +state 71 + action 0 + 78 : [0.98, 1] + 79 : [0.0001, 0.02] +state 72 target + action 0 + 72 : [1, 1] +state 73 + action 0 + 80 : [1, 1] +state 74 + action 0 + 81 : [0.97, 0.99] + 82 : [0.01, 0.03] +state 75 + action 0 + 83 : [1, 1] +state 76 + action 0 + 84 : [1, 1] +state 77 + action 0 + 66 : [0.97, 0.99] + 67 : [0.01, 0.03] +state 78 + action 0 + 85 : [1, 1] +state 79 + action 0 + 84 : [1, 1] +state 80 + action 0 + 86 : [0.98, 1] + 87 : [0.0001, 0.02] +state 81 + action 0 + 88 : [1, 1] +state 82 + action 0 + 89 : [1, 1] +state 83 + action 0 + 78 : [0.98, 1] + 79 : [0.0001, 0.02] +state 84 + action 0 + 90 : [1, 1] +state 85 + action 0 + 91 : [1, 1] +state 86 + action 0 + 92 : [1, 1] +state 87 + action 0 + 93 : [1, 1] +state 88 + action 0 + 94 : [1, 1] +state 89 + action 0 + 95 : [0.97, 0.99] + 96 : [0.01, 0.03] +state 90 target + action 0 + 90 : [1, 1] +state 91 + action 0 + 66 : [0.97, 0.99] + 67 : [0.01, 0.03] +state 92 + action 0 + 97 : [1, 1] +state 93 + action 0 + 98 : [0.97, 0.99] + 99 : [0.01, 0.03] +state 94 + action 0 + 100 : [0.98, 1] + 101 : [0.0001, 0.02] +state 95 + action 0 + 102 : [1, 1] +state 96 + action 0 + 103 : [1, 1] +state 97 + action 0 + 104 : [0.97, 0.99] + 105 : [0.01, 0.03] +state 98 + action 0 + 106 : [1, 1] +state 99 + action 0 + 107 : [1, 1] +state 100 + action 0 + 108 : [1, 1] +state 101 + action 0 + 107 : [1, 1] +state 102 + action 0 + 109 : [1, 1] +state 103 + action 0 + 110 : [1, 1] +state 104 + action 0 + 111 : [1, 1] +state 105 + action 0 + 112 : [1, 1] +state 106 + action 0 + 100 : [0.98, 1] + 101 : [0.0001, 0.02] +state 107 + action 0 + 113 : [0.97, 0.99] + 114 : [0.01, 0.03] +state 108 + action 0 + 115 : [1, 1] +state 109 + action 0 + 116 : [0.98, 1] + 117 : [0.0001, 0.02] +state 110 target + action 0 + 110 : [1, 1] +state 111 + action 0 + 118 : [1, 1] +state 112 + action 0 + 119 : [0.97, 0.99] + 120 : [0.01, 0.03] +state 113 + action 0 + 121 : [1, 1] +state 114 + action 0 + 122 : [1, 1] +state 115 + action 0 + 104 : [0.97, 0.99] + 105 : [0.01, 0.03] +state 116 + action 0 + 123 : [1, 1] +state 117 + action 0 + 122 : [1, 1] +state 118 + action 0 + 124 : [0.98, 1] + 125 : [0.0001, 0.02] +state 119 + action 0 + 126 : [1, 1] +state 120 + action 0 + 127 : [1, 1] +state 121 + action 0 + 116 : [0.98, 1] + 117 : [0.0001, 0.02] +state 122 + action 0 + 128 : [1, 1] +state 123 + action 0 + 129 : [1, 1] +state 124 + action 0 + 130 : [1, 1] +state 125 + action 0 + 131 : [1, 1] +state 126 + action 0 + 132 : [1, 1] +state 127 + action 0 + 133 : [0.97, 0.99] + 134 : [0.01, 0.03] +state 128 target + action 0 + 128 : [1, 1] +state 129 + action 0 + 104 : [0.97, 0.99] + 105 : [0.01, 0.03] +state 130 + action 0 + 135 : [1, 1] +state 131 + action 0 + 136 : [0.97, 0.99] + 137 : [0.01, 0.03] +state 132 + action 0 + 138 : [0.98, 1] + 139 : [0.0001, 0.02] +state 133 + action 0 + 140 : [1, 1] +state 134 + action 0 + 141 : [1, 1] +state 135 + action 0 + 142 : [0.97, 0.99] + 143 : [0.01, 0.03] +state 136 + action 0 + 144 : [1, 1] +state 137 + action 0 + 145 : [1, 1] +state 138 + action 0 + 146 : [1, 1] +state 139 + action 0 + 145 : [1, 1] +state 140 + action 0 + 147 : [1, 1] +state 141 + action 0 + 148 : [1, 1] +state 142 + action 0 + 149 : [1, 1] +state 143 + action 0 + 150 : [1, 1] +state 144 + action 0 + 138 : [0.98, 1] + 139 : [0.0001, 0.02] +state 145 + action 0 + 151 : [0.97, 0.99] + 152 : [0.01, 0.03] +state 146 + action 0 + 153 : [1, 1] +state 147 + action 0 + 154 : [0.98, 1] + 155 : [0.0001, 0.02] +state 148 target + action 0 + 148 : [1, 1] +state 149 + action 0 + 156 : [1, 1] +state 150 + action 0 + 157 : [0.97, 0.99] + 158 : [0.01, 0.03] +state 151 + action 0 + 159 : [1, 1] +state 152 + action 0 + 160 : [1, 1] +state 153 + action 0 + 142 : [0.97, 0.99] + 143 : [0.01, 0.03] +state 154 + action 0 + 161 : [1, 1] +state 155 + action 0 + 160 : [1, 1] +state 156 + action 0 + 162 : [0.98, 1] + 163 : [0.0001, 0.02] +state 157 + action 0 + 164 : [1, 1] +state 158 + action 0 + 165 : [1, 1] +state 159 + action 0 + 154 : [0.98, 1] + 155 : [0.0001, 0.02] +state 160 + action 0 + 166 : [1, 1] +state 161 + action 0 + 167 : [1, 1] +state 162 + action 0 + 168 : [1, 1] +state 163 + action 0 + 169 : [1, 1] +state 164 + action 0 + 170 : [1, 1] +state 165 + action 0 + 171 : [0.97, 0.99] + 172 : [0.01, 0.03] +state 166 target + action 0 + 166 : [1, 1] +state 167 + action 0 + 142 : [0.97, 0.99] + 143 : [0.01, 0.03] +state 168 + action 0 + 173 : [1, 1] +state 169 + action 0 + 174 : [0.97, 0.99] + 175 : [0.01, 0.03] +state 170 + action 0 + 176 : [0.98, 1] + 177 : [0.0001, 0.02] +state 171 + action 0 + 178 : [1, 1] +state 172 + action 0 + 179 : [1, 1] +state 173 + action 0 + 180 : [0.97, 0.99] + 181 : [0.01, 0.03] +state 174 + action 0 + 182 : [1, 1] +state 175 + action 0 + 183 : [1, 1] +state 176 + action 0 + 184 : [1, 1] +state 177 + action 0 + 183 : [1, 1] +state 178 + action 0 + 185 : [1, 1] +state 179 + action 0 + 186 : [1, 1] +state 180 + action 0 + 187 : [1, 1] +state 181 + action 0 + 188 : [1, 1] +state 182 + action 0 + 176 : [0.98, 1] + 177 : [0.0001, 0.02] +state 183 + action 0 + 189 : [0.97, 0.99] + 190 : [0.01, 0.03] +state 184 + action 0 + 191 : [1, 1] +state 185 + action 0 + 192 : [0.98, 1] + 193 : [0.0001, 0.02] +state 186 target + action 0 + 186 : [1, 1] +state 187 + action 0 + 194 : [1, 1] +state 188 + action 0 + 195 : [0.97, 0.99] + 196 : [0.01, 0.03] +state 189 + action 0 + 197 : [1, 1] +state 190 + action 0 + 198 : [1, 1] +state 191 + action 0 + 180 : [0.97, 0.99] + 181 : [0.01, 0.03] +state 192 + action 0 + 199 : [1, 1] +state 193 + action 0 + 198 : [1, 1] +state 194 + action 0 + 200 : [0.98, 1] + 201 : [0.0001, 0.02] +state 195 + action 0 + 202 : [1, 1] +state 196 + action 0 + 203 : [1, 1] +state 197 + action 0 + 192 : [0.98, 1] + 193 : [0.0001, 0.02] +state 198 + action 0 + 204 : [1, 1] +state 199 + action 0 + 205 : [1, 1] +state 200 + action 0 + 206 : [1, 1] +state 201 + action 0 + 207 : [1, 1] +state 202 + action 0 + 208 : [1, 1] +state 203 + action 0 + 209 : [0.97, 0.99] + 210 : [0.01, 0.03] +state 204 target + action 0 + 204 : [1, 1] +state 205 + action 0 + 180 : [0.97, 0.99] + 181 : [0.01, 0.03] +state 206 + action 0 + 211 : [1, 1] +state 207 + action 0 + 212 : [0.97, 0.99] + 213 : [0.01, 0.03] +state 208 + action 0 + 214 : [0.98, 1] + 215 : [0.0001, 0.02] +state 209 + action 0 + 216 : [1, 1] +state 210 + action 0 + 217 : [1, 1] +state 211 + action 0 + 218 : [0.97, 0.99] + 219 : [0.01, 0.03] +state 212 + action 0 + 220 : [1, 1] +state 213 + action 0 + 221 : [1, 1] +state 214 + action 0 + 222 : [1, 1] +state 215 + action 0 + 221 : [1, 1] +state 216 + action 0 + 223 : [1, 1] +state 217 + action 0 + 224 : [1, 1] +state 218 + action 0 + 225 : [1, 1] +state 219 + action 0 + 226 : [1, 1] +state 220 + action 0 + 214 : [0.98, 1] + 215 : [0.0001, 0.02] +state 221 + action 0 + 227 : [0.97, 0.99] + 228 : [0.01, 0.03] +state 222 + action 0 + 229 : [1, 1] +state 223 + action 0 + 230 : [0.98, 1] + 231 : [0.0001, 0.02] +state 224 target + action 0 + 224 : [1, 1] +state 225 + action 0 + 232 : [1, 1] +state 226 + action 0 + 233 : [0.97, 0.99] + 234 : [0.01, 0.03] +state 227 + action 0 + 235 : [1, 1] +state 228 + action 0 + 236 : [1, 1] +state 229 + action 0 + 218 : [0.97, 0.99] + 219 : [0.01, 0.03] +state 230 + action 0 + 237 : [1, 1] +state 231 + action 0 + 236 : [1, 1] +state 232 + action 0 + 238 : [0.98, 1] + 239 : [0.0001, 0.02] +state 233 + action 0 + 240 : [1, 1] +state 234 + action 0 + 241 : [1, 1] +state 235 + action 0 + 230 : [0.98, 1] + 231 : [0.0001, 0.02] +state 236 + action 0 + 242 : [1, 1] +state 237 + action 0 + 243 : [1, 1] +state 238 + action 0 + 244 : [1, 1] +state 239 + action 0 + 245 : [1, 1] +state 240 + action 0 + 246 : [1, 1] +state 241 + action 0 + 247 : [0.97, 0.99] + 248 : [0.01, 0.03] +state 242 target + action 0 + 242 : [1, 1] +state 243 + action 0 + 218 : [0.97, 0.99] + 219 : [0.01, 0.03] +state 244 + action 0 + 249 : [1, 1] +state 245 + action 0 + 250 : [0.97, 0.99] + 251 : [0.01, 0.03] +state 246 + action 0 + 252 : [0.98, 1] + 253 : [0.0001, 0.02] +state 247 + action 0 + 254 : [1, 1] +state 248 + action 0 + 255 : [1, 1] +state 249 + action 0 + 256 : [0.97, 0.99] + 257 : [0.01, 0.03] +state 250 + action 0 + 258 : [1, 1] +state 251 + action 0 + 259 : [1, 1] +state 252 + action 0 + 260 : [1, 1] +state 253 + action 0 + 259 : [1, 1] +state 254 + action 0 + 261 : [1, 1] +state 255 + action 0 + 262 : [1, 1] +state 256 + action 0 + 263 : [1, 1] +state 257 + action 0 + 264 : [1, 1] +state 258 + action 0 + 252 : [0.98, 1] + 253 : [0.0001, 0.02] +state 259 + action 0 + 265 : [0.97, 0.99] + 266 : [0.01, 0.03] +state 260 + action 0 + 267 : [1, 1] +state 261 + action 0 + 268 : [0.98, 1] + 269 : [0.0001, 0.02] +state 262 target + action 0 + 262 : [1, 1] +state 263 + action 0 + 270 : [1, 1] +state 264 + action 0 + 271 : [0.97, 0.99] + 272 : [0.01, 0.03] +state 265 + action 0 + 273 : [1, 1] +state 266 + action 0 + 274 : [1, 1] +state 267 + action 0 + 256 : [0.97, 0.99] + 257 : [0.01, 0.03] +state 268 + action 0 + 275 : [1, 1] +state 269 + action 0 + 274 : [1, 1] +state 270 + action 0 + 276 : [0.98, 1] + 277 : [0.0001, 0.02] +state 271 + action 0 + 278 : [1, 1] +state 272 + action 0 + 279 : [1, 1] +state 273 + action 0 + 268 : [0.98, 1] + 269 : [0.0001, 0.02] +state 274 + action 0 + 280 : [1, 1] +state 275 + action 0 + 281 : [1, 1] +state 276 + action 0 + 282 : [1, 1] +state 277 + action 0 + 283 : [1, 1] +state 278 + action 0 + 284 : [1, 1] +state 279 + action 0 + 285 : [0.97, 0.99] + 286 : [0.01, 0.03] +state 280 target + action 0 + 280 : [1, 1] +state 281 + action 0 + 256 : [0.97, 0.99] + 257 : [0.01, 0.03] +state 282 + action 0 + 287 : [1, 1] +state 283 + action 0 + 288 : [0.97, 0.99] + 289 : [0.01, 0.03] +state 284 + action 0 + 290 : [0.98, 1] + 291 : [0.0001, 0.02] +state 285 + action 0 + 292 : [1, 1] +state 286 + action 0 + 293 : [1, 1] +state 287 + action 0 + 294 : [0.97, 0.99] + 295 : [0.01, 0.03] +state 288 + action 0 + 296 : [1, 1] +state 289 + action 0 + 297 : [1, 1] +state 290 + action 0 + 298 : [1, 1] +state 291 + action 0 + 297 : [1, 1] +state 292 + action 0 + 299 : [1, 1] +state 293 + action 0 + 300 : [1, 1] +state 294 + action 0 + 301 : [1, 1] +state 295 + action 0 + 302 : [1, 1] +state 296 + action 0 + 290 : [0.98, 1] + 291 : [0.0001, 0.02] +state 297 + action 0 + 303 : [0.97, 0.99] + 304 : [0.01, 0.03] +state 298 + action 0 + 305 : [1, 1] +state 299 + action 0 + 306 : [0.98, 1] + 307 : [0.0001, 0.02] +state 300 target + action 0 + 300 : [1, 1] +state 301 + action 0 + 308 : [1, 1] +state 302 + action 0 + 309 : [0.97, 0.99] + 310 : [0.01, 0.03] +state 303 + action 0 + 311 : [1, 1] +state 304 + action 0 + 312 : [1, 1] +state 305 + action 0 + 294 : [0.97, 0.99] + 295 : [0.01, 0.03] +state 306 + action 0 + 313 : [1, 1] +state 307 + action 0 + 312 : [1, 1] +state 308 + action 0 + 314 : [0.98, 1] + 315 : [0.0001, 0.02] +state 309 + action 0 + 316 : [1, 1] +state 310 + action 0 + 317 : [1, 1] +state 311 + action 0 + 306 : [0.98, 1] + 307 : [0.0001, 0.02] +state 312 + action 0 + 318 : [1, 1] +state 313 + action 0 + 319 : [1, 1] +state 314 + action 0 + 320 : [1, 1] +state 315 + action 0 + 321 : [1, 1] +state 316 + action 0 + 322 : [1, 1] +state 317 + action 0 + 323 : [0.97, 0.99] + 324 : [0.01, 0.03] +state 318 target + action 0 + 318 : [1, 1] +state 319 + action 0 + 294 : [0.97, 0.99] + 295 : [0.01, 0.03] +state 320 + action 0 + 325 : [1, 1] +state 321 + action 0 + 326 : [0.97, 0.99] + 327 : [0.01, 0.03] +state 322 + action 0 + 328 : [0.98, 1] + 329 : [0.0001, 0.02] +state 323 + action 0 + 330 : [1, 1] +state 324 + action 0 + 331 : [1, 1] +state 325 + action 0 + 332 : [0.97, 0.99] + 333 : [0.01, 0.03] +state 326 + action 0 + 334 : [1, 1] +state 327 + action 0 + 335 : [1, 1] +state 328 + action 0 + 336 : [1, 1] +state 329 + action 0 + 335 : [1, 1] +state 330 + action 0 + 337 : [1, 1] +state 331 + action 0 + 338 : [1, 1] +state 332 + action 0 + 339 : [1, 1] +state 333 + action 0 + 340 : [1, 1] +state 334 + action 0 + 328 : [0.98, 1] + 329 : [0.0001, 0.02] +state 335 + action 0 + 341 : [0.97, 0.99] + 342 : [0.01, 0.03] +state 336 + action 0 + 343 : [1, 1] +state 337 + action 0 + 344 : [0.98, 1] + 345 : [0.0001, 0.02] +state 338 target + action 0 + 338 : [1, 1] +state 339 + action 0 + 346 : [1, 1] +state 340 + action 0 + 347 : [0.97, 0.99] + 348 : [0.01, 0.03] +state 341 + action 0 + 349 : [1, 1] +state 342 + action 0 + 350 : [1, 1] +state 343 + action 0 + 332 : [0.97, 0.99] + 333 : [0.01, 0.03] +state 344 + action 0 + 351 : [1, 1] +state 345 + action 0 + 350 : [1, 1] +state 346 + action 0 + 352 : [0.98, 1] + 353 : [0.0001, 0.02] +state 347 + action 0 + 354 : [1, 1] +state 348 + action 0 + 355 : [1, 1] +state 349 + action 0 + 344 : [0.98, 1] + 345 : [0.0001, 0.02] +state 350 + action 0 + 356 : [1, 1] +state 351 + action 0 + 357 : [1, 1] +state 352 + action 0 + 358 : [1, 1] +state 353 + action 0 + 359 : [1, 1] +state 354 + action 0 + 360 : [1, 1] +state 355 + action 0 + 361 : [0.97, 0.99] + 362 : [0.01, 0.03] +state 356 target + action 0 + 356 : [1, 1] +state 357 + action 0 + 332 : [0.97, 0.99] + 333 : [0.01, 0.03] +state 358 + action 0 + 363 : [1, 1] +state 359 + action 0 + 364 : [0.97, 0.99] + 365 : [0.01, 0.03] +state 360 + action 0 + 366 : [0.98, 1] + 367 : [0.0001, 0.02] +state 361 + action 0 + 368 : [1, 1] +state 362 + action 0 + 369 : [1, 1] +state 363 + action 0 + 370 : [0.97, 0.99] + 371 : [0.01, 0.03] +state 364 + action 0 + 372 : [1, 1] +state 365 + action 0 + 373 : [1, 1] +state 366 + action 0 + 374 : [1, 1] +state 367 + action 0 + 373 : [1, 1] +state 368 + action 0 + 375 : [1, 1] +state 369 + action 0 + 376 : [1, 1] +state 370 + action 0 + 377 : [1, 1] +state 371 + action 0 + 378 : [1, 1] +state 372 + action 0 + 366 : [0.98, 1] + 367 : [0.0001, 0.02] +state 373 + action 0 + 379 : [0.97, 0.99] + 380 : [0.01, 0.03] +state 374 + action 0 + 381 : [1, 1] +state 375 + action 0 + 382 : [0.98, 1] + 383 : [0.0001, 0.02] +state 376 target + action 0 + 376 : [1, 1] +state 377 + action 0 + 384 : [1, 1] +state 378 + action 0 + 385 : [0.97, 0.99] + 386 : [0.01, 0.03] +state 379 + action 0 + 387 : [1, 1] +state 380 + action 0 + 388 : [1, 1] +state 381 + action 0 + 370 : [0.97, 0.99] + 371 : [0.01, 0.03] +state 382 + action 0 + 389 : [1, 1] +state 383 + action 0 + 388 : [1, 1] +state 384 + action 0 + 390 : [0.98, 1] + 391 : [0.0001, 0.02] +state 385 + action 0 + 392 : [1, 1] +state 386 + action 0 + 393 : [1, 1] +state 387 + action 0 + 382 : [0.98, 1] + 383 : [0.0001, 0.02] +state 388 + action 0 + 394 : [1, 1] +state 389 + action 0 + 395 : [1, 1] +state 390 + action 0 + 396 : [1, 1] +state 391 + action 0 + 397 : [1, 1] +state 392 + action 0 + 398 : [1, 1] +state 393 + action 0 + 399 : [0.97, 0.99] + 400 : [0.01, 0.03] +state 394 target + action 0 + 394 : [1, 1] +state 395 + action 0 + 370 : [0.97, 0.99] + 371 : [0.01, 0.03] +state 396 + action 0 + 401 : [1, 1] +state 397 + action 0 + 402 : [0.97, 0.99] + 403 : [0.01, 0.03] +state 398 + action 0 + 404 : [0.98, 1] + 405 : [0.0001, 0.02] +state 399 + action 0 + 406 : [1, 1] +state 400 + action 0 + 407 : [1, 1] +state 401 + action 0 + 408 : [0.97, 0.99] + 409 : [0.01, 0.03] +state 402 + action 0 + 410 : [1, 1] +state 403 + action 0 + 411 : [1, 1] +state 404 + action 0 + 412 : [1, 1] +state 405 + action 0 + 411 : [1, 1] +state 406 + action 0 + 413 : [1, 1] +state 407 + action 0 + 414 : [1, 1] +state 408 + action 0 + 415 : [1, 1] +state 409 + action 0 + 416 : [1, 1] +state 410 + action 0 + 404 : [0.98, 1] + 405 : [0.0001, 0.02] +state 411 + action 0 + 417 : [0.97, 0.99] + 418 : [0.01, 0.03] +state 412 + action 0 + 419 : [1, 1] +state 413 + action 0 + 420 : [0.98, 1] + 421 : [0.0001, 0.02] +state 414 target + action 0 + 414 : [1, 1] +state 415 + action 0 + 422 : [1, 1] +state 416 + action 0 + 423 : [0.97, 0.99] + 424 : [0.01, 0.03] +state 417 + action 0 + 425 : [1, 1] +state 418 + action 0 + 426 : [1, 1] +state 419 + action 0 + 408 : [0.97, 0.99] + 409 : [0.01, 0.03] +state 420 + action 0 + 427 : [1, 1] +state 421 + action 0 + 426 : [1, 1] +state 422 + action 0 + 428 : [0.98, 1] + 429 : [0.0001, 0.02] +state 423 + action 0 + 430 : [1, 1] +state 424 + action 0 + 431 : [1, 1] +state 425 + action 0 + 420 : [0.98, 1] + 421 : [0.0001, 0.02] +state 426 + action 0 + 432 : [1, 1] +state 427 + action 0 + 433 : [1, 1] +state 428 + action 0 + 434 : [1, 1] +state 429 + action 0 + 435 : [1, 1] +state 430 + action 0 + 436 : [1, 1] +state 431 + action 0 + 437 : [0.97, 0.99] + 438 : [0.01, 0.03] +state 432 target + action 0 + 432 : [1, 1] +state 433 + action 0 + 408 : [0.97, 0.99] + 409 : [0.01, 0.03] +state 434 + action 0 + 439 : [1, 1] +state 435 + action 0 + 440 : [0.97, 0.99] + 441 : [0.01, 0.03] +state 436 + action 0 + 442 : [0.98, 1] + 443 : [0.0001, 0.02] +state 437 + action 0 + 444 : [1, 1] +state 438 + action 0 + 445 : [1, 1] +state 439 + action 0 + 446 : [0.97, 0.99] + 447 : [0.01, 0.03] +state 440 + action 0 + 448 : [1, 1] +state 441 + action 0 + 449 : [1, 1] +state 442 + action 0 + 450 : [1, 1] +state 443 + action 0 + 449 : [1, 1] +state 444 + action 0 + 451 : [1, 1] +state 445 + action 0 + 452 : [1, 1] +state 446 + action 0 + 453 : [1, 1] +state 447 + action 0 + 454 : [1, 1] +state 448 + action 0 + 442 : [0.98, 1] + 443 : [0.0001, 0.02] +state 449 + action 0 + 455 : [0.97, 0.99] + 456 : [0.01, 0.03] +state 450 + action 0 + 457 : [1, 1] +state 451 + action 0 + 458 : [0.98, 1] + 459 : [0.0001, 0.02] +state 452 target + action 0 + 452 : [1, 1] +state 453 + action 0 + 460 : [1, 1] +state 454 + action 0 + 461 : [0.97, 0.99] + 462 : [0.01, 0.03] +state 455 + action 0 + 463 : [1, 1] +state 456 + action 0 + 464 : [1, 1] +state 457 + action 0 + 446 : [0.97, 0.99] + 447 : [0.01, 0.03] +state 458 + action 0 + 465 : [1, 1] +state 459 + action 0 + 464 : [1, 1] +state 460 + action 0 + 466 : [0.98, 1] + 467 : [0.0001, 0.02] +state 461 + action 0 + 468 : [1, 1] +state 462 + action 0 + 469 : [1, 1] +state 463 + action 0 + 458 : [0.98, 1] + 459 : [0.0001, 0.02] +state 464 + action 0 + 470 : [1, 1] +state 465 + action 0 + 471 : [1, 1] +state 466 + action 0 + 472 : [1, 1] +state 467 + action 0 + 473 : [1, 1] +state 468 + action 0 + 474 : [1, 1] +state 469 + action 0 + 475 : [0.97, 0.99] + 476 : [0.01, 0.03] +state 470 target + action 0 + 470 : [1, 1] +state 471 + action 0 + 446 : [0.97, 0.99] + 447 : [0.01, 0.03] +state 472 + action 0 + 477 : [1, 1] +state 473 + action 0 + 478 : [0.97, 0.99] + 479 : [0.01, 0.03] +state 474 + action 0 + 480 : [0.98, 1] + 481 : [0.0001, 0.02] +state 475 + action 0 + 482 : [1, 1] +state 476 + action 0 + 483 : [1, 1] +state 477 + action 0 + 484 : [0.97, 0.99] + 485 : [0.01, 0.03] +state 478 + action 0 + 486 : [1, 1] +state 479 + action 0 + 487 : [1, 1] +state 480 + action 0 + 488 : [1, 1] +state 481 + action 0 + 487 : [1, 1] +state 482 + action 0 + 489 : [1, 1] +state 483 + action 0 + 490 : [1, 1] +state 484 + action 0 + 491 : [1, 1] +state 485 + action 0 + 492 : [1, 1] +state 486 + action 0 + 480 : [0.98, 1] + 481 : [0.0001, 0.02] +state 487 + action 0 + 493 : [0.97, 0.99] + 494 : [0.01, 0.03] +state 488 + action 0 + 495 : [1, 1] +state 489 + action 0 + 496 : [0.98, 1] + 497 : [0.0001, 0.02] +state 490 target + action 0 + 490 : [1, 1] +state 491 + action 0 + 498 : [1, 1] +state 492 + action 0 + 499 : [0.97, 0.99] + 500 : [0.01, 0.03] +state 493 + action 0 + 501 : [1, 1] +state 494 + action 0 + 502 : [1, 1] +state 495 + action 0 + 484 : [0.97, 0.99] + 485 : [0.01, 0.03] +state 496 + action 0 + 503 : [1, 1] +state 497 + action 0 + 502 : [1, 1] +state 498 + action 0 + 504 : [0.98, 1] + 505 : [0.0001, 0.02] +state 499 + action 0 + 506 : [1, 1] +state 500 + action 0 + 507 : [1, 1] +state 501 + action 0 + 496 : [0.98, 1] + 497 : [0.0001, 0.02] +state 502 + action 0 + 508 : [1, 1] +state 503 + action 0 + 509 : [1, 1] +state 504 + action 0 + 510 : [1, 1] +state 505 + action 0 + 511 : [1, 1] +state 506 + action 0 + 512 : [1, 1] +state 507 + action 0 + 513 : [0.97, 0.99] + 514 : [0.01, 0.03] +state 508 target + action 0 + 508 : [1, 1] +state 509 + action 0 + 484 : [0.97, 0.99] + 485 : [0.01, 0.03] +state 510 + action 0 + 515 : [1, 1] +state 511 + action 0 + 516 : [0.97, 0.99] + 517 : [0.01, 0.03] +state 512 + action 0 + 518 : [0.98, 1] + 519 : [0.0001, 0.02] +state 513 + action 0 + 520 : [1, 1] +state 514 + action 0 + 521 : [1, 1] +state 515 + action 0 + 522 : [0.97, 0.99] + 523 : [0.01, 0.03] +state 516 + action 0 + 524 : [1, 1] +state 517 + action 0 + 525 : [1, 1] +state 518 + action 0 + 526 : [1, 1] +state 519 + action 0 + 525 : [1, 1] +state 520 + action 0 + 527 : [1, 1] +state 521 + action 0 + 528 : [1, 1] +state 522 + action 0 + 529 : [1, 1] +state 523 + action 0 + 530 : [1, 1] +state 524 + action 0 + 518 : [0.98, 1] + 519 : [0.0001, 0.02] +state 525 + action 0 + 531 : [0.97, 0.99] + 532 : [0.01, 0.03] +state 526 + action 0 + 533 : [1, 1] +state 527 + action 0 + 534 : [0.98, 1] + 535 : [0.0001, 0.02] +state 528 target + action 0 + 528 : [1, 1] +state 529 + action 0 + 536 : [1, 1] +state 530 + action 0 + 537 : [0.97, 0.99] + 538 : [0.01, 0.03] +state 531 + action 0 + 539 : [1, 1] +state 532 + action 0 + 540 : [1, 1] +state 533 + action 0 + 522 : [0.97, 0.99] + 523 : [0.01, 0.03] +state 534 + action 0 + 541 : [1, 1] +state 535 + action 0 + 540 : [1, 1] +state 536 + action 0 + 542 : [0.98, 1] + 543 : [0.0001, 0.02] +state 537 + action 0 + 544 : [1, 1] +state 538 + action 0 + 545 : [1, 1] +state 539 + action 0 + 534 : [0.98, 1] + 535 : [0.0001, 0.02] +state 540 + action 0 + 546 : [1, 1] +state 541 + action 0 + 547 : [1, 1] +state 542 + action 0 + 548 : [1, 1] +state 543 + action 0 + 549 : [1, 1] +state 544 + action 0 + 550 : [1, 1] +state 545 + action 0 + 551 : [0.97, 0.99] + 552 : [0.01, 0.03] +state 546 target + action 0 + 546 : [1, 1] +state 547 + action 0 + 522 : [0.97, 0.99] + 523 : [0.01, 0.03] +state 548 + action 0 + 553 : [1, 1] +state 549 + action 0 + 554 : [0.97, 0.99] + 555 : [0.01, 0.03] +state 550 + action 0 + 556 : [0.98, 1] + 557 : [0.0001, 0.02] +state 551 + action 0 + 558 : [1, 1] +state 552 + action 0 + 559 : [1, 1] +state 553 + action 0 + 560 : [0.97, 0.99] + 561 : [0.01, 0.03] +state 554 + action 0 + 562 : [1, 1] +state 555 + action 0 + 563 : [1, 1] +state 556 + action 0 + 564 : [1, 1] +state 557 + action 0 + 563 : [1, 1] +state 558 + action 0 + 565 : [1, 1] +state 559 + action 0 + 566 : [1, 1] +state 560 + action 0 + 567 : [1, 1] +state 561 + action 0 + 568 : [1, 1] +state 562 + action 0 + 556 : [0.98, 1] + 557 : [0.0001, 0.02] +state 563 + action 0 + 569 : [0.97, 0.99] + 570 : [0.01, 0.03] +state 564 + action 0 + 571 : [1, 1] +state 565 + action 0 + 572 : [0.98, 1] + 573 : [0.0001, 0.02] +state 566 target + action 0 + 566 : [1, 1] +state 567 + action 0 + 574 : [1, 1] +state 568 + action 0 + 575 : [0.97, 0.99] + 576 : [0.01, 0.03] +state 569 + action 0 + 577 : [1, 1] +state 570 + action 0 + 578 : [1, 1] +state 571 + action 0 + 560 : [0.97, 0.99] + 561 : [0.01, 0.03] +state 572 + action 0 + 579 : [1, 1] +state 573 + action 0 + 578 : [1, 1] +state 574 + action 0 + 580 : [0.98, 1] + 581 : [0.0001, 0.02] +state 575 + action 0 + 582 : [1, 1] +state 576 + action 0 + 583 : [1, 1] +state 577 + action 0 + 572 : [0.98, 1] + 573 : [0.0001, 0.02] +state 578 + action 0 + 584 : [1, 1] +state 579 + action 0 + 585 : [1, 1] +state 580 + action 0 + 586 : [1, 1] +state 581 + action 0 + 587 : [1, 1] +state 582 + action 0 + 588 : [1, 1] +state 583 + action 0 + 589 : [0.97, 0.99] + 590 : [0.01, 0.03] +state 584 target + action 0 + 584 : [1, 1] +state 585 + action 0 + 560 : [0.97, 0.99] + 561 : [0.01, 0.03] +state 586 + action 0 + 591 : [1, 1] +state 587 + action 0 + 592 : [0.97, 0.99] + 593 : [0.01, 0.03] +state 588 + action 0 + 594 : [0.98, 1] + 595 : [0.0001, 0.02] +state 589 + action 0 + 596 : [1, 1] +state 590 + action 0 + 597 : [1, 1] +state 591 deadlock + action 0 + 591 : [1, 1] +state 592 + action 0 + 598 : [1, 1] +state 593 + action 0 + 599 : [1, 1] +state 594 + action 0 + 600 : [1, 1] +state 595 + action 0 + 599 : [1, 1] +state 596 + action 0 + 601 : [1, 1] +state 597 + action 0 + 602 : [1, 1] +state 598 + action 0 + 594 : [0.98, 1] + 595 : [0.0001, 0.02] +state 599 + action 0 + 603 : [0.97, 0.99] + 604 : [0.01, 0.03] +state 600 + action 0 + 605 : [1, 1] +state 601 + action 0 + 606 : [0.98, 1] + 607 : [0.0001, 0.02] +state 602 target + action 0 + 602 : [1, 1] +state 603 + action 0 + 608 : [1, 1] +state 604 + action 0 + 609 : [1, 1] +state 605 deadlock + action 0 + 605 : [1, 1] +state 606 + action 0 + 610 : [1, 1] +state 607 + action 0 + 609 : [1, 1] +state 608 + action 0 + 606 : [0.98, 1] + 607 : [0.0001, 0.02] +state 609 + action 0 + 611 : [1, 1] +state 610 + action 0 + 612 : [1, 1] +state 611 target + action 0 + 611 : [1, 1] +state 612 deadlock + action 0 + 612 : [1, 1] diff --git a/resources/examples/testfiles/imdp/tiny-01.drn b/resources/examples/testfiles/imdp/tiny-01.drn new file mode 100644 index 0000000000..6bf3ab10ca --- /dev/null +++ b/resources/examples/testfiles/imdp/tiny-01.drn @@ -0,0 +1,20 @@ +@type: MDP +@parameters + +@reward_models + +@nr_states +3 +@nr_choices +3 +@model +state 0 init + action 0 + 1 : [0.4, 0.9] + 2 : [0.5, 0.8] +state 1 target + action 0 + 1 : [1, 1] +state 2 + action 0 + 2 : [1, 1] \ No newline at end of file diff --git a/resources/examples/testfiles/imdp/tiny-02.drn b/resources/examples/testfiles/imdp/tiny-02.drn new file mode 100644 index 0000000000..244e7f9b09 --- /dev/null +++ b/resources/examples/testfiles/imdp/tiny-02.drn @@ -0,0 +1,23 @@ +// Exported by storm +// Original model type: DTMC +@type: MDP +@parameters + +@reward_models + +@nr_states +3 +@nr_choices +3 +@model +state 0 init + action 0 + 0 : [0.1, 0.2] + 1 : [0.2, 0.6] + 2 : [0.3, 0.8] +state 1 target + action 0 + 1 : [1, 1] +state 2 + action 0 + 2 : [1, 1] \ No newline at end of file diff --git a/resources/examples/testfiles/imdp/tiny-03.drn b/resources/examples/testfiles/imdp/tiny-03.drn new file mode 100644 index 0000000000..2f7d99b526 --- /dev/null +++ b/resources/examples/testfiles/imdp/tiny-03.drn @@ -0,0 +1,23 @@ +@type: MDP +@parameters + +@reward_models + +@nr_states +3 +@nr_choices +4 +@model +state 0 init + action 0 + 1 : [0.4, 0.9] + 2 : [0.5, 0.8] + action 1 + 1 : [0.4, 0.9] + 2 : [0.5, 0.8] +state 1 target + action 0 + 1 : [1, 1] +state 2 + action 0 + 2 : [1, 1] \ No newline at end of file diff --git a/resources/examples/testfiles/imdp/tiny-04.drn b/resources/examples/testfiles/imdp/tiny-04.drn new file mode 100644 index 0000000000..6498eaec3a --- /dev/null +++ b/resources/examples/testfiles/imdp/tiny-04.drn @@ -0,0 +1,35 @@ +@type: MDP +@parameters + +@reward_models +steps +@nr_states +5 +@nr_choices +8 +@model +state 0 init [1] + action 0 + 1 : [0.4, 0.4] + 2 : [0.3, 0.3] + 3 : [0.1, 0.6] +state 1 [1] + action 0 + 1 : [1, 1] + action 1 + 2 : [1, 1] +state 2 [1] + action 0 + 3 : [0.4, 0.9] + 4 : [0.5, 0.8] + action 1 + 3 : [0.4, 0.9] + 4 : [0.5, 0.8] + action 2 + 0 : [1,1] +state 3 target + action 0 + 3 : [1, 1] +state 4 + action 0 + 4 : [1, 1] diff --git a/src/storm-dft/parser/DFTJsonParser.cpp b/src/storm-dft/parser/DFTJsonParser.cpp index c0143d1579..560a1cafcf 100644 --- a/src/storm-dft/parser/DFTJsonParser.cpp +++ b/src/storm-dft/parser/DFTJsonParser.cpp @@ -8,6 +8,7 @@ #include "storm/adapters/JsonAdapter.h" #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/NotSupportedException.h" +#include "storm/exceptions/WrongFormatException.h" #include "storm/io/file.h" #include "storm/utility/macros.h" diff --git a/src/storm-parsers/parser/DirectEncodingParser.cpp b/src/storm-parsers/parser/DirectEncodingParser.cpp index f7eada3dcc..02cb5c95bd 100644 --- a/src/storm-parsers/parser/DirectEncodingParser.cpp +++ b/src/storm-parsers/parser/DirectEncodingParser.cpp @@ -429,6 +429,7 @@ ValueType DirectEncodingParser::parseValue(std::stri template class DirectEncodingParser; template class DirectEncodingParser; template class DirectEncodingParser; +template class DirectEncodingParser; } // namespace parser } // namespace storm diff --git a/src/storm-parsers/parser/ValueParser.cpp b/src/storm-parsers/parser/ValueParser.cpp index f6076408b9..5de5fef96d 100644 --- a/src/storm-parsers/parser/ValueParser.cpp +++ b/src/storm-parsers/parser/ValueParser.cpp @@ -1,20 +1,28 @@ #include "storm-parsers/parser/ValueParser.h" -#include "storm-parsers/parser/ExpressionParser.h" +#include +#include + +#include "storm-parsers/parser/ExpressionParser.h" +#include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/NotSupportedException.h" +#include "storm/storage/expressions/ExpressionEvaluator.h" +#include "storm/utility/constants.h" namespace storm { namespace parser { template -ValueParser::ValueParser() - : manager(new storm::expressions::ExpressionManager()), parser(std::make_unique(*manager)), evaluator(*manager) { +ValueParser::ParametricData::ParametricData() + : manager(new storm::expressions::ExpressionManager()), + parser(std::make_unique(*manager)), + evaluator(new storm::expressions::ExpressionEvaluator(*manager)) { // Set empty mapping to enable expression creation even without parameters parser->setIdentifierMapping(identifierMapping); } template -ValueParser::~ValueParser() = default; +ValueParser::ParametricData::~ParametricData() = default; template void ValueParser::addParameter(std::string const& parameter) { @@ -23,15 +31,15 @@ void ValueParser::addParameter(std::string const& parameter) { template<> void ValueParser::addParameter(std::string const& parameter) { - storm::expressions::Variable var = manager->declareRationalVariable(parameter); - identifierMapping.emplace(var.getName(), var); - parser->setIdentifierMapping(identifierMapping); + storm::expressions::Variable var = data.manager->declareRationalVariable(parameter); + data.identifierMapping.emplace(var.getName(), var); + data.parser->setIdentifierMapping(data.identifierMapping); STORM_LOG_TRACE("Added parameter: " << var.getName()); } template<> storm::RationalFunction ValueParser::parseValue(std::string const& value) const { - storm::RationalFunction rationalFunction = evaluator.asRational(parser->parseFromString(value)); + storm::RationalFunction rationalFunction = data.evaluator->asRational(data.parser->parseFromString(value)); STORM_LOG_TRACE("Parsed expression: " << rationalFunction); return rationalFunction; } @@ -41,10 +49,94 @@ ValueType ValueParser::parseValue(std::string const& value) const { return parseNumber(value); } +template +NumberType parseNumber(std::string const& value) { + NumberType result; + if (!parseNumber(value, result)) { + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Could not parse value '" << value << "' into " << typeid(NumberType).name() << "."); + } + return result; +} + +bool parseDouble(std::string const& value, double& result) { + if (boost::conversion::try_lexical_convert(value, result)) { + return true; + } else { + // Try as rational number + storm::RationalNumber rationalResult; + if (parseNumber(value, rationalResult)) { + result = storm::utility::convertNumber(rationalResult); + return true; + } else { + return false; + } + } +} +bool parseInterval(std::string const& value, storm::Interval& result) { + // Try whether it is a constant. + if (double pointResult; parseNumber(value, pointResult)) { + result = storm::Interval(pointResult); + return true; + } + + std::string intermediate = value; + boost::trim(intermediate); + carl::BoundType leftBound; + carl::BoundType rightBound; + if (intermediate.front() == '(') { + leftBound = carl::BoundType::STRICT; + } else if (intermediate.front() == '[') { + leftBound = carl::BoundType::WEAK; + } else { + return false; // Expect start with '(' or '['. + } + if (intermediate.back() == ')') { + rightBound = carl::BoundType::STRICT; + } else if (intermediate.back() == ']') { + rightBound = carl::BoundType::WEAK; + } else { + return false; // Expected end with ')' or ']'. + } + intermediate = intermediate.substr(1, intermediate.size() - 2); + + std::vector words; + boost::split(words, intermediate, boost::is_any_of(",")); + if (words.size() != 2) { + return false; // Did not find exactly one comma. + } + double leftVal, rightVal; + boost::trim(words[0]); + if (!parseNumber(words[0], leftVal)) { + return false; // lower value of interval invalid. + } + boost::trim(words[1]); + if (!parseNumber(words[1], rightVal)) { + return false; // upper value of interval invalid. + } + result = storm::Interval(leftVal, leftBound, rightVal, rightBound); + return true; +} + +template +bool parseNumber(std::string const& value, NumberType& result) { + if constexpr (std::is_same_v) { + return parseDouble(value, result); + } else if constexpr (std::is_same_v) { + return carl::try_parse(value, result); + } else if constexpr (std::is_same_v) { + return parseInterval(value, result); + } else { + return boost::conversion::try_lexical_convert(value, result); + } +} + // Template instantiations. template class ValueParser; template class ValueParser; template class ValueParser; +template class ValueParser; + +template std::size_t parseNumber(std::string const&); } // namespace parser } // namespace storm diff --git a/src/storm-parsers/parser/ValueParser.h b/src/storm-parsers/parser/ValueParser.h index 03ee84f4ca..47a85dd1a2 100644 --- a/src/storm-parsers/parser/ValueParser.h +++ b/src/storm-parsers/parser/ValueParser.h @@ -1,12 +1,18 @@ -#ifndef STORM_PARSER_VALUEPARSER_H_ -#define STORM_PARSER_VALUEPARSER_H_ +#pragma once -#include -#include "storm/exceptions/WrongFormatException.h" -#include "storm/storage/expressions/ExpressionEvaluator.h" +#include +#include +#include + +#include "storm/adapters/RationalFunctionForward.h" #include "storm/storage/expressions/ExpressionManager.h" -#include "storm/utility/constants.h" + namespace storm { +namespace expressions { +template +class ExpressionEvaluator; +} + namespace parser { class ExpressionParser; @@ -16,12 +22,6 @@ class ExpressionParser; template class ValueParser { public: - /*! - * Constructor. - */ - ValueParser(); - virtual ~ValueParser(); - /*! * Parse ValueType from string. * @@ -39,10 +39,15 @@ class ValueParser { void addParameter(std::string const& parameter); private: - std::shared_ptr manager; - std::unique_ptr parser; // Pointer to avoid header include. - storm::expressions::ExpressionEvaluator evaluator; - std::unordered_map identifierMapping; + struct ParametricData { + ParametricData(); + ~ParametricData(); + std::shared_ptr manager; + std::unique_ptr parser; // Pointer to avoid header include. + std::unique_ptr> evaluator; + std::unordered_map identifierMapping; + }; + std::conditional_t, ParametricData, std::nullptr_t> data; }; /*! @@ -50,32 +55,20 @@ class ValueParser { * * @param value String containing the value. * + * @throws WrongFormatException if parsing is not successful * @return NumberType. */ template -inline NumberType parseNumber(std::string const& value) { - try { - return boost::lexical_cast(value); - } catch (boost::bad_lexical_cast&) { - STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Could not parse value '" << value << "' into " << typeid(NumberType).name() << "."); - } -} +NumberType parseNumber(std::string const& value); -template<> -inline storm::RationalNumber parseNumber(std::string const& value) { - return storm::utility::convertNumber(value); -} - -template<> -inline double parseNumber(std::string const& value) { - try { - return boost::lexical_cast(value); - } catch (boost::bad_lexical_cast&) { - return storm::utility::convertNumber(parseNumber(value)); - } -} +/*! + * Parse number from string. + * @param value String containing the value. + * @param result if parsing is successful, the parsed number is stored here + * @return whether parsing is successful. + */ +template +bool parseNumber(std::string const& value, NumberType& result); } // namespace parser } // namespace storm - -#endif /* STORM_PARSER_VALUEPARSER_H_ */ diff --git a/src/storm/adapters/RationalFunctionForward.h b/src/storm/adapters/RationalFunctionForward.h index 486e50ccce..b64ccd8a2f 100644 --- a/src/storm/adapters/RationalFunctionForward.h +++ b/src/storm/adapters/RationalFunctionForward.h @@ -19,9 +19,6 @@ namespace carl { -template -class Interval; - template class FactorizedPolynomial; @@ -51,6 +48,5 @@ typedef carl::MultivariatePolynomial RawPolynomial; typedef carl::FactorizedPolynomial Polynomial; typedef carl::RationalFunction RationalFunction; -typedef carl::Interval Interval; } // namespace storm diff --git a/src/storm/adapters/RationalNumberAdapter.h b/src/storm/adapters/RationalNumberAdapter.h index cd67bcac18..7e72c6def3 100644 --- a/src/storm/adapters/RationalNumberAdapter.h +++ b/src/storm/adapters/RationalNumberAdapter.h @@ -13,6 +13,7 @@ #include #endif +#include #include #if defined(STORM_HAVE_CLN) diff --git a/src/storm/adapters/RationalNumberForward.h b/src/storm/adapters/RationalNumberForward.h index a079d08076..8bb71b3c2b 100644 --- a/src/storm/adapters/RationalNumberForward.h +++ b/src/storm/adapters/RationalNumberForward.h @@ -16,6 +16,11 @@ class cl_I; } // namespace cln #endif +namespace carl { +template +class Interval; +} + namespace storm { #if defined(STORM_HAVE_CLN) typedef cln::cl_RA ClnRationalNumber; @@ -25,6 +30,7 @@ typedef cln::cl_I ClnIntegerNumber; typedef __gmp_expr GmpRationalNumber; typedef __gmp_expr GmpIntegerNumber; #endif +typedef carl::Interval Interval; #if defined(STORM_HAVE_CLN) && defined(STORM_USE_CLN_EA) typedef ClnRationalNumber RationalNumber; diff --git a/src/storm/io/DirectEncodingExporter.cpp b/src/storm/io/DirectEncodingExporter.cpp index debf4322dd..edb8799ca5 100644 --- a/src/storm/io/DirectEncodingExporter.cpp +++ b/src/storm/io/DirectEncodingExporter.cpp @@ -279,5 +279,7 @@ template void explicitExportSparseModel(std::ostream& os, template void explicitExportSparseModel(std::ostream& os, std::shared_ptr> sparseModel, std::vector const& parameters, DirectEncodingOptions const& options); +template void explicitExportSparseModel(std::ostream& os, std::shared_ptr> sparseModel, + std::vector const& parameters, DirectEncodingOptions const& options); } // namespace exporter } // namespace storm diff --git a/src/storm/modelchecker/AbstractModelChecker.cpp b/src/storm/modelchecker/AbstractModelChecker.cpp index d6bb15ab55..e0eb3f622a 100644 --- a/src/storm/modelchecker/AbstractModelChecker.cpp +++ b/src/storm/modelchecker/AbstractModelChecker.cpp @@ -45,13 +45,13 @@ std::string AbstractModelChecker::getClassName() const { } template -std::unique_ptr AbstractModelChecker::check(CheckTask const& checkTask) { +std::unique_ptr AbstractModelChecker::check(CheckTask const& checkTask) { Environment env; return this->check(env, checkTask); } template -std::unique_ptr AbstractModelChecker::check(Environment const& env, CheckTask const& checkTask) { +std::unique_ptr AbstractModelChecker::check(Environment const& env, CheckTask const& checkTask) { storm::logic::Formula const& formula = checkTask.getFormula(); STORM_LOG_THROW(this->canHandle(checkTask), storm::exceptions::InvalidArgumentException, "The model checker (" << getClassName() << ") is not able to check the formula '" << formula << "'."); @@ -63,7 +63,7 @@ std::unique_ptr AbstractModelChecker::check(Environment template std::unique_ptr AbstractModelChecker::computeProbabilities(Environment const& env, - CheckTask const& checkTask) { + CheckTask const& checkTask) { storm::logic::Formula const& formula = checkTask.getFormula(); if (formula.isStateFormula() || formula.hasQualitativeResult()) { @@ -93,21 +93,21 @@ std::unique_ptr AbstractModelChecker::computeProbabiliti template std::unique_ptr AbstractModelChecker::computeBoundedUntilProbabilities( - Environment const&, CheckTask const& checkTask) { + Environment const&, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeConditionalProbabilities( - Environment const&, CheckTask const& checkTask) { + Environment const&, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeReachabilityProbabilities( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::EventuallyFormula const& pathFormula = checkTask.getFormula(); storm::logic::UntilFormula newFormula(storm::logic::Formula::getTrueFormula(), pathFormula.getSubformula().asSharedPointer()); return this->computeUntilProbabilities(env, checkTask.substituteFormula(newFormula)); @@ -115,56 +115,56 @@ std::unique_ptr AbstractModelChecker::computeReachabilit template std::unique_ptr AbstractModelChecker::computeGloballyProbabilities( - Environment const&, CheckTask const& checkTask) { + Environment const&, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeNextProbabilities(Environment const&, - CheckTask const& checkTask) { + CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeUntilProbabilities(Environment const&, - CheckTask const& checkTask) { + CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template -std::unique_ptr AbstractModelChecker::computeHOAPathProbabilities(Environment const&, - CheckTask const& checkTask) { +std::unique_ptr AbstractModelChecker::computeHOAPathProbabilities( + Environment const&, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeLTLProbabilities(Environment const&, - CheckTask const& checkTask) { + CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } template -std::unique_ptr AbstractModelChecker::computeStateFormulaProbabilities(Environment const& env, - CheckTask const& checkTask) { +std::unique_ptr AbstractModelChecker::computeStateFormulaProbabilities( + Environment const& env, CheckTask const& checkTask) { // recurse std::unique_ptr resultPointer = this->check(env, checkTask.getFormula()); if (resultPointer->isExplicitQualitativeCheckResult()) { STORM_LOG_ASSERT(ModelType::Representation == storm::models::ModelRepresentation::Sparse, "Unexpected model type."); - return std::make_unique>(resultPointer->asExplicitQualitativeCheckResult()); + return std::make_unique>(resultPointer->asExplicitQualitativeCheckResult()); } else { STORM_LOG_ASSERT(resultPointer->isSymbolicQualitativeCheckResult(), "Unexpected result type."); STORM_LOG_ASSERT(ModelType::Representation != storm::models::ModelRepresentation::Sparse, "Unexpected model type."); auto const& qualRes = resultPointer->asSymbolicQualitativeCheckResult::ddType>(); - return std::make_unique::ddType, ValueType>>(qualRes); + return std::make_unique::ddType, SolutionType>>(qualRes); } } template std::unique_ptr AbstractModelChecker::computeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask) { + CheckTask const& checkTask) { storm::logic::Formula const& rewardFormula = checkTask.getFormula(); if (rewardFormula.isCumulativeRewardFormula()) { return this->computeCumulativeRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asCumulativeRewardFormula())); @@ -184,56 +184,56 @@ std::unique_ptr AbstractModelChecker::computeRewards(Env template std::unique_ptr AbstractModelChecker::computeConditionalRewards( - Environment const&, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + Environment const&, storm::logic::RewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeCumulativeRewards( - Environment const&, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + Environment const&, storm::logic::RewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeInstantaneousRewards( - Environment const&, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + Environment const&, storm::logic::RewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeReachabilityRewards( - Environment const&, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + Environment const&, storm::logic::RewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeTotalRewards(Environment const&, storm::logic::RewardMeasureType, - CheckTask const& checkTask) { + CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeLongRunAverageRewards( - Environment const&, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + Environment const&, storm::logic::RewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeLongRunAverageProbabilities( - Environment const&, CheckTask const& checkTask) { + Environment const&, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask) { + CheckTask const& checkTask) { storm::logic::Formula const& timeFormula = checkTask.getFormula(); if (timeFormula.isReachabilityTimeFormula()) { return this->computeReachabilityTimes(env, rewardMeasureType, checkTask.substituteFormula(timeFormula.asReachabilityTimeFormula())); @@ -243,15 +243,15 @@ std::unique_ptr AbstractModelChecker::computeTimes(Envir } template -std::unique_ptr AbstractModelChecker::computeReachabilityTimes(Environment const&, storm::logic::RewardMeasureType, - CheckTask const& checkTask) { +std::unique_ptr AbstractModelChecker::computeReachabilityTimes( + Environment const&, storm::logic::RewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::checkStateFormula(Environment const& env, - CheckTask const& checkTask) { + CheckTask const& checkTask) { storm::logic::StateFormula const& stateFormula = checkTask.getFormula(); if (stateFormula.isBinaryBooleanStateFormula()) { return this->checkBinaryBooleanStateFormula(env, checkTask.substituteFormula(stateFormula.asBinaryBooleanStateFormula())); @@ -289,7 +289,7 @@ std::unique_ptr AbstractModelChecker::checkStateFormula( template std::unique_ptr AbstractModelChecker::checkAtomicExpressionFormula( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::AtomicExpressionFormula const& stateFormula = checkTask.getFormula(); std::stringstream stream; stream << stateFormula.getExpression(); @@ -297,15 +297,15 @@ std::unique_ptr AbstractModelChecker::checkAtomicExpress } template -std::unique_ptr AbstractModelChecker::checkAtomicLabelFormula(Environment const&, - CheckTask const& checkTask) { +std::unique_ptr AbstractModelChecker::checkAtomicLabelFormula( + Environment const&, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::checkBinaryBooleanStateFormula( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::BinaryBooleanStateFormula const& stateFormula = checkTask.getFormula(); STORM_LOG_THROW(stateFormula.getLeftSubformula().isStateFormula() && stateFormula.getRightSubformula().isStateFormula(), storm::exceptions::InvalidArgumentException, "The given formula is invalid."); @@ -331,21 +331,21 @@ std::unique_ptr AbstractModelChecker::checkBinaryBoolean template std::unique_ptr AbstractModelChecker::checkBooleanLiteralFormula( - Environment const&, CheckTask const& checkTask) { + Environment const&, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::checkProbabilityOperatorFormula( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::ProbabilityOperatorFormula const& stateFormula = checkTask.getFormula(); std::unique_ptr result = this->computeProbabilities(env, checkTask.substituteFormula(stateFormula.getSubformula())); if (checkTask.isBoundSet()) { STORM_LOG_THROW(result->isQuantitative(), storm::exceptions::InvalidOperationException, "Unable to perform comparison operation on non-quantitative result."); - return result->asQuantitativeCheckResult().compareAgainstBound(checkTask.getBoundComparisonType(), checkTask.getBoundThreshold()); + return result->asQuantitativeCheckResult().compareAgainstBound(checkTask.getBoundComparisonType(), checkTask.getBoundThreshold()); } else { return result; } @@ -353,14 +353,14 @@ std::unique_ptr AbstractModelChecker::checkProbabilityOp template std::unique_ptr AbstractModelChecker::checkRewardOperatorFormula( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::RewardOperatorFormula const& stateFormula = checkTask.getFormula(); std::unique_ptr result = this->computeRewards(env, stateFormula.getMeasureType(), checkTask.substituteFormula(stateFormula.getSubformula())); if (checkTask.isBoundSet()) { STORM_LOG_THROW(result->isQuantitative(), storm::exceptions::InvalidOperationException, "Unable to perform comparison operation on non-quantitative result."); - return result->asQuantitativeCheckResult().compareAgainstBound(checkTask.getBoundComparisonType(), checkTask.getBoundThreshold()); + return result->asQuantitativeCheckResult().compareAgainstBound(checkTask.getBoundComparisonType(), checkTask.getBoundThreshold()); } else { return result; } @@ -368,7 +368,7 @@ std::unique_ptr AbstractModelChecker::checkRewardOperato template std::unique_ptr AbstractModelChecker::checkTimeOperatorFormula( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::TimeOperatorFormula const& stateFormula = checkTask.getFormula(); STORM_LOG_THROW(stateFormula.getSubformula().isReachabilityTimeFormula(), storm::exceptions::InvalidArgumentException, "The given formula is invalid."); @@ -377,7 +377,7 @@ std::unique_ptr AbstractModelChecker::checkTimeOperatorF if (checkTask.isBoundSet()) { STORM_LOG_THROW(result->isQuantitative(), storm::exceptions::InvalidOperationException, "Unable to perform comparison operation on non-quantitative result."); - return result->asQuantitativeCheckResult().compareAgainstBound(checkTask.getBoundComparisonType(), checkTask.getBoundThreshold()); + return result->asQuantitativeCheckResult().compareAgainstBound(checkTask.getBoundComparisonType(), checkTask.getBoundThreshold()); } else { return result; } @@ -385,7 +385,7 @@ std::unique_ptr AbstractModelChecker::checkTimeOperatorF template std::unique_ptr AbstractModelChecker::checkLongRunAverageOperatorFormula( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::LongRunAverageOperatorFormula const& stateFormula = checkTask.getFormula(); STORM_LOG_THROW(stateFormula.getSubformula().isStateFormula(), storm::exceptions::InvalidArgumentException, "The given formula is invalid."); @@ -395,7 +395,7 @@ std::unique_ptr AbstractModelChecker::checkLongRunAverag if (checkTask.isBoundSet()) { STORM_LOG_THROW(result->isQuantitative(), storm::exceptions::InvalidOperationException, "Unable to perform comparison operation on non-quantitative result."); - return result->asQuantitativeCheckResult().compareAgainstBound(checkTask.getBoundComparisonType(), checkTask.getBoundThreshold()); + return result->asQuantitativeCheckResult().compareAgainstBound(checkTask.getBoundComparisonType(), checkTask.getBoundThreshold()); } else { return result; } @@ -403,7 +403,7 @@ std::unique_ptr AbstractModelChecker::checkLongRunAverag template std::unique_ptr AbstractModelChecker::checkUnaryBooleanStateFormula( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::UnaryBooleanStateFormula const& stateFormula = checkTask.getFormula(); std::unique_ptr subResult = this->check(env, checkTask.template substituteFormula(stateFormula.getSubformula())); STORM_LOG_THROW(subResult->isQualitative(), storm::exceptions::InternalTypeErrorException, "Expected qualitative result."); @@ -417,28 +417,28 @@ std::unique_ptr AbstractModelChecker::checkUnaryBooleanS template std::unique_ptr AbstractModelChecker::checkLexObjectiveFormula( - Environment const&, CheckTask const& checkTask) { + Environment const&, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::checkMultiObjectiveFormula( - Environment const&, CheckTask const& checkTask) { + Environment const&, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::checkQuantileFormula(Environment const&, - CheckTask const& checkTask) { + CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::checkGameFormula(Environment const&, - CheckTask const& checkTask) { + CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } @@ -455,7 +455,6 @@ template class AbstractModelChecker>; template class AbstractModelChecker>; template class AbstractModelChecker>; -#ifdef STORM_HAVE_CARL template class AbstractModelChecker>>; template class AbstractModelChecker>>; @@ -473,7 +472,9 @@ template class AbstractModelChecker>; template class AbstractModelChecker>; template class AbstractModelChecker>; -#endif + +template class AbstractModelChecker>; + // DD template class AbstractModelChecker>; template class AbstractModelChecker>; diff --git a/src/storm/modelchecker/AbstractModelChecker.h b/src/storm/modelchecker/AbstractModelChecker.h index e924c93f06..23c8d08656 100644 --- a/src/storm/modelchecker/AbstractModelChecker.h +++ b/src/storm/modelchecker/AbstractModelChecker.h @@ -24,6 +24,7 @@ class AbstractModelChecker { } typedef typename ModelType::ValueType ValueType; + using SolutionType = typename std::conditional, double, ValueType>::type; /*! * Returns the name of the model checker class (e.g., for display in error messages). @@ -37,7 +38,7 @@ class AbstractModelChecker { * @param checkTask The task for which to check whether the model checker can handle it. * @return True iff the model checker can check the given task. */ - virtual bool canHandle(CheckTask const& checkTask) const = 0; + virtual bool canHandle(CheckTask const& checkTask) const = 0; /*! * Checks the provided formula. @@ -45,89 +46,90 @@ class AbstractModelChecker { * @param checkTask The verification task to pursue. * @return The verification result. */ - virtual std::unique_ptr check(Environment const& env, CheckTask const& checkTask); + virtual std::unique_ptr check(Environment const& env, CheckTask const& checkTask); /*! * Checks the provided formula with the default environment. * TODO This function is obsolete as soon as the Environment is fully integrated. */ - std::unique_ptr check(CheckTask const& checkTask); + std::unique_ptr check(CheckTask const& checkTask); // The methods to compute probabilities for path formulas. - virtual std::unique_ptr computeProbabilities(Environment const& env, CheckTask const& checkTask); + virtual std::unique_ptr computeProbabilities(Environment const& env, CheckTask const& checkTask); virtual std::unique_ptr computeConditionalProbabilities(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr computeReachabilityProbabilities(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr computeGloballyProbabilities(Environment const& env, - CheckTask const& checkTask); - virtual std::unique_ptr computeNextProbabilities(Environment const& env, CheckTask const& checkTask); - virtual std::unique_ptr computeUntilProbabilities(Environment const& env, CheckTask const& checkTask); + CheckTask const& checkTask); + virtual std::unique_ptr computeNextProbabilities(Environment const& env, CheckTask const& checkTask); + virtual std::unique_ptr computeUntilProbabilities(Environment const& env, + CheckTask const& checkTask); virtual std::unique_ptr computeHOAPathProbabilities(Environment const& env, - CheckTask const& checkTask); - virtual std::unique_ptr computeLTLProbabilities(Environment const& env, CheckTask const& checkTask); - std::unique_ptr computeStateFormulaProbabilities(Environment const& env, CheckTask const& checkTask); + CheckTask const& checkTask); + virtual std::unique_ptr computeLTLProbabilities(Environment const& env, CheckTask const& checkTask); + std::unique_ptr computeStateFormulaProbabilities(Environment const& env, CheckTask const& checkTask); // The methods to compute the rewards for path formulas. virtual std::unique_ptr computeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr computeConditionalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask); + CheckTask const& checkTask); // The methods to compute the long-run average probabilities and timing measures. virtual std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr computeTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask); + CheckTask const& checkTask); // The methods to check state formulas. - virtual std::unique_ptr checkStateFormula(Environment const& env, CheckTask const& checkTask); + virtual std::unique_ptr checkStateFormula(Environment const& env, CheckTask const& checkTask); virtual std::unique_ptr checkAtomicExpressionFormula(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr checkAtomicLabelFormula(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr checkBinaryBooleanStateFormula(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr checkBooleanLiteralFormula(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr checkProbabilityOperatorFormula(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr checkRewardOperatorFormula(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); virtual std::unique_ptr checkTimeOperatorFormula(Environment const& env, - CheckTask const& checkTask); - virtual std::unique_ptr checkLongRunAverageOperatorFormula(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); + virtual std::unique_ptr checkLongRunAverageOperatorFormula( + Environment const& env, CheckTask const& checkTask); virtual std::unique_ptr checkUnaryBooleanStateFormula(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); // The methods to check multi-objective formulas. virtual std::unique_ptr checkMultiObjectiveFormula(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); // The methods to check quantile formulas. - virtual std::unique_ptr checkQuantileFormula(Environment const& env, CheckTask const& checkTask); + virtual std::unique_ptr checkQuantileFormula(Environment const& env, CheckTask const& checkTask); // The methods to check lexicographic LTL formulae virtual std::unique_ptr checkLexObjectiveFormula(Environment const& env, - CheckTask const& checkTask); + CheckTask const& checkTask); // The methods to check game formulas. - virtual std::unique_ptr checkGameFormula(Environment const& env, CheckTask const& checkTask); + virtual std::unique_ptr checkGameFormula(Environment const& env, CheckTask const& checkTask); }; } // namespace modelchecker } // namespace storm diff --git a/src/storm/modelchecker/CheckTask.h b/src/storm/modelchecker/CheckTask.h index 028ffbee10..7fb6697610 100644 --- a/src/storm/modelchecker/CheckTask.h +++ b/src/storm/modelchecker/CheckTask.h @@ -39,6 +39,7 @@ class CheckTask { this->onlyInitialStatesRelevant = onlyInitialStatesRelevant; this->produceSchedulers = false; this->qualitative = false; + this->robustUncertainty = true; updateOperatorInformation(); } @@ -50,7 +51,8 @@ class CheckTask { template CheckTask substituteFormula(NewFormulaType const& newFormula) const { CheckTask result(newFormula, this->optimizationDirection, this->playerCoalition, this->rewardModel, - this->onlyInitialStatesRelevant, this->bound, this->qualitative, this->produceSchedulers, this->hint); + this->onlyInitialStatesRelevant, this->bound, this->qualitative, this->produceSchedulers, this->hint, + this->robustUncertainty); result.updateOperatorInformation(); return result; } @@ -128,7 +130,8 @@ class CheckTask { template CheckTask convertValueType() const { return CheckTask(this->formula, this->optimizationDirection, this->playerCoalition, this->rewardModel, - this->onlyInitialStatesRelevant, this->bound, this->qualitative, this->produceSchedulers, this->hint); + this->onlyInitialStatesRelevant, this->bound, this->qualitative, this->produceSchedulers, this->hint, + this->robustUncertainty); } /*! @@ -302,6 +305,14 @@ class CheckTask { return this->substituteFormula(this->getFormula()); } + bool getRobustUncertainty() const { + return robustUncertainty; + } + + void setRobustUncertainty(bool robust = true) { + robustUncertainty = robust; + } + private: /*! * Creates a task object with the given options. @@ -320,7 +331,8 @@ class CheckTask { */ CheckTask(std::reference_wrapper const& formula, boost::optional const& optimizationDirection, boost::optional playerCoalition, boost::optional const& rewardModel, bool onlyInitialStatesRelevant, - boost::optional const& bound, bool qualitative, bool produceSchedulers, std::shared_ptr const& hint) + boost::optional const& bound, bool qualitative, bool produceSchedulers, std::shared_ptr const& hint, + bool robust) : formula(formula), optimizationDirection(optimizationDirection), playerCoalition(playerCoalition), @@ -329,7 +341,8 @@ class CheckTask { bound(bound), qualitative(qualitative), produceSchedulers(produceSchedulers), - hint(hint) { + hint(hint), + robustUncertainty(robust) { // Intentionally left empty. } @@ -360,6 +373,9 @@ class CheckTask { // A hint that might contain information that speeds up the modelchecking process (if supported by the model checker) std::shared_ptr hint; + + /// Whether uncertainty should be resolved robust (standard) or angelically. + bool robustUncertainty; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/helper/finitehorizon/SparseDeterministicStepBoundedHorizonHelper.h b/src/storm/modelchecker/helper/finitehorizon/SparseDeterministicStepBoundedHorizonHelper.h index 848b982a04..42eb687725 100644 --- a/src/storm/modelchecker/helper/finitehorizon/SparseDeterministicStepBoundedHorizonHelper.h +++ b/src/storm/modelchecker/helper/finitehorizon/SparseDeterministicStepBoundedHorizonHelper.h @@ -1,7 +1,7 @@ #pragma once #include "storm/modelchecker/hints/ModelCheckerHint.h" -#include "storm/modelchecker/prctl/helper/SolutionType.h" +#include "storm/modelchecker/prctl/helper/SemanticSolutionType.h" #include "storm/solver/SolveGoal.h" #include "storm/storage/SparseMatrix.h" #include "storm/utility/solver.h" diff --git a/src/storm/modelchecker/helper/finitehorizon/SparseNondeterministicStepBoundedHorizonHelper.h b/src/storm/modelchecker/helper/finitehorizon/SparseNondeterministicStepBoundedHorizonHelper.h index ea5098c487..fae2a12eae 100644 --- a/src/storm/modelchecker/helper/finitehorizon/SparseNondeterministicStepBoundedHorizonHelper.h +++ b/src/storm/modelchecker/helper/finitehorizon/SparseNondeterministicStepBoundedHorizonHelper.h @@ -1,7 +1,7 @@ #pragma once #include "storm/modelchecker/hints/ModelCheckerHint.h" -#include "storm/modelchecker/prctl/helper/SolutionType.h" +#include "storm/modelchecker/prctl/helper/SemanticSolutionType.h" #include "storm/solver/SolveGoal.h" #include "storm/storage/SparseMatrix.h" #include "storm/utility/solver.h" diff --git a/src/storm/modelchecker/hints/ExplicitModelCheckerHint.cpp b/src/storm/modelchecker/hints/ExplicitModelCheckerHint.cpp index 9fbf7dfa13..131cbbb083 100644 --- a/src/storm/modelchecker/hints/ExplicitModelCheckerHint.cpp +++ b/src/storm/modelchecker/hints/ExplicitModelCheckerHint.cpp @@ -120,6 +120,7 @@ void ExplicitModelCheckerHint::setNoEndComponentsInMaybeStates(bool v template class ExplicitModelCheckerHint; template class ExplicitModelCheckerHint; template class ExplicitModelCheckerHint; +template class ExplicitModelCheckerHint; } // namespace modelchecker } // namespace storm diff --git a/src/storm/modelchecker/hints/ModelCheckerHint.cpp b/src/storm/modelchecker/hints/ModelCheckerHint.cpp index 5a40d62dea..0a5fbefcfa 100644 --- a/src/storm/modelchecker/hints/ModelCheckerHint.cpp +++ b/src/storm/modelchecker/hints/ModelCheckerHint.cpp @@ -29,6 +29,8 @@ template ExplicitModelCheckerHint const& ModelCheckerHint template ExplicitModelCheckerHint& ModelCheckerHint::asExplicitModelCheckerHint(); template ExplicitModelCheckerHint const& ModelCheckerHint::asExplicitModelCheckerHint() const; template ExplicitModelCheckerHint& ModelCheckerHint::asExplicitModelCheckerHint(); +template ExplicitModelCheckerHint const& ModelCheckerHint::asExplicitModelCheckerHint() const; +template ExplicitModelCheckerHint& ModelCheckerHint::asExplicitModelCheckerHint(); } // namespace modelchecker } // namespace storm diff --git a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp index bbaecdc2bf..daaa680c4f 100644 --- a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp @@ -42,61 +42,70 @@ SparseMdpPrctlModelChecker::SparseMdpPrctlModelChecker(Spars } template -bool SparseMdpPrctlModelChecker::canHandleStatic(CheckTask const& checkTask, +bool SparseMdpPrctlModelChecker::canHandleStatic(CheckTask const& checkTask, bool* requiresSingleInitialState) { storm::logic::Formula const& formula = checkTask.getFormula(); - if (formula.isInFragment(storm::logic::prctlstar() - .setLongRunAverageRewardFormulasAllowed(true) - .setLongRunAverageProbabilitiesAllowed(true) - .setConditionalProbabilityFormulasAllowed(true) - .setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true) - .setTotalRewardFormulasAllowed(true) - .setRewardBoundedUntilFormulasAllowed(true) - .setRewardBoundedCumulativeRewardFormulasAllowed(true) - .setMultiDimensionalBoundedUntilFormulasAllowed(true) - .setMultiDimensionalCumulativeRewardFormulasAllowed(true) - .setTimeOperatorsAllowed(true) - .setReachbilityTimeFormulasAllowed(true) - .setRewardAccumulationAllowed(true))) { - return true; - } else if (checkTask.isOnlyInitialStatesRelevantSet()) { - auto multiObjectiveFragment = storm::logic::multiObjective() - .setTimeAllowed(true) - .setCumulativeRewardFormulasAllowed(true) - .setTimeBoundedCumulativeRewardFormulasAllowed(true) - .setStepBoundedCumulativeRewardFormulasAllowed(true) - .setRewardBoundedCumulativeRewardFormulasAllowed(true) - .setTimeBoundedUntilFormulasAllowed(true) - .setStepBoundedUntilFormulasAllowed(true) - .setRewardBoundedUntilFormulasAllowed(true) - .setMultiDimensionalBoundedUntilFormulasAllowed(true) - .setMultiDimensionalCumulativeRewardFormulasAllowed(true) - .setRewardAccumulationAllowed(true); - auto lexObjectiveFragment = storm::logic::lexObjective() - .setHOAPathFormulasAllowed(true) - .setCumulativeRewardFormulasAllowed(true) - .setTimeBoundedCumulativeRewardFormulasAllowed(true) - .setStepBoundedCumulativeRewardFormulasAllowed(true) - .setRewardBoundedCumulativeRewardFormulasAllowed(true) - .setTimeBoundedUntilFormulasAllowed(true) - .setStepBoundedUntilFormulasAllowed(true) - .setRewardBoundedUntilFormulasAllowed(true) - .setMultiDimensionalBoundedUntilFormulasAllowed(true) - .setMultiDimensionalCumulativeRewardFormulasAllowed(true) - .setRewardAccumulationAllowed(true); - - if (formula.isInFragment(multiObjectiveFragment) || formula.isInFragment(storm::logic::quantiles()) || formula.isInFragment(lexObjectiveFragment)) { - if (requiresSingleInitialState) { - *requiresSingleInitialState = true; - } + if constexpr (std::is_same_v) { + if (formula.isInFragment(storm::logic::propositional())) { + return true; + } + if (formula.isInFragment(storm::logic::reachability())) { return true; } + } else { + if (formula.isInFragment(storm::logic::prctlstar() + .setLongRunAverageRewardFormulasAllowed(true) + .setLongRunAverageProbabilitiesAllowed(true) + .setConditionalProbabilityFormulasAllowed(true) + .setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true) + .setTotalRewardFormulasAllowed(true) + .setRewardBoundedUntilFormulasAllowed(true) + .setRewardBoundedCumulativeRewardFormulasAllowed(true) + .setMultiDimensionalBoundedUntilFormulasAllowed(true) + .setMultiDimensionalCumulativeRewardFormulasAllowed(true) + .setTimeOperatorsAllowed(true) + .setReachbilityTimeFormulasAllowed(true) + .setRewardAccumulationAllowed(true))) { + return true; + } else if (checkTask.isOnlyInitialStatesRelevantSet()) { + auto multiObjectiveFragment = storm::logic::multiObjective() + .setTimeAllowed(true) + .setCumulativeRewardFormulasAllowed(true) + .setTimeBoundedCumulativeRewardFormulasAllowed(true) + .setStepBoundedCumulativeRewardFormulasAllowed(true) + .setRewardBoundedCumulativeRewardFormulasAllowed(true) + .setTimeBoundedUntilFormulasAllowed(true) + .setStepBoundedUntilFormulasAllowed(true) + .setRewardBoundedUntilFormulasAllowed(true) + .setMultiDimensionalBoundedUntilFormulasAllowed(true) + .setMultiDimensionalCumulativeRewardFormulasAllowed(true) + .setRewardAccumulationAllowed(true); + auto lexObjectiveFragment = storm::logic::lexObjective() + .setHOAPathFormulasAllowed(true) + .setCumulativeRewardFormulasAllowed(true) + .setTimeBoundedCumulativeRewardFormulasAllowed(true) + .setStepBoundedCumulativeRewardFormulasAllowed(true) + .setRewardBoundedCumulativeRewardFormulasAllowed(true) + .setTimeBoundedUntilFormulasAllowed(true) + .setStepBoundedUntilFormulasAllowed(true) + .setRewardBoundedUntilFormulasAllowed(true) + .setMultiDimensionalBoundedUntilFormulasAllowed(true) + .setMultiDimensionalCumulativeRewardFormulasAllowed(true) + .setRewardAccumulationAllowed(true); + + if (formula.isInFragment(multiObjectiveFragment) || formula.isInFragment(storm::logic::quantiles()) || formula.isInFragment(lexObjectiveFragment)) { + if (requiresSingleInitialState) { + *requiresSingleInitialState = true; + } + return true; + } + } } return false; } template -bool SparseMdpPrctlModelChecker::canHandle(CheckTask const& checkTask) const { +bool SparseMdpPrctlModelChecker::canHandle(CheckTask const& checkTask) const { bool requiresSingleInitialState = false; if (canHandleStatic(checkTask, &requiresSingleInitialState)) { return !requiresSingleInitialState || this->getModel().getInitialStates().getNumberOfSetBits() == 1; @@ -107,56 +116,63 @@ bool SparseMdpPrctlModelChecker::canHandle(CheckTask std::unique_ptr SparseMdpPrctlModelChecker::computeBoundedUntilProbabilities( - Environment const& env, CheckTask const& checkTask) { - storm::logic::BoundedUntilFormula const& pathFormula = checkTask.getFormula(); - STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, - "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); - if (pathFormula.isMultiDimensional() || pathFormula.getTimeBoundReference().isRewardBound()) { - STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::InvalidOperationException, - "Checking non-trivial bounded until probabilities can only be computed for the initial states of the model."); - STORM_LOG_WARN_COND(!checkTask.isQualitativeSet(), "Checking non-trivial bounded until formulas is not optimized w.r.t. qualitative queries"); - storm::logic::OperatorInformation opInfo(checkTask.getOptimizationDirection()); - if (checkTask.isBoundSet()) { - opInfo.bound = checkTask.getBound(); - } - auto formula = std::make_shared(checkTask.getFormula().asSharedPointer(), opInfo); - helper::rewardbounded::MultiDimensionalRewardUnfolding rewardUnfolding(this->getModel(), formula); - auto numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeRewardBoundedValues( - env, checkTask.getOptimizationDirection(), rewardUnfolding, this->getModel().getInitialStates()); - return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + Environment const& env, CheckTask const& checkTask) { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We have not yet implemented bounded until with intervals"); + return nullptr; } else { - STORM_LOG_THROW(pathFormula.hasUpperBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have (a single) upper step bound."); - STORM_LOG_THROW(pathFormula.hasIntegerLowerBound(), storm::exceptions::InvalidPropertyException, "Formula lower step bound must be discrete/integral."); - STORM_LOG_THROW(pathFormula.hasIntegerUpperBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have discrete upper time bound."); - std::unique_ptr leftResultPointer = this->check(env, pathFormula.getLeftSubformula()); - std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); - ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); - ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - storm::modelchecker::helper::SparseNondeterministicStepBoundedHorizonHelper helper; - std::vector numericResult = - helper.compute(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), - this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), - pathFormula.getNonStrictLowerBound(), pathFormula.getNonStrictUpperBound(), checkTask.getHint()); - return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + storm::logic::BoundedUntilFormula const& pathFormula = checkTask.getFormula(); + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, + "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + if (pathFormula.isMultiDimensional() || pathFormula.getTimeBoundReference().isRewardBound()) { + STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::InvalidOperationException, + "Checking non-trivial bounded until probabilities can only be computed for the initial states of the model."); + STORM_LOG_WARN_COND(!checkTask.isQualitativeSet(), "Checking non-trivial bounded until formulas is not optimized w.r.t. qualitative queries"); + storm::logic::OperatorInformation opInfo(checkTask.getOptimizationDirection()); + if (checkTask.isBoundSet()) { + opInfo.bound = checkTask.getBound(); + } + auto formula = std::make_shared(checkTask.getFormula().asSharedPointer(), opInfo); + helper::rewardbounded::MultiDimensionalRewardUnfolding rewardUnfolding(this->getModel(), formula); + auto numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeRewardBoundedValues( + env, checkTask.getOptimizationDirection(), rewardUnfolding, this->getModel().getInitialStates()); + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + } else { + STORM_LOG_THROW(pathFormula.hasUpperBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have (a single) upper step bound."); + STORM_LOG_THROW(pathFormula.hasIntegerLowerBound(), storm::exceptions::InvalidPropertyException, + "Formula lower step bound must be discrete/integral."); + STORM_LOG_THROW(pathFormula.hasIntegerUpperBound(), storm::exceptions::InvalidPropertyException, + "Formula needs to have discrete upper time bound."); + std::unique_ptr leftResultPointer = this->check(env, pathFormula.getLeftSubformula()); + std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); + ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); + ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); + storm::modelchecker::helper::SparseNondeterministicStepBoundedHorizonHelper helper; + std::vector numericResult = + helper.compute(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), + this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), + pathFormula.getNonStrictLowerBound(), pathFormula.getNonStrictUpperBound(), checkTask.getHint()); + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + } } } template std::unique_ptr SparseMdpPrctlModelChecker::computeNextProbabilities( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::NextFormula const& pathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeNextProbabilities( + std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeNextProbabilities( env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector()); - return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } template std::unique_ptr SparseMdpPrctlModelChecker::computeUntilProbabilities( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::UntilFormula const& pathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); @@ -164,86 +180,94 @@ std::unique_ptr SparseMdpPrctlModelChecker::com std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeUntilProbabilities( - env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeUntilProbabilities( + env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), checkTask.getHint()); - std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); if (checkTask.isProduceSchedulersSet() && ret.scheduler) { - result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); + result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); } return result; } template std::unique_ptr SparseMdpPrctlModelChecker::computeGloballyProbabilities( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::GloballyFormula const& pathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeGloballyProbabilities( - env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeGloballyProbabilities( + env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet()); - std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); if (checkTask.isProduceSchedulersSet() && ret.scheduler) { - result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); + result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); } return result; } template std::unique_ptr SparseMdpPrctlModelChecker::computeHOAPathProbabilities( - Environment const& env, CheckTask const& checkTask) { - storm::logic::HOAPathFormula const& pathFormula = checkTask.getFormula(); - - storm::modelchecker::helper::SparseLTLHelper helper(this->getModel().getTransitionMatrix()); - storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); - - auto formulaChecker = [&](storm::logic::Formula const& formula) { - return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); - }; - auto apSets = helper.computeApSets(pathFormula.getAPMapping(), formulaChecker); - std::vector numericResult = helper.computeDAProductProbabilities(env, *pathFormula.readAutomaton(), apSets); - - std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(numericResult))); - if (checkTask.isProduceSchedulersSet()) { - result->asExplicitQuantitativeCheckResult().setScheduler( - std::make_unique>(helper.extractScheduler(this->getModel()))); - } + Environment const& env, CheckTask const& checkTask) { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We have not yet implemented automata-props with intervals"); + } else { + storm::logic::HOAPathFormula const& pathFormula = checkTask.getFormula(); - return result; + storm::modelchecker::helper::SparseLTLHelper helper(this->getModel().getTransitionMatrix()); + storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); + + auto formulaChecker = [&](storm::logic::Formula const& formula) { + return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); + }; + auto apSets = helper.computeApSets(pathFormula.getAPMapping(), formulaChecker); + std::vector numericResult = helper.computeDAProductProbabilities(env, *pathFormula.readAutomaton(), apSets); + + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + if (checkTask.isProduceSchedulersSet()) { + result->asExplicitQuantitativeCheckResult().setScheduler( + std::make_unique>(helper.extractScheduler(this->getModel()))); + } + + return result; + } } template std::unique_ptr SparseMdpPrctlModelChecker::computeLTLProbabilities( - Environment const& env, CheckTask const& checkTask) { - storm::logic::PathFormula const& pathFormula = checkTask.getFormula(); + Environment const& env, CheckTask const& checkTask) { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We have not yet implemented LTL with intervals"); + } else { + storm::logic::PathFormula const& pathFormula = checkTask.getFormula(); - STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, - "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, + "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); - storm::modelchecker::helper::SparseLTLHelper helper(this->getModel().getTransitionMatrix()); - storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); + storm::modelchecker::helper::SparseLTLHelper helper(this->getModel().getTransitionMatrix()); + storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); - auto formulaChecker = [&](storm::logic::Formula const& formula) { - return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); - }; - std::vector numericResult = helper.computeLTLProbabilities(env, pathFormula, formulaChecker); + auto formulaChecker = [&](storm::logic::Formula const& formula) { + return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); + }; + std::vector numericResult = helper.computeLTLProbabilities(env, pathFormula, formulaChecker); - std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(numericResult))); - if (checkTask.isProduceSchedulersSet()) { - result->asExplicitQuantitativeCheckResult().setScheduler( - std::make_unique>(helper.extractScheduler(this->getModel()))); - } + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + if (checkTask.isProduceSchedulersSet()) { + result->asExplicitQuantitativeCheckResult().setScheduler( + std::make_unique>(helper.extractScheduler(this->getModel()))); + } - return result; + return result; + } } template std::unique_ptr SparseMdpPrctlModelChecker::computeConditionalProbabilities( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::ConditionalFormula const& conditionalFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); @@ -259,188 +283,212 @@ std::unique_ptr SparseMdpPrctlModelChecker::com ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - return storm::modelchecker::helper::SparseMdpPrctlHelper::computeConditionalProbabilities( - env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), + return storm::modelchecker::helper::SparseMdpPrctlHelper::computeConditionalProbabilities( + env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector()); } template std::unique_ptr SparseMdpPrctlModelChecker::computeCumulativeRewards( - Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); if (rewardPathFormula.isMultiDimensional() || rewardPathFormula.getTimeBoundReference().isRewardBound()) { - STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::InvalidOperationException, - "Checking reward bounded cumulative reward formulas can only be done for the initial states of the model."); - STORM_LOG_THROW(!checkTask.getFormula().hasRewardAccumulation(), storm::exceptions::InvalidOperationException, - "Checking reward bounded cumulative reward formulas is not supported if reward accumulations are given."); - STORM_LOG_WARN_COND(!checkTask.isQualitativeSet(), "Checking reward bounded until formulas is not optimized w.r.t. qualitative queries"); - storm::logic::OperatorInformation opInfo(checkTask.getOptimizationDirection()); - if (checkTask.isBoundSet()) { - opInfo.bound = checkTask.getBound(); + if constexpr (std::is_same_v) { + throw exceptions::NotImplementedException() << "Multi-reward bounded is not supported with interval models"; + } else { + STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::InvalidOperationException, + "Checking reward bounded cumulative reward formulas can only be done for the initial states of the model."); + STORM_LOG_THROW(!checkTask.getFormula().hasRewardAccumulation(), storm::exceptions::InvalidOperationException, + "Checking reward bounded cumulative reward formulas is not supported if reward accumulations are given."); + STORM_LOG_WARN_COND(!checkTask.isQualitativeSet(), "Checking reward bounded until formulas is not optimized w.r.t. qualitative queries"); + storm::logic::OperatorInformation opInfo(checkTask.getOptimizationDirection()); + if (checkTask.isBoundSet()) { + opInfo.bound = checkTask.getBound(); + } + auto formula = std::make_shared(checkTask.getFormula().asSharedPointer(), checkTask.getRewardModel(), opInfo); + helper::rewardbounded::MultiDimensionalRewardUnfolding rewardUnfolding(this->getModel(), formula); + auto numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeRewardBoundedValues( + env, checkTask.getOptimizationDirection(), rewardUnfolding, this->getModel().getInitialStates()); + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } - auto formula = std::make_shared(checkTask.getFormula().asSharedPointer(), checkTask.getRewardModel(), opInfo); - helper::rewardbounded::MultiDimensionalRewardUnfolding rewardUnfolding(this->getModel(), formula); - auto numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeRewardBoundedValues( - env, checkTask.getOptimizationDirection(), rewardUnfolding, this->getModel().getInitialStates()); - return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } else { STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); auto rewardModel = storm::utility::createFilteredRewardModel(this->getModel(), checkTask); - std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeCumulativeRewards( - env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), rewardModel.get(), + std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeCumulativeRewards( + env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), rewardModel.get(), rewardPathFormula.getNonStrictBound()); - return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } } template std::unique_ptr SparseMdpPrctlModelChecker::computeInstantaneousRewards( - Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeInstantaneousRewards( - env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), + std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeInstantaneousRewards( + env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); - return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } template std::unique_ptr SparseMdpPrctlModelChecker::computeReachabilityRewards( - Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); auto rewardModel = storm::utility::createFilteredRewardModel(this->getModel(), checkTask); - auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeReachabilityRewards( - env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeReachabilityRewards( + env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), rewardModel.get(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), checkTask.getHint()); - std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); if (checkTask.isProduceSchedulersSet() && ret.scheduler) { - result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); + result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); } return result; } template std::unique_ptr SparseMdpPrctlModelChecker::computeReachabilityTimes( - Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeReachabilityTimes( - env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeReachabilityTimes( + env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), checkTask.getHint()); - std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); if (checkTask.isProduceSchedulersSet() && ret.scheduler) { - result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); + result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); } return result; } template std::unique_ptr SparseMdpPrctlModelChecker::computeTotalRewards( - Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); auto rewardModel = storm::utility::createFilteredRewardModel(this->getModel(), checkTask); - auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeTotalRewards( - env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeTotalRewards( + env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), rewardModel.get(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), checkTask.getHint()); - std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); if (checkTask.isProduceSchedulersSet() && ret.scheduler) { - result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); + result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); } return result; } template std::unique_ptr SparseMdpPrctlModelChecker::computeLongRunAverageProbabilities( - Environment const& env, CheckTask const& checkTask) { - storm::logic::StateFormula const& stateFormula = checkTask.getFormula(); - STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, - "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); - std::unique_ptr subResultPointer = this->check(env, stateFormula); - ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - - storm::modelchecker::helper::SparseNondeterministicInfiniteHorizonHelper helper(this->getModel().getTransitionMatrix()); - storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); - auto values = helper.computeLongRunAverageProbabilities(env, subResult.getTruthValuesVector()); - - std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(values))); - if (checkTask.isProduceSchedulersSet()) { - result->asExplicitQuantitativeCheckResult().setScheduler(std::make_unique>(helper.extractScheduler())); + Environment const& env, CheckTask const& checkTask) { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We have not yet implemented LRA probabilities with intervals"); + } else { + storm::logic::StateFormula const& stateFormula = checkTask.getFormula(); + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, + "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + std::unique_ptr subResultPointer = this->check(env, stateFormula); + ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); + + storm::modelchecker::helper::SparseNondeterministicInfiniteHorizonHelper helper(this->getModel().getTransitionMatrix()); + storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); + auto values = helper.computeLongRunAverageProbabilities(env, subResult.getTruthValuesVector()); + + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(values))); + if (checkTask.isProduceSchedulersSet()) { + result->asExplicitQuantitativeCheckResult().setScheduler( + std::make_unique>(helper.extractScheduler())); + } + return result; } - return result; } template std::unique_ptr SparseMdpPrctlModelChecker::computeLongRunAverageRewards( Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask) { - STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, - "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); - auto rewardModel = storm::utility::createFilteredRewardModel(this->getModel(), checkTask); - storm::modelchecker::helper::SparseNondeterministicInfiniteHorizonHelper helper(this->getModel().getTransitionMatrix()); - storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); - auto values = helper.computeLongRunAverageRewards(env, rewardModel.get()); - std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(values))); - if (checkTask.isProduceSchedulersSet()) { - result->asExplicitQuantitativeCheckResult().setScheduler(std::make_unique>(helper.extractScheduler())); + CheckTask const& checkTask) { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We have not yet implemented lra with intervals"); + } else { + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, + "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + auto rewardModel = storm::utility::createFilteredRewardModel(this->getModel(), checkTask); + storm::modelchecker::helper::SparseNondeterministicInfiniteHorizonHelper helper(this->getModel().getTransitionMatrix()); + storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); + auto values = helper.computeLongRunAverageRewards(env, rewardModel.get()); + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(values))); + if (checkTask.isProduceSchedulersSet()) { + result->asExplicitQuantitativeCheckResult().setScheduler( + std::make_unique>(helper.extractScheduler())); + } + return result; } - return result; } template std::unique_ptr SparseMdpPrctlModelChecker::checkMultiObjectiveFormula( - Environment const& env, CheckTask const& checkTask) { - return multiobjective::performMultiObjectiveModelChecking(env, this->getModel(), checkTask.getFormula()); + Environment const& env, CheckTask const& checkTask) { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We have not yet implemented multi-objective with intervals"); + } else { + return multiobjective::performMultiObjectiveModelChecking(env, this->getModel(), checkTask.getFormula()); + } } template std::unique_ptr SparseMdpPrctlModelChecker::checkLexObjectiveFormula( - const Environment& env, const CheckTask& checkTask) { - auto formulaChecker = [&](storm::logic::Formula const& formula) { - return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); - }; - auto ret = lexicographic::check(env, this->getModel(), checkTask, formulaChecker); - std::unique_ptr result(new LexicographicCheckResult(ret.values, *this->getModel().getInitialStates().begin())); - return result; + const Environment& env, const CheckTask& checkTask) { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We have not yet implemented lexicographic model checking with intervals"); + } else { + auto formulaChecker = [&](storm::logic::Formula const& formula) { + return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); + }; + auto ret = lexicographic::check(env, this->getModel(), checkTask, formulaChecker); + std::unique_ptr result(new LexicographicCheckResult(ret.values, *this->getModel().getInitialStates().begin())); + return result; + } } template std::unique_ptr SparseMdpPrctlModelChecker::checkQuantileFormula( - Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::InvalidOperationException, - "Computing quantiles is only supported for the initial states of a model."); - STORM_LOG_THROW(this->getModel().getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::InvalidOperationException, - "Quantiles not supported on models with multiple initial states."); - uint64_t initialState = *this->getModel().getInitialStates().begin(); - - helper::rewardbounded::QuantileHelper qHelper(this->getModel(), checkTask.getFormula()); - auto res = qHelper.computeQuantile(env); - - if (res.size() == 1 && res.front().size() == 1) { - return std::unique_ptr(new ExplicitQuantitativeCheckResult(initialState, std::move(res.front().front()))); + Environment const& env, CheckTask const& checkTask) { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We have not yet implemented quantile formulas with intervals"); } else { - return std::unique_ptr(new ExplicitParetoCurveCheckResult(initialState, std::move(res))); + STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::InvalidOperationException, + "Computing quantiles is only supported for the initial states of a model."); + STORM_LOG_THROW(this->getModel().getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::InvalidOperationException, + "Quantiles not supported on models with multiple initial states."); + uint64_t initialState = *this->getModel().getInitialStates().begin(); + + helper::rewardbounded::QuantileHelper qHelper(this->getModel(), checkTask.getFormula()); + auto res = qHelper.computeQuantile(env); + + if (res.size() == 1 && res.front().size() == 1) { + return std::unique_ptr(new ExplicitQuantitativeCheckResult(initialState, std::move(res.front().front()))); + } else { + return std::unique_ptr(new ExplicitParetoCurveCheckResult(initialState, std::move(res))); + } } } template class SparseMdpPrctlModelChecker>; - -#ifdef STORM_HAVE_CARL template class SparseMdpPrctlModelChecker>; -#endif +template class SparseMdpPrctlModelChecker>; } // namespace modelchecker } // namespace storm diff --git a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h index 4b340f0349..01f5707b65 100644 --- a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h @@ -1,5 +1,4 @@ -#ifndef STORM_MODELCHECKER_SPARSEMDPPRCTLMODELCHECKER_H_ -#define STORM_MODELCHECKER_SPARSEMDPPRCTLMODELCHECKER_H_ +#pragma once #include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h" #include "storm/models/sparse/Mdp.h" @@ -15,6 +14,7 @@ class SparseMdpPrctlModelChecker : public SparsePropositionalModelChecker, double, ValueType>::type; explicit SparseMdpPrctlModelChecker(SparseMdpModelType const& model); @@ -22,47 +22,46 @@ class SparseMdpPrctlModelChecker : public SparsePropositionalModelChecker const& checkTask, bool* requiresSingleInitialState = nullptr); + static bool canHandleStatic(CheckTask const& checkTask, bool* requiresSingleInitialState = nullptr); // The implemented methods of the AbstractModelChecker interface. - virtual bool canHandle(CheckTask const& checkTask) const override; + virtual bool canHandle(CheckTask const& checkTask) const override; virtual std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr computeNextProbabilities(Environment const& env, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr computeUntilProbabilities(Environment const& env, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr computeGloballyProbabilities(Environment const& env, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr computeConditionalProbabilities(Environment const& env, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask) override; - virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; + virtual std::unique_ptr computeInstantaneousRewards( + Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, + CheckTask const& checkTask) override; virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageRewards( Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr computeLTLProbabilities(Environment const& env, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr computeHOAPathProbabilities(Environment const& env, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr checkMultiObjectiveFormula(Environment const& env, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr checkLexObjectiveFormula(Environment const& env, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr checkQuantileFormula(Environment const& env, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; }; } // namespace modelchecker } // namespace storm - -#endif /* STORM_MODELCHECKER_SPARSEMDPPRCTLMODELCHECKER_H_ */ diff --git a/src/storm/modelchecker/prctl/helper/BaierUpperRewardBoundsComputer.cpp b/src/storm/modelchecker/prctl/helper/BaierUpperRewardBoundsComputer.cpp index 7fa6636a73..0dbc69b979 100644 --- a/src/storm/modelchecker/prctl/helper/BaierUpperRewardBoundsComputer.cpp +++ b/src/storm/modelchecker/prctl/helper/BaierUpperRewardBoundsComputer.cpp @@ -211,5 +211,4 @@ ValueType BaierUpperRewardBoundsComputer::computeUpperBound() { template class BaierUpperRewardBoundsComputer; template class BaierUpperRewardBoundsComputer; - } // namespace storm::modelchecker::helper diff --git a/src/storm/modelchecker/prctl/helper/SolutionType.h b/src/storm/modelchecker/prctl/helper/SemanticSolutionType.h similarity index 63% rename from src/storm/modelchecker/prctl/helper/SolutionType.h rename to src/storm/modelchecker/prctl/helper/SemanticSolutionType.h index 50f38a9315..5092b26d1f 100644 --- a/src/storm/modelchecker/prctl/helper/SolutionType.h +++ b/src/storm/modelchecker/prctl/helper/SemanticSolutionType.h @@ -3,7 +3,7 @@ namespace storm { namespace modelchecker { namespace helper { -enum class SolutionType { UntilProbabilities, ExpectedRewards }; +enum class SemanticSolutionType { UntilProbabilities, ExpectedRewards }; } } // namespace modelchecker } // namespace storm diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpEndComponentInformation.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpEndComponentInformation.cpp index 643e590211..e4f9a7be27 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpEndComponentInformation.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpEndComponentInformation.cpp @@ -8,6 +8,8 @@ #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/adapters/RationalNumberAdapter.h" +#include "storm/exceptions/NotImplementedException.h" + namespace storm { namespace modelchecker { namespace helper { @@ -103,7 +105,11 @@ SparseMdpEndComponentInformation SparseMdpEndComponentInformation const* summand, storm::storage::SparseMatrix& submatrix, std::vector* columnSumVector, std::vector* summandResultVector, bool gatherExitChoices) { SparseMdpEndComponentInformation result(endComponentDecomposition, maybeStates); - + // TODO: Just like SparseMdpPrctlHelper::computeFixedPointSystemUntilProbabilities, this method must be adapted for intervals. + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, + "We do not support the elimination of end components and the creation of an adequate equation system with interval models."); + } // (1) Compute the number of maybe states not in ECs before any other maybe state. std::vector const& maybeStatesNotInEcBefore = result.getNumberOfMaybeStatesNotInEcBeforeIndices(); uint64_t numberOfStates = result.numberOfMaybeStatesNotInEc + result.numberOfEc; @@ -241,6 +247,11 @@ SparseMdpEndComponentInformation SparseMdpEndComponentInformation const& transitionMatrix, std::vector& rhsVector, storm::storage::BitVector const& maybeStates, storm::storage::SparseMatrix& submatrix, std::vector& subvector, bool gatherExitChoices) { SparseMdpEndComponentInformation result(endComponentDecomposition, maybeStates); + // TODO: Just like SparseMdpPrctlHelper::computeFixedPointSystemUntilProbabilities, this method must be adapted for intervals. + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, + "We do not support the elimination of end components and the creation of an adequate equation system with interval models."); + } // (1) Compute the number of maybe states not in ECs before any other maybe state. std::vector maybeStatesNotInEcBefore = result.getNumberOfMaybeStatesNotInEcBeforeIndices(); @@ -361,7 +372,8 @@ void SparseMdpEndComponentInformation::setValues(std::vector -void SparseMdpEndComponentInformation::setScheduler(storm::storage::Scheduler& scheduler, storm::storage::BitVector const& maybeStates, +template +void SparseMdpEndComponentInformation::setScheduler(storm::storage::Scheduler& scheduler, storm::storage::BitVector const& maybeStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& fromResult) { @@ -408,11 +420,26 @@ void SparseMdpEndComponentInformation::setScheduler(storm::storage::S } template class SparseMdpEndComponentInformation; - -#ifdef STORM_HAVE_CARL template class SparseMdpEndComponentInformation; +template class SparseMdpEndComponentInformation; + +template void SparseMdpEndComponentInformation::setScheduler(storm::storage::Scheduler& scheduler, storm::storage::BitVector const& maybeStates, + storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::SparseMatrix const& backwardTransitions, + std::vector const& fromResult); + +template void SparseMdpEndComponentInformation::setScheduler( + storm::storage::Scheduler& scheduler, storm::storage::BitVector const& maybeStates, + storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, + std::vector const& fromResult); + +template void SparseMdpEndComponentInformation::setScheduler(storm::storage::Scheduler& scheduler, + storm::storage::BitVector const& maybeStates, + storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::SparseMatrix const& backwardTransitions, + std::vector const& fromResult); + // template class SparseMdpEndComponentInformation; -#endif } // namespace helper } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpEndComponentInformation.h b/src/storm/modelchecker/prctl/helper/SparseMdpEndComponentInformation.h index d3fd2cfeb2..7c9b78b852 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpEndComponentInformation.h +++ b/src/storm/modelchecker/prctl/helper/SparseMdpEndComponentInformation.h @@ -67,7 +67,9 @@ class SparseMdpEndComponentInformation { storm::storage::SparseMatrix& submatrix, std::vector& subvector, bool gatherExitChoices = false); void setValues(std::vector& result, storm::storage::BitVector const& maybeStates, std::vector const& fromResult); - void setScheduler(storm::storage::Scheduler& scheduler, storm::storage::BitVector const& maybeStates, + + template + void setScheduler(storm::storage::Scheduler& scheduler, storm::storage::BitVector const& maybeStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& fromResult); diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index 0d09e217d2..d1f81dfede 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -2,6 +2,8 @@ #include +#include "storm/modelchecker/prctl/helper/SemanticSolutionType.h" + #include "storm/modelchecker/hints/ExplicitModelCheckerHint.h" #include "storm/modelchecker/prctl/helper/BaierUpperRewardBoundsComputer.h" #include "storm/modelchecker/prctl/helper/DsMpiUpperRewardBoundsComputer.h" @@ -52,117 +54,125 @@ namespace storm { namespace modelchecker { namespace helper { -template -std::map SparseMdpPrctlHelper::computeRewardBoundedValues( +template +std::map SparseMdpPrctlHelper::computeRewardBoundedValues( Environment const& env, OptimizationDirection dir, rewardbounded::MultiDimensionalRewardUnfolding& rewardUnfolding, storm::storage::BitVector const& initialStates) { - storm::utility::Stopwatch swAll(true), swBuild, swCheck; - - // Get lower and upper bounds for the solution. - auto lowerBound = rewardUnfolding.getLowerObjectiveBound(); - auto upperBound = rewardUnfolding.getUpperObjectiveBound(); - - // Initialize epoch models - auto initEpoch = rewardUnfolding.getStartEpoch(); - auto epochOrder = rewardUnfolding.getEpochComputationOrder(initEpoch); - - // initialize data that will be needed for each epoch - std::vector x, b; - std::unique_ptr> minMaxSolver; - - ValueType precision = rewardUnfolding.getRequiredEpochModelPrecision( - initEpoch, storm::utility::convertNumber(storm::settings::getModule().getPrecision())); - Environment preciseEnv = env; - preciseEnv.solver().minMax().setPrecision(storm::utility::convertNumber(precision)); - - // In case of cdf export we store the necessary data. - std::vector> cdfData; - - storm::utility::ProgressMeasurement progress("epochs"); - progress.setMaxCount(epochOrder.size()); - progress.startNewMeasurement(0); - uint64_t numCheckedEpochs = 0; - for (auto const& epoch : epochOrder) { - swBuild.start(); - auto& epochModel = rewardUnfolding.setCurrentEpoch(epoch); - swBuild.stop(); - swCheck.start(); - rewardUnfolding.setSolutionForCurrentEpoch(epochModel.analyzeSingleObjective(preciseEnv, dir, x, b, minMaxSolver, lowerBound, upperBound)); - swCheck.stop(); - if (storm::settings::getModule().isExportCdfSet() && - !rewardUnfolding.getEpochManager().hasBottomDimension(epoch)) { - std::vector cdfEntry; - for (uint64_t i = 0; i < rewardUnfolding.getEpochManager().getDimensionCount(); ++i) { - uint64_t offset = rewardUnfolding.getDimension(i).boundType == helper::rewardbounded::DimensionBoundType::LowerBound ? 1 : 0; - cdfEntry.push_back(storm::utility::convertNumber(rewardUnfolding.getEpochManager().getDimensionOfEpoch(epoch, i) + offset) * - rewardUnfolding.getDimension(i).scalingFactor); + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support computing reward bounded values with interval models."); + } else { + storm::utility::Stopwatch swAll(true), swBuild, swCheck; + + // Get lower and upper bounds for the solution. + auto lowerBound = rewardUnfolding.getLowerObjectiveBound(); + auto upperBound = rewardUnfolding.getUpperObjectiveBound(); + + // Initialize epoch models + auto initEpoch = rewardUnfolding.getStartEpoch(); + auto epochOrder = rewardUnfolding.getEpochComputationOrder(initEpoch); + + // initialize data that will be needed for each epoch + std::vector x, b; + std::unique_ptr> minMaxSolver; + + ValueType precision = rewardUnfolding.getRequiredEpochModelPrecision( + initEpoch, storm::utility::convertNumber(storm::settings::getModule().getPrecision())); + Environment preciseEnv = env; + preciseEnv.solver().minMax().setPrecision(storm::utility::convertNumber(precision)); + + // In case of cdf export we store the necessary data. + std::vector> cdfData; + + storm::utility::ProgressMeasurement progress("epochs"); + progress.setMaxCount(epochOrder.size()); + progress.startNewMeasurement(0); + uint64_t numCheckedEpochs = 0; + for (auto const& epoch : epochOrder) { + swBuild.start(); + auto& epochModel = rewardUnfolding.setCurrentEpoch(epoch); + swBuild.stop(); + swCheck.start(); + rewardUnfolding.setSolutionForCurrentEpoch(epochModel.analyzeSingleObjective(preciseEnv, dir, x, b, minMaxSolver, lowerBound, upperBound)); + swCheck.stop(); + if (storm::settings::getModule().isExportCdfSet() && + !rewardUnfolding.getEpochManager().hasBottomDimension(epoch)) { + std::vector cdfEntry; + for (uint64_t i = 0; i < rewardUnfolding.getEpochManager().getDimensionCount(); ++i) { + uint64_t offset = rewardUnfolding.getDimension(i).boundType == helper::rewardbounded::DimensionBoundType::LowerBound ? 1 : 0; + cdfEntry.push_back(storm::utility::convertNumber(rewardUnfolding.getEpochManager().getDimensionOfEpoch(epoch, i) + offset) * + rewardUnfolding.getDimension(i).scalingFactor); + } + cdfEntry.push_back(rewardUnfolding.getInitialStateResult(epoch)); + cdfData.push_back(std::move(cdfEntry)); + } + ++numCheckedEpochs; + progress.updateProgress(numCheckedEpochs); + if (storm::utility::resources::isTerminate()) { + break; } - cdfEntry.push_back(rewardUnfolding.getInitialStateResult(epoch)); - cdfData.push_back(std::move(cdfEntry)); } - ++numCheckedEpochs; - progress.updateProgress(numCheckedEpochs); - if (storm::utility::resources::isTerminate()) { - break; + + std::map result; + for (auto initState : initialStates) { + result[initState] = rewardUnfolding.getInitialStateResult(initEpoch, initState); } - } - std::map result; - for (auto initState : initialStates) { - result[initState] = rewardUnfolding.getInitialStateResult(initEpoch, initState); - } + swAll.stop(); - swAll.stop(); + if (storm::settings::getModule().isExportCdfSet()) { + std::vector headers; + for (uint64_t i = 0; i < rewardUnfolding.getEpochManager().getDimensionCount(); ++i) { + headers.push_back(rewardUnfolding.getDimension(i).formula->toString()); + } + headers.push_back("Result"); + storm::utility::exportDataToCSVFile( + storm::settings::getModule().getExportCdfDirectory() + "cdf.csv", cdfData, headers); + } - if (storm::settings::getModule().isExportCdfSet()) { - std::vector headers; - for (uint64_t i = 0; i < rewardUnfolding.getEpochManager().getDimensionCount(); ++i) { - headers.push_back(rewardUnfolding.getDimension(i).formula->toString()); + if (storm::settings::getModule().isShowStatisticsSet()) { + STORM_PRINT_AND_LOG("---------------------------------\n"); + STORM_PRINT_AND_LOG("Statistics:\n"); + STORM_PRINT_AND_LOG("---------------------------------\n"); + STORM_PRINT_AND_LOG(" #checked epochs: " << epochOrder.size() << ".\n"); + STORM_PRINT_AND_LOG(" overall Time: " << swAll << ".\n"); + STORM_PRINT_AND_LOG("Epoch Model building Time: " << swBuild << ".\n"); + STORM_PRINT_AND_LOG("Epoch Model checking Time: " << swCheck << ".\n"); + STORM_PRINT_AND_LOG("---------------------------------\n"); } - headers.push_back("Result"); - storm::utility::exportDataToCSVFile( - storm::settings::getModule().getExportCdfDirectory() + "cdf.csv", cdfData, headers); - } - if (storm::settings::getModule().isShowStatisticsSet()) { - STORM_PRINT_AND_LOG("---------------------------------\n"); - STORM_PRINT_AND_LOG("Statistics:\n"); - STORM_PRINT_AND_LOG("---------------------------------\n"); - STORM_PRINT_AND_LOG(" #checked epochs: " << epochOrder.size() << ".\n"); - STORM_PRINT_AND_LOG(" overall Time: " << swAll << ".\n"); - STORM_PRINT_AND_LOG("Epoch Model building Time: " << swBuild << ".\n"); - STORM_PRINT_AND_LOG("Epoch Model checking Time: " << swCheck << ".\n"); - STORM_PRINT_AND_LOG("---------------------------------\n"); + return result; } - - return result; } -template -std::vector SparseMdpPrctlHelper::computeNextProbabilities(Environment const& env, OptimizationDirection dir, - storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::BitVector const& nextStates) { - // Create the vector with which to multiply and initialize it correctly. - std::vector result(transitionMatrix.getRowGroupCount()); - storm::utility::vector::setVectorValues(result, nextStates, storm::utility::one()); +template +std::vector SparseMdpPrctlHelper::computeNextProbabilities( + Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::BitVector const& nextStates) { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support next probabilities with reward models."); + } else { + // Create the vector with which to multiply and initialize it correctly. + std::vector result(transitionMatrix.getRowGroupCount()); + storm::utility::vector::setVectorValues(result, nextStates, storm::utility::one()); - auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); - multiplier->multiplyAndReduce(env, dir, result, nullptr, result); + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->multiplyAndReduce(env, dir, result, nullptr, result); - return result; + return result; + } } -template -std::vector computeValidSchedulerHint(Environment const& env, SolutionType const& type, +template +std::vector computeValidSchedulerHint(Environment const& env, SemanticSolutionType const& type, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& filterStates, storm::storage::BitVector const& targetStates) { - storm::storage::Scheduler validScheduler(maybeStates.size()); + storm::storage::Scheduler validScheduler(maybeStates.size()); - if (type == SolutionType::UntilProbabilities) { + if (type == SemanticSolutionType::UntilProbabilities) { storm::utility::graph::computeSchedulerProbGreater0E(transitionMatrix, backwardTransitions, filterStates, targetStates, validScheduler, boost::none); - } else if (type == SolutionType::ExpectedRewards) { + } else if (type == SemanticSolutionType::ExpectedRewards) { storm::utility::graph::computeSchedulerProb1E(maybeStates | targetStates, transitionMatrix, backwardTransitions, filterStates, targetStates, validScheduler); } else { @@ -256,8 +266,8 @@ struct SparseMdpHintType { bool noEndComponents; }; -template -void extractValueAndSchedulerHint(SparseMdpHintType& hintStorage, storm::storage::SparseMatrix const& transitionMatrix, +template +void extractValueAndSchedulerHint(SparseMdpHintType& hintStorage, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& maybeStates, boost::optional const& selectedChoices, ModelCheckerHint const& hint, bool skipECWithinMaybeStatesCheck) { @@ -309,22 +319,22 @@ void extractValueAndSchedulerHint(SparseMdpHintType& hintStorage, sto (skipECWithinMaybeStatesCheck || hintStorage.hasSchedulerHint() || storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, maybeStates, ~maybeStates) .full())) { - hintStorage.valueHint = storm::utility::vector::filterVector(hint.template asExplicitModelCheckerHint().getResultHint(), maybeStates); + hintStorage.valueHint = storm::utility::vector::filterVector(hint.template asExplicitModelCheckerHint().getResultHint(), maybeStates); } } -template -SparseMdpHintType computeHints(Environment const& env, SolutionType const& type, ModelCheckerHint const& hint, - storm::OptimizationDirection const& dir, storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& maybeStates, - storm::storage::BitVector const& phiStates, storm::storage::BitVector const& targetStates, bool produceScheduler, - boost::optional const& selectedChoices = boost::none) { - SparseMdpHintType result; +template +SparseMdpHintType computeHints(Environment const& env, SemanticSolutionType const& type, ModelCheckerHint const& hint, + storm::OptimizationDirection const& dir, storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& maybeStates, + storm::storage::BitVector const& phiStates, storm::storage::BitVector const& targetStates, bool produceScheduler, + boost::optional const& selectedChoices = boost::none) { + SparseMdpHintType result; // There are no end components if we minimize until probabilities or // maximize reachability rewards or if the hint tells us so. - result.noEndComponents = (dir == storm::solver::OptimizationDirection::Minimize && type == SolutionType::UntilProbabilities) || - (dir == storm::solver::OptimizationDirection::Maximize && type == SolutionType::ExpectedRewards) || + result.noEndComponents = (dir == storm::solver::OptimizationDirection::Minimize && type == SemanticSolutionType::UntilProbabilities) || + (dir == storm::solver::OptimizationDirection::Maximize && type == SemanticSolutionType::ExpectedRewards) || (hint.isExplicitModelCheckerHint() && hint.asExplicitModelCheckerHint().getNoEndComponentsInMaybeStates()); // If there are no end components, the solution is unique. (Note that the other direction does not hold, @@ -333,7 +343,7 @@ SparseMdpHintType computeHints(Environment const& env, SolutionType c // Check for requirements of the solver. bool hasSchedulerHint = hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint().hasSchedulerHint(); - storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, result.uniqueSolution, result.noEndComponents, dir, hasSchedulerHint, produceScheduler); if (requirements.hasEnabledRequirement()) { @@ -348,20 +358,21 @@ SparseMdpHintType computeHints(Environment const& env, SolutionType c requirements.clearUniqueSolution(); // If we compute until probabilities, we can even assume the absence of end components. // Note that in the case of minimizing expected rewards there might still be end components in which reward is collected. - result.noEndComponents = (type == SolutionType::UntilProbabilities); + result.noEndComponents = (type == SemanticSolutionType::UntilProbabilities); } // If the solver requires an initial scheduler, compute one now. Note that any scheduler is valid if there are no end components. if (requirements.validInitialScheduler() && !result.noEndComponents) { STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it."); - result.schedulerHint = computeValidSchedulerHint(env, type, transitionMatrix, backwardTransitions, maybeStates, phiStates, targetStates); + result.schedulerHint = + computeValidSchedulerHint(env, type, transitionMatrix, backwardTransitions, maybeStates, phiStates, targetStates); requirements.clearValidInitialScheduler(); } // Finally, we have information on the bounds depending on the problem type. - if (type == SolutionType::UntilProbabilities) { + if (type == SemanticSolutionType::UntilProbabilities) { requirements.clearBounds(); - } else if (type == SolutionType::ExpectedRewards) { + } else if (type == SemanticSolutionType::ExpectedRewards) { requirements.clearLowerBounds(); } if (requirements.upperBounds()) { @@ -386,10 +397,10 @@ SparseMdpHintType computeHints(Environment const& env, SolutionType c // Only set bounds if we did not obtain them from the hint. if (!result.hasLowerResultBound()) { - result.lowerResultBound = storm::utility::zero(); + result.lowerResultBound = storm::utility::zero(); } - if (!result.hasUpperResultBound() && type == SolutionType::UntilProbabilities) { - result.upperResultBound = storm::utility::one(); + if (!result.hasUpperResultBound() && type == SemanticSolutionType::UntilProbabilities) { + result.upperResultBound = storm::utility::one(); } // If we received an upper bound, we can drop the requirement to compute one. @@ -422,21 +433,22 @@ struct MaybeStateResult { boost::optional> scheduler; }; -template -MaybeStateResult computeValuesForMaybeStates(Environment const& env, storm::solver::SolveGoal&& goal, - storm::storage::SparseMatrix&& submatrix, std::vector const& b, - bool produceScheduler, SparseMdpHintType& hint) { +template +MaybeStateResult computeValuesForMaybeStates(Environment const& env, storm::solver::SolveGoal&& goal, + storm::storage::SparseMatrix&& submatrix, std::vector const& b, + bool produceScheduler, SparseMdpHintType& hint) { // Initialize the solution vector. - std::vector x = - hint.hasValueHint() - ? std::move(hint.getValueHint()) - : std::vector(submatrix.getRowGroupCount(), hint.hasLowerResultBound() ? hint.getLowerResultBound() : storm::utility::zero()); + std::vector x = + hint.hasValueHint() ? std::move(hint.getValueHint()) + : std::vector(submatrix.getRowGroupCount(), + hint.hasLowerResultBound() ? hint.getLowerResultBound() : storm::utility::zero()); // Set up the solver. - storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; - std::unique_ptr> solver = + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; + std::unique_ptr> solver = storm::solver::configureMinMaxLinearEquationSolver(env, std::move(goal), minMaxLinearEquationSolverFactory, std::move(submatrix)); solver->setRequirementsChecked(); + solver->setUncertaintyIsRobust(goal.isRobust()); solver->setHasUniqueSolution(hint.hasUniqueSolution()); solver->setHasNoEndComponents(hint.hasNoEndComponents()); if (hint.hasLowerResultBound()) { @@ -458,7 +470,7 @@ MaybeStateResult computeValuesForMaybeStates(Environment const& env, #ifndef NDEBUG // As a sanity check, make sure our local upper bounds were in fact correct. - if (solver->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { + if (solver->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { auto resultIt = x.begin(); for (auto const& entry : solver->getUpperBounds()) { STORM_LOG_ASSERT( @@ -470,7 +482,7 @@ MaybeStateResult computeValuesForMaybeStates(Environment const& env, #endif // Create result. - MaybeStateResult result(std::move(x)); + MaybeStateResult result(std::move(x)); // If requested, return the requested scheduler. if (produceScheduler) { @@ -508,8 +520,8 @@ QualitativeStateSetsUntilProbabilities getQualitativeStateSetsUntilProbabilities return result; } -template -QualitativeStateSetsUntilProbabilities computeQualitativeStateSetsUntilProbabilities(storm::solver::SolveGoal const& goal, +template +QualitativeStateSetsUntilProbabilities computeQualitativeStateSetsUntilProbabilities(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, @@ -532,8 +544,8 @@ QualitativeStateSetsUntilProbabilities computeQualitativeStateSetsUntilProbabili return result; } -template -QualitativeStateSetsUntilProbabilities getQualitativeStateSetsUntilProbabilities(storm::solver::SolveGoal const& goal, +template +QualitativeStateSetsUntilProbabilities getQualitativeStateSetsUntilProbabilities(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, @@ -545,19 +557,28 @@ QualitativeStateSetsUntilProbabilities getQualitativeStateSetsUntilProbabilities } } -template -void extractSchedulerChoices(storm::storage::Scheduler& scheduler, std::vector const& subChoices, +template +void extractSchedulerChoices(storm::storage::Scheduler& scheduler, std::vector const& subChoices, storm::storage::BitVector const& maybeStates) { - auto subChoiceIt = subChoices.begin(); - for (auto maybeState : maybeStates) { - scheduler.setChoice(*subChoiceIt, maybeState); - ++subChoiceIt; + if constexpr (subChoicesCoverOnlyMaybeStates) { + auto subChoiceIt = subChoices.begin(); + for (auto maybeState : maybeStates) { + scheduler.setChoice(*subChoiceIt, maybeState); + ++subChoiceIt; + } + assert(subChoiceIt == subChoices.end()); + } else { + // See computeFixedPointSystemUntilProbabilities, where we create a different equation system. + // Consequentially, we run a slightly different code here for interval-based models. + STORM_LOG_ASSERT(maybeStates.size() == subChoices.size(), "Sizes do not coincide."); + for (auto maybeState : maybeStates) { + scheduler.setChoice(subChoices[maybeState], maybeState); + } } - assert(subChoiceIt == subChoices.end()); } -template -void extendScheduler(storm::storage::Scheduler& scheduler, storm::solver::SolveGoal const& goal, +template +void extendScheduler(storm::storage::Scheduler& scheduler, storm::solver::SolveGoal const& goal, QualitativeStateSetsUntilProbabilities const& qualitativeStateSets, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates) { @@ -578,25 +599,41 @@ void extendScheduler(storm::storage::Scheduler& scheduler, storm::sol } } -template -void computeFixedPointSystemUntilProbabilities(storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, +template +void computeFixedPointSystemUntilProbabilities(storm::solver::SolveGoal& goal, + storm::storage::SparseMatrix const& transitionMatrix, QualitativeStateSetsUntilProbabilities const& qualitativeStateSets, storm::storage::SparseMatrix& submatrix, std::vector& b) { - // First, we can eliminate the rows and columns from the original transition probability matrix for states - // whose probabilities are already known. - submatrix = transitionMatrix.getSubmatrix(true, qualitativeStateSets.maybeStates, qualitativeStateSets.maybeStates, false); - - // Prepare the right-hand side of the equation system. For entry i this corresponds to - // the accumulated probability of going from state i to some state that has probability 1. - b = transitionMatrix.getConstrainedRowGroupSumVector(qualitativeStateSets.maybeStates, qualitativeStateSets.statesWithProbability1); + if constexpr (std::is_same_v) { + // For non-interval based models, we can eliminate the rows and columns from the original transition probability matrix for states + // whose probabilities are already known... However, there is information in the transition to those states. + // Thus, we cannot eliminate them all. + // We can however drop all the outgoing transitions from these states. + // TODO: we can drop more than those entries and actually remove many states (all but the ones reachable in one step from the maybe states), + // TODO ctned: however, there is quite some bookkeeping involved in projecting the right vectors. + // TODO ctned: Instead is likely easier to just do a pass and make a unique sink and a unique target state. + // TODO ctned: If this is ever changed, extractSchedulerChoices must also be updated. + submatrix = transitionMatrix.filterEntries(transitionMatrix.getRowFilter(qualitativeStateSets.maybeStates)); + + // Prepare the right-hand side of the equation system. For entry i this corresponds to + // the accumulated probability of going from state i to some state that has probability 1. + storm::utility::vector::setAllValues(b, transitionMatrix.getRowFilter(qualitativeStateSets.statesWithProbability1)); + } else { + // First, we can eliminate the rows and columns from the original transition probability matrix for states + // whose probabilities are already known. + submatrix = transitionMatrix.getSubmatrix(true, qualitativeStateSets.maybeStates, qualitativeStateSets.maybeStates, false); + // Prepare the right-hand side of the equation system. For entry i this corresponds to + // the accumulated probability of going from state i to some state that has probability 1. + b = transitionMatrix.getConstrainedRowGroupSumVector(qualitativeStateSets.maybeStates, qualitativeStateSets.statesWithProbability1); + } // If the solve goal has relevant values, we need to adjust them. goal.restrictRelevantValues(qualitativeStateSets.maybeStates); } -template +template boost::optional> computeFixedPointSystemUntilProbabilitiesEliminateEndComponents( - storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, + storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, QualitativeStateSetsUntilProbabilities const& qualitativeStateSets, storm::storage::SparseMatrix& submatrix, std::vector& b, bool produceScheduler) { // Get the set of states that (under some scheduler) can stay in the set of maybestates forever @@ -640,16 +677,16 @@ boost::optional> computeFixedPointSy } } -template -MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeUntilProbabilities( - Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, +template +MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeUntilProbabilities( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { STORM_LOG_THROW(!qualitative || !produceScheduler, storm::exceptions::InvalidSettingsException, "Cannot produce scheduler when performing qualitative model checking only."); // Prepare resulting vector. - std::vector result(transitionMatrix.getRowGroupCount(), storm::utility::zero()); + std::vector result(transitionMatrix.getRowGroupCount(), storm::utility::zero()); // We need to identify the maybe states (states which have a probability for satisfying the until formula // that is strictly between 0 and 1) and the states that satisfy the formula with probablity 1 and 0, respectively. @@ -661,15 +698,15 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper(result, qualitativeStateSets.statesWithProbability1, storm::utility::one()); + storm::utility::vector::setVectorValues(result, qualitativeStateSets.statesWithProbability1, storm::utility::one()); // Check if the values of the maybe states are relevant for the SolveGoal bool maybeStatesNotRelevant = goal.hasRelevantValues() && goal.relevantValues().isDisjointFrom(qualitativeStateSets.maybeStates); // If requested, we will produce a scheduler. - std::unique_ptr> scheduler; + std::unique_ptr> scheduler; if (produceScheduler) { - scheduler = std::make_unique>(transitionMatrix.getRowGroupCount()); + scheduler = std::make_unique>(transitionMatrix.getRowGroupCount()); // If maybeStatesNotRelevant is true, we have to set the scheduler for maybe states as "dontCare" if (maybeStatesNotRelevant) { for (auto state : qualitativeStateSets.maybeStates) { @@ -681,15 +718,15 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper(result, qualitativeStateSets.maybeStates, storm::utility::convertNumber(0.5)); + storm::utility::vector::setVectorValues(result, qualitativeStateSets.maybeStates, storm::utility::convertNumber(0.5)); } else { if (!qualitativeStateSets.maybeStates.empty()) { // In this case we have have to compute the remaining probabilities. // Obtain proper hint information either from the provided hint or from requirements of the solver. - SparseMdpHintType hintInformation = - computeHints(env, SolutionType::UntilProbabilities, hint, goal.direction(), transitionMatrix, backwardTransitions, - qualitativeStateSets.maybeStates, phiStates, qualitativeStateSets.statesWithProbability1, produceScheduler); + SparseMdpHintType hintInformation = computeHints( + env, SemanticSolutionType::UntilProbabilities, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, + phiStates, qualitativeStateSets.statesWithProbability1, produceScheduler); // Declare the components of the equation system we will solve. storm::storage::SparseMatrix submatrix; @@ -706,21 +743,26 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper resultForMaybeStates = + MaybeStateResult resultForMaybeStates = computeValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, produceScheduler, hintInformation); // If we eliminated end components, we need to extract the result differently. if (ecInformation && ecInformation.get().getEliminatedEndComponents()) { - ecInformation.get().setValues(result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues()); - if (produceScheduler) { - ecInformation.get().setScheduler(*scheduler, qualitativeStateSets.maybeStates, transitionMatrix, backwardTransitions, - resultForMaybeStates.getScheduler()); + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support this end component with interval models."); + } else { + ecInformation.get().setValues(result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues()); + if (produceScheduler) { + ecInformation.get().setScheduler(*scheduler, qualitativeStateSets.maybeStates, transitionMatrix, backwardTransitions, + resultForMaybeStates.getScheduler()); + } } } else { // Set values of resulting vector according to result. - storm::utility::vector::setVectorValues(result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues()); + storm::utility::vector::setVectorValues(result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues()); if (produceScheduler) { - extractSchedulerChoices(*scheduler, resultForMaybeStates.getScheduler(), qualitativeStateSets.maybeStates); + extractSchedulerChoices>(*scheduler, resultForMaybeStates.getScheduler(), + qualitativeStateSets.maybeStates); } } } @@ -738,12 +780,12 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelperisMemorylessScheduler(), "Expected a memoryless scheduler"); // Return result. - return MDPSparseModelCheckingHelperReturnType(std::move(result), std::move(scheduler)); + return MDPSparseModelCheckingHelperReturnType(std::move(result), std::move(scheduler)); } -template -MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeGloballyProbabilities( - Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, +template +MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeGloballyProbabilities( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, bool useMecBasedTechnique) { if (useMecBasedTechnique) { @@ -764,53 +806,61 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper() - element; + element = storm::utility::one() - element; } return result; } } -template +template template -std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, - storm::storage::SparseMatrix const& transitionMatrix, - RewardModelType const& rewardModel, uint_fast64_t stepCount) { - // Only compute the result if the model has a state-based reward this->getModel(). - STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); +std::vector SparseMdpPrctlHelper::computeInstantaneousRewards( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, + RewardModelType const& rewardModel, uint_fast64_t stepCount) { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support instantenous rewards with interval models."); + } else { + // Only compute the result if the model has a state-based reward this->getModel(). + STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); - // Initialize result to state rewards of the this->getModel(). - std::vector result(rewardModel.getStateRewardVector()); + // Initialize result to state rewards of the this->getModel(). + std::vector result(rewardModel.getStateRewardVector()); - auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); - multiplier->repeatedMultiplyAndReduce(env, goal.direction(), result, nullptr, stepCount); + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->repeatedMultiplyAndReduce(env, goal.direction(), result, nullptr, stepCount); - return result; + return result; + } } -template +template template -std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, - storm::storage::SparseMatrix const& transitionMatrix, - RewardModelType const& rewardModel, uint_fast64_t stepBound) { - // Only compute the result if the model has at least one reward this->getModel(). - STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); +std::vector SparseMdpPrctlHelper::computeCumulativeRewards( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, + RewardModelType const& rewardModel, uint_fast64_t stepBound) { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support cumulative rewards with interval models."); + } else { + // Only compute the result if the model has at least one reward this->getModel(). + STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); - // Compute the reward vector to add in each step based on the available reward models. - std::vector totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix); + // Compute the reward vector to add in each step based on the available reward models. + std::vector totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix); - // Initialize result to the zero vector. - std::vector result(transitionMatrix.getRowGroupCount(), storm::utility::zero()); + // Initialize result to the zero vector. + std::vector result(transitionMatrix.getRowGroupCount(), storm::utility::zero()); - auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); - multiplier->repeatedMultiplyAndReduce(env, goal.direction(), result, &totalRewardVector, stepBound); + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->repeatedMultiplyAndReduce(env, goal.direction(), result, &totalRewardVector, stepBound); - return result; + return result; + } } -template +template template -MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeTotalRewards( - Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, +MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeTotalRewards( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { // Reduce to reachability rewards @@ -865,7 +915,7 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper result = computeReachabilityRewardsHelper( + MDPSparseModelCheckingHelperReturnType result = computeReachabilityRewardsHelper( env, std::move(goal), ecElimResult.matrix, ecElimResult.matrix.transpose(true), [&](uint_fast64_t rowCount, storm::storage::SparseMatrix const& newTransitionMatrix, storm::storage::BitVector const& maybeStates) { std::vector result; @@ -898,7 +948,7 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper resultInEcQuotient = std::move(result.values); + std::vector resultInEcQuotient = std::move(result.values); result.values.resize(ecElimResult.oldToNewStateMapping.size()); storm::utility::vector::selectVectorValues(result.values, ecElimResult.oldToNewStateMapping, resultInEcQuotient); return result; @@ -906,10 +956,10 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper +template template -MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards( - Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, +MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { // Only compute the result if the model has at least one reward this->getModel(). @@ -923,9 +973,9 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper -MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityTimes( - Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, +template +MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityTimes( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { return computeReachabilityRewardsHelper( @@ -938,9 +988,9 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper -std::vector SparseMdpPrctlHelper::computeReachabilityRewards( - Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, +template +std::vector SparseMdpPrctlHelper::computeReachabilityRewards( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& intervalRewardModel, bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative) { // Only compute the result if the reward model is not empty. @@ -1006,9 +1056,9 @@ QualitativeStateSetsReachabilityRewards getQualitativeStateSetsReachabilityRewar return result; } -template +template QualitativeStateSetsReachabilityRewards computeQualitativeStateSetsReachabilityRewards( - storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, + storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, std::function const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter) { QualitativeStateSetsReachabilityRewards result; @@ -1037,8 +1087,8 @@ QualitativeStateSetsReachabilityRewards computeQualitativeStateSetsReachabilityR return result; } -template -QualitativeStateSetsReachabilityRewards getQualitativeStateSetsReachabilityRewards(storm::solver::SolveGoal const& goal, +template +QualitativeStateSetsReachabilityRewards getQualitativeStateSetsReachabilityRewards(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, ModelCheckerHint const& hint, @@ -1052,8 +1102,8 @@ QualitativeStateSetsReachabilityRewards getQualitativeStateSetsReachabilityRewar } } -template -void extendScheduler(storm::storage::Scheduler& scheduler, storm::solver::SolveGoal const& goal, +template +void extendScheduler(storm::storage::Scheduler& scheduler, storm::solver::SolveGoal const& goal, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, std::function const& zeroRewardChoicesGetter) { @@ -1073,8 +1123,8 @@ void extendScheduler(storm::storage::Scheduler& scheduler, storm::sol } } -template -void extractSchedulerChoices(storm::storage::Scheduler& scheduler, storm::storage::SparseMatrix const& transitionMatrix, +template +void extractSchedulerChoices(storm::storage::Scheduler& scheduler, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& subChoices, storm::storage::BitVector const& maybeStates, boost::optional const& selectedChoices) { auto subChoiceIt = subChoices.begin(); @@ -1098,9 +1148,9 @@ void extractSchedulerChoices(storm::storage::Scheduler& scheduler, st assert(subChoiceIt == subChoices.end()); } -template +template void computeFixedPointSystemReachabilityRewards( - storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, + storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, boost::optional const& selectedChoices, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, @@ -1128,9 +1178,9 @@ void computeFixedPointSystemReachabilityRewards( goal.restrictRelevantValues(qualitativeStateSets.maybeStates); } -template +template boost::optional> computeFixedPointSystemReachabilityRewardsEliminateEndComponents( - storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, + storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, boost::optional const& selectedChoices, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& @@ -1212,23 +1262,27 @@ boost::optional> computeFixedPointSy } } -template -void computeUpperRewardBounds(SparseMdpHintType& hintInformation, storm::OptimizationDirection const& direction, +template +void computeUpperRewardBounds(SparseMdpHintType& hintInformation, storm::OptimizationDirection const& direction, storm::storage::SparseMatrix const& submatrix, std::vector const& choiceRewards, std::vector const& oneStepTargetProbabilities) { - // For the min-case, we use DS-MPI, for the max-case variant 2 of the Baier et al. paper (CAV'17). - if (direction == storm::OptimizationDirection::Minimize) { - DsMpiMdpUpperRewardBoundsComputer dsmpi(submatrix, choiceRewards, oneStepTargetProbabilities); - hintInformation.upperResultBounds = dsmpi.computeUpperBounds(); + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support computing upper reward bounds with interval models."); } else { - BaierUpperRewardBoundsComputer baier(submatrix, choiceRewards, oneStepTargetProbabilities); - hintInformation.upperResultBound = baier.computeUpperBound(); + // For the min-case, we use DS-MPI, for the max-case variant 2 of the Baier et al. paper (CAV'17). + if (direction == storm::OptimizationDirection::Minimize) { + DsMpiMdpUpperRewardBoundsComputer dsmpi(submatrix, choiceRewards, oneStepTargetProbabilities); + hintInformation.upperResultBounds = dsmpi.computeUpperBounds(); + } else { + BaierUpperRewardBoundsComputer baier(submatrix, choiceRewards, oneStepTargetProbabilities); + hintInformation.upperResultBound = baier.computeUpperBound(); + } } } -template -MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewardsHelper( - Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, +template +MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewardsHelper( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, @@ -1236,7 +1290,7 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter, ModelCheckerHint const& hint) { // Prepare resulting vector. - std::vector result(transitionMatrix.getRowGroupCount(), storm::utility::zero()); + std::vector result(transitionMatrix.getRowGroupCount(), storm::utility::zero()); // Determine which states have a reward that is infinity or less than infinity. QualitativeStateSetsReachabilityRewards qualitativeStateSets = getQualitativeStateSetsReachabilityRewards( @@ -1246,12 +1300,16 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper()); + storm::utility::vector::setVectorValues(result, qualitativeStateSets.infinityStates, storm::utility::infinity()); // If requested, we will produce a scheduler. - std::unique_ptr> scheduler; + std::unique_ptr> scheduler; if (produceScheduler) { - scheduler = std::make_unique>(transitionMatrix.getRowGroupCount()); + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support producing schedulers in this function with interval models."); + } else { + scheduler = std::make_unique>(transitionMatrix.getRowGroupCount()); + } } // Check if the values of the maybe states are relevant for the SolveGoal @@ -1262,7 +1320,7 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper(result, qualitativeStateSets.maybeStates, storm::utility::one()); + storm::utility::vector::setVectorValues(result, qualitativeStateSets.maybeStates, storm::utility::one()); } else { if (!qualitativeStateSets.maybeStates.empty()) { // In this case we have to compute the reward values for the remaining states. @@ -1274,8 +1332,8 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper hintInformation = computeHints( - env, SolutionType::ExpectedRewards, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, + SparseMdpHintType hintInformation = computeHints( + env, SemanticSolutionType::ExpectedRewards, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, ~qualitativeStateSets.rewardZeroStates, qualitativeStateSets.rewardZeroStates, produceScheduler, selectedChoices); // Declare the components of the equation system we will solve. @@ -1292,9 +1350,13 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper> ecInformation; if (hintInformation.getEliminateEndComponents()) { - ecInformation = computeFixedPointSystemReachabilityRewardsEliminateEndComponents( - goal, transitionMatrix, backwardTransitions, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, submatrix, b, - oneStepTargetProbabilities, produceScheduler); + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support eliminating end components with interval models."); + } else { + ecInformation = computeFixedPointSystemReachabilityRewardsEliminateEndComponents( + goal, transitionMatrix, backwardTransitions, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, submatrix, b, + oneStepTargetProbabilities, produceScheduler); + } } else { // Otherwise, we compute the standard equations. computeFixedPointSystemReachabilityRewards(goal, transitionMatrix, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, @@ -1308,19 +1370,23 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper resultForMaybeStates = + MaybeStateResult resultForMaybeStates = computeValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, produceScheduler, hintInformation); // If we eliminated end components, we need to extract the result differently. if (ecInformation && ecInformation.get().getEliminatedEndComponents()) { - ecInformation.get().setValues(result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues()); - if (produceScheduler) { - ecInformation.get().setScheduler(*scheduler, qualitativeStateSets.maybeStates, transitionMatrix, backwardTransitions, - resultForMaybeStates.getScheduler()); + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support eliminating end components with interval models."); + } else { + ecInformation.get().setValues(result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues()); + if (produceScheduler) { + ecInformation.get().setScheduler(*scheduler, qualitativeStateSets.maybeStates, transitionMatrix, backwardTransitions, + resultForMaybeStates.getScheduler()); + } } } else { // Set values of resulting vector according to result. - storm::utility::vector::setVectorValues(result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues()); + storm::utility::vector::setVectorValues(result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues()); if (produceScheduler) { extractSchedulerChoices(*scheduler, transitionMatrix, resultForMaybeStates.getScheduler(), qualitativeStateSets.maybeStates, selectedChoices); @@ -1340,175 +1406,184 @@ MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelperisDeterministicScheduler(), "Expected a deterministic scheduler"); STORM_LOG_ASSERT((!produceScheduler && !scheduler) || scheduler->isMemorylessScheduler(), "Expected a memoryless scheduler"); - return MDPSparseModelCheckingHelperReturnType(std::move(result), std::move(scheduler)); + if constexpr (std::is_same_v) { + return MDPSparseModelCheckingHelperReturnType(std::move(result)); + } else { + return MDPSparseModelCheckingHelperReturnType(std::move(result), std::move(scheduler)); + } } -template -std::unique_ptr SparseMdpPrctlHelper::computeConditionalProbabilities( - Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, +template +std::unique_ptr SparseMdpPrctlHelper::computeConditionalProbabilities( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates) { - std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now(); - - // For the max-case, we can simply take the given target states. For the min-case, however, we need to - // find the MECs of non-target states and make them the new target states. - storm::storage::BitVector fixedTargetStates; - if (!goal.minimize()) { - fixedTargetStates = targetStates; + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support computing conditional probabilities with interval models."); } else { - fixedTargetStates = storm::storage::BitVector(targetStates.size()); - storm::storage::MaximalEndComponentDecomposition mecDecomposition(transitionMatrix, backwardTransitions, ~targetStates); - for (auto const& mec : mecDecomposition) { - for (auto const& stateActionsPair : mec) { - fixedTargetStates.set(stateActionsPair.first); + std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now(); + + // For the max-case, we can simply take the given target states. For the min-case, however, we need to + // find the MECs of non-target states and make them the new target states. + storm::storage::BitVector fixedTargetStates; + if (!goal.minimize()) { + fixedTargetStates = targetStates; + } else { + fixedTargetStates = storm::storage::BitVector(targetStates.size()); + storm::storage::MaximalEndComponentDecomposition mecDecomposition(transitionMatrix, backwardTransitions, ~targetStates); + for (auto const& mec : mecDecomposition) { + for (auto const& stateActionsPair : mec) { + fixedTargetStates.set(stateActionsPair.first); + } } } - } - storm::storage::BitVector allStates(fixedTargetStates.size(), true); - - // Extend the target states by computing all states that have probability 1 to go to a target state - // under *all* schedulers. - fixedTargetStates = - storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, allStates, fixedTargetStates); - - // We solve the max-case and later adjust the result if the optimization direction was to minimize. - storm::storage::BitVector initialStatesBitVector = goal.relevantValues(); - STORM_LOG_THROW(initialStatesBitVector.getNumberOfSetBits() == 1, storm::exceptions::NotSupportedException, - "Computing conditional probabilities in MDPs is only supported for models with exactly one initial state."); - storm::storage::sparse::state_type initialState = *initialStatesBitVector.begin(); - - // Extend the condition states by computing all states that have probability 1 to go to a condition state - // under *all* schedulers. - storm::storage::BitVector extendedConditionStates = - storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, allStates, conditionStates); - - STORM_LOG_DEBUG("Computing probabilities to satisfy condition."); - std::chrono::high_resolution_clock::time_point conditionStart = std::chrono::high_resolution_clock::now(); - std::vector conditionProbabilities = std::move( - computeUntilProbabilities(env, OptimizationDirection::Maximize, transitionMatrix, backwardTransitions, allStates, extendedConditionStates, false, false) - .values); - std::chrono::high_resolution_clock::time_point conditionEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Computed probabilities to satisfy for condition in " - << std::chrono::duration_cast(conditionEnd - conditionStart).count() << "ms."); - - // If the conditional probability is undefined for the initial state, we return directly. - if (storm::utility::isZero(conditionProbabilities[initialState])) { - return std::unique_ptr(new ExplicitQuantitativeCheckResult(initialState, storm::utility::infinity())); - } - - STORM_LOG_DEBUG("Computing probabilities to reach target."); - std::chrono::high_resolution_clock::time_point targetStart = std::chrono::high_resolution_clock::now(); - std::vector targetProbabilities = std::move( - computeUntilProbabilities(env, OptimizationDirection::Maximize, transitionMatrix, backwardTransitions, allStates, fixedTargetStates, false, false) - .values); - std::chrono::high_resolution_clock::time_point targetEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Computed probabilities to reach target in " << std::chrono::duration_cast(targetEnd - targetStart).count() - << "ms."); - - storm::storage::BitVector statesWithProbabilityGreater0E(transitionMatrix.getRowGroupCount(), true); - storm::storage::sparse::state_type state = 0; - for (auto const& element : conditionProbabilities) { - if (storm::utility::isZero(element)) { - statesWithProbabilityGreater0E.set(state, false); + storm::storage::BitVector allStates(fixedTargetStates.size(), true); + + // Extend the target states by computing all states that have probability 1 to go to a target state + // under *all* schedulers. + fixedTargetStates = + storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, allStates, fixedTargetStates); + + // We solve the max-case and later adjust the result if the optimization direction was to minimize. + storm::storage::BitVector initialStatesBitVector = goal.relevantValues(); + STORM_LOG_THROW(initialStatesBitVector.getNumberOfSetBits() == 1, storm::exceptions::NotSupportedException, + "Computing conditional probabilities in MDPs is only supported for models with exactly one initial state."); + storm::storage::sparse::state_type initialState = *initialStatesBitVector.begin(); + + // Extend the condition states by computing all states that have probability 1 to go to a condition state + // under *all* schedulers. + storm::storage::BitVector extendedConditionStates = + storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, allStates, conditionStates); + + STORM_LOG_DEBUG("Computing probabilities to satisfy condition."); + std::chrono::high_resolution_clock::time_point conditionStart = std::chrono::high_resolution_clock::now(); + std::vector conditionProbabilities = + std::move(computeUntilProbabilities(env, OptimizationDirection::Maximize, transitionMatrix, backwardTransitions, allStates, extendedConditionStates, + false, false) + .values); + std::chrono::high_resolution_clock::time_point conditionEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Computed probabilities to satisfy for condition in " + << std::chrono::duration_cast(conditionEnd - conditionStart).count() << "ms."); + + // If the conditional probability is undefined for the initial state, we return directly. + if (storm::utility::isZero(conditionProbabilities[initialState])) { + return std::unique_ptr(new ExplicitQuantitativeCheckResult(initialState, storm::utility::infinity())); } - ++state; - } - - // Determine those states that need to be equipped with a restart mechanism. - STORM_LOG_DEBUG("Computing problematic states."); - storm::storage::BitVector pureResetStates = storm::utility::graph::performProb0A(backwardTransitions, allStates, extendedConditionStates); - storm::storage::BitVector problematicStates = storm::utility::graph::performProb0E( - transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, allStates, extendedConditionStates | fixedTargetStates); - - // Otherwise, we build the transformed MDP. - storm::storage::BitVector relevantStates = storm::utility::graph::getReachableStates(transitionMatrix, initialStatesBitVector, allStates, - extendedConditionStates | fixedTargetStates | pureResetStates); - STORM_LOG_TRACE("Found " << relevantStates.getNumberOfSetBits() << " relevant states for conditional probability computation."); - std::vector numberOfStatesBeforeRelevantStates = relevantStates.getNumberOfSetBitsBeforeIndices(); - storm::storage::sparse::state_type newGoalState = relevantStates.getNumberOfSetBits(); - storm::storage::sparse::state_type newStopState = newGoalState + 1; - storm::storage::sparse::state_type newFailState = newStopState + 1; - - // Build the transitions of the (relevant) states of the original model. - storm::storage::SparseMatrixBuilder builder(0, newFailState + 1, 0, true, true); - uint_fast64_t currentRow = 0; - for (auto state : relevantStates) { - builder.newRowGroup(currentRow); - if (fixedTargetStates.get(state)) { - if (!storm::utility::isZero(conditionProbabilities[state])) { - builder.addNextValue(currentRow, newGoalState, conditionProbabilities[state]); - } - if (!storm::utility::isOne(conditionProbabilities[state])) { - builder.addNextValue(currentRow, newFailState, storm::utility::one() - conditionProbabilities[state]); - } - ++currentRow; - } else if (extendedConditionStates.get(state)) { - if (!storm::utility::isZero(targetProbabilities[state])) { - builder.addNextValue(currentRow, newGoalState, targetProbabilities[state]); - } - if (!storm::utility::isOne(targetProbabilities[state])) { - builder.addNextValue(currentRow, newStopState, storm::utility::one() - targetProbabilities[state]); + + STORM_LOG_DEBUG("Computing probabilities to reach target."); + std::chrono::high_resolution_clock::time_point targetStart = std::chrono::high_resolution_clock::now(); + std::vector targetProbabilities = std::move( + computeUntilProbabilities(env, OptimizationDirection::Maximize, transitionMatrix, backwardTransitions, allStates, fixedTargetStates, false, false) + .values); + std::chrono::high_resolution_clock::time_point targetEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Computed probabilities to reach target in " << std::chrono::duration_cast(targetEnd - targetStart).count() + << "ms."); + + storm::storage::BitVector statesWithProbabilityGreater0E(transitionMatrix.getRowGroupCount(), true); + storm::storage::sparse::state_type state = 0; + for (auto const& element : conditionProbabilities) { + if (storm::utility::isZero(element)) { + statesWithProbabilityGreater0E.set(state, false); } - ++currentRow; - } else if (pureResetStates.get(state)) { - builder.addNextValue(currentRow, numberOfStatesBeforeRelevantStates[initialState], storm::utility::one()); - ++currentRow; - } else { - for (uint_fast64_t row = transitionMatrix.getRowGroupIndices()[state]; row < transitionMatrix.getRowGroupIndices()[state + 1]; ++row) { - for (auto const& successorEntry : transitionMatrix.getRow(row)) { - builder.addNextValue(currentRow, numberOfStatesBeforeRelevantStates[successorEntry.getColumn()], successorEntry.getValue()); + ++state; + } + + // Determine those states that need to be equipped with a restart mechanism. + STORM_LOG_DEBUG("Computing problematic states."); + storm::storage::BitVector pureResetStates = storm::utility::graph::performProb0A(backwardTransitions, allStates, extendedConditionStates); + storm::storage::BitVector problematicStates = storm::utility::graph::performProb0E( + transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, allStates, extendedConditionStates | fixedTargetStates); + + // Otherwise, we build the transformed MDP. + storm::storage::BitVector relevantStates = storm::utility::graph::getReachableStates(transitionMatrix, initialStatesBitVector, allStates, + extendedConditionStates | fixedTargetStates | pureResetStates); + STORM_LOG_TRACE("Found " << relevantStates.getNumberOfSetBits() << " relevant states for conditional probability computation."); + std::vector numberOfStatesBeforeRelevantStates = relevantStates.getNumberOfSetBitsBeforeIndices(); + storm::storage::sparse::state_type newGoalState = relevantStates.getNumberOfSetBits(); + storm::storage::sparse::state_type newStopState = newGoalState + 1; + storm::storage::sparse::state_type newFailState = newStopState + 1; + + // Build the transitions of the (relevant) states of the original model. + storm::storage::SparseMatrixBuilder builder(0, newFailState + 1, 0, true, true); + uint_fast64_t currentRow = 0; + for (auto state : relevantStates) { + builder.newRowGroup(currentRow); + if (fixedTargetStates.get(state)) { + if (!storm::utility::isZero(conditionProbabilities[state])) { + builder.addNextValue(currentRow, newGoalState, conditionProbabilities[state]); + } + if (!storm::utility::isOne(conditionProbabilities[state])) { + builder.addNextValue(currentRow, newFailState, storm::utility::one() - conditionProbabilities[state]); } ++currentRow; - } - if (problematicStates.get(state)) { + } else if (extendedConditionStates.get(state)) { + if (!storm::utility::isZero(targetProbabilities[state])) { + builder.addNextValue(currentRow, newGoalState, targetProbabilities[state]); + } + if (!storm::utility::isOne(targetProbabilities[state])) { + builder.addNextValue(currentRow, newStopState, storm::utility::one() - targetProbabilities[state]); + } + ++currentRow; + } else if (pureResetStates.get(state)) { builder.addNextValue(currentRow, numberOfStatesBeforeRelevantStates[initialState], storm::utility::one()); ++currentRow; + } else { + for (uint_fast64_t row = transitionMatrix.getRowGroupIndices()[state]; row < transitionMatrix.getRowGroupIndices()[state + 1]; ++row) { + for (auto const& successorEntry : transitionMatrix.getRow(row)) { + builder.addNextValue(currentRow, numberOfStatesBeforeRelevantStates[successorEntry.getColumn()], successorEntry.getValue()); + } + ++currentRow; + } + if (problematicStates.get(state)) { + builder.addNextValue(currentRow, numberOfStatesBeforeRelevantStates[initialState], storm::utility::one()); + ++currentRow; + } } } - } - // Now build the transitions of the newly introduced states. - builder.newRowGroup(currentRow); - builder.addNextValue(currentRow, newGoalState, storm::utility::one()); - ++currentRow; - builder.newRowGroup(currentRow); - builder.addNextValue(currentRow, newStopState, storm::utility::one()); - ++currentRow; - builder.newRowGroup(currentRow); - builder.addNextValue(currentRow, numberOfStatesBeforeRelevantStates[initialState], storm::utility::one()); - ++currentRow; - - std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Computed transformed model in " << std::chrono::duration_cast(end - start).count() << "ms."); - - // Finally, build the matrix and dispatch the query as a reachability query. - STORM_LOG_DEBUG("Computing conditional probabilties."); - storm::storage::BitVector newGoalStates(newFailState + 1); - newGoalStates.set(newGoalState); - storm::storage::SparseMatrix newTransitionMatrix = builder.build(); - STORM_LOG_DEBUG("Transformed model has " << newTransitionMatrix.getRowGroupCount() << " states and " << newTransitionMatrix.getNonzeroEntryCount() - << " transitions."); - storm::storage::SparseMatrix newBackwardTransitions = newTransitionMatrix.transpose(true); - - storm::solver::OptimizationDirection dir = goal.direction(); - if (goal.minimize()) { - goal.oneMinus(); - } + // Now build the transitions of the newly introduced states. + builder.newRowGroup(currentRow); + builder.addNextValue(currentRow, newGoalState, storm::utility::one()); + ++currentRow; + builder.newRowGroup(currentRow); + builder.addNextValue(currentRow, newStopState, storm::utility::one()); + ++currentRow; + builder.newRowGroup(currentRow); + builder.addNextValue(currentRow, numberOfStatesBeforeRelevantStates[initialState], storm::utility::one()); + ++currentRow; + + std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Computed transformed model in " << std::chrono::duration_cast(end - start).count() << "ms."); + + // Finally, build the matrix and dispatch the query as a reachability query. + STORM_LOG_DEBUG("Computing conditional probabilties."); + storm::storage::BitVector newGoalStates(newFailState + 1); + newGoalStates.set(newGoalState); + storm::storage::SparseMatrix newTransitionMatrix = builder.build(); + STORM_LOG_DEBUG("Transformed model has " << newTransitionMatrix.getRowGroupCount() << " states and " << newTransitionMatrix.getNonzeroEntryCount() + << " transitions."); + storm::storage::SparseMatrix newBackwardTransitions = newTransitionMatrix.transpose(true); + + storm::solver::OptimizationDirection dir = goal.direction(); + if (goal.minimize()) { + goal.oneMinus(); + } - std::chrono::high_resolution_clock::time_point conditionalStart = std::chrono::high_resolution_clock::now(); - std::vector goalProbabilities = - std::move(computeUntilProbabilities(env, std::move(goal), newTransitionMatrix, newBackwardTransitions, - storm::storage::BitVector(newFailState + 1, true), newGoalStates, false, false) - .values); - std::chrono::high_resolution_clock::time_point conditionalEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Computed conditional probabilities in transformed model in " - << std::chrono::duration_cast(conditionalEnd - conditionalStart).count() << "ms."); + std::chrono::high_resolution_clock::time_point conditionalStart = std::chrono::high_resolution_clock::now(); + std::vector goalProbabilities = + std::move(computeUntilProbabilities(env, std::move(goal), newTransitionMatrix, newBackwardTransitions, + storm::storage::BitVector(newFailState + 1, true), newGoalStates, false, false) + .values); + std::chrono::high_resolution_clock::time_point conditionalEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Computed conditional probabilities in transformed model in " + << std::chrono::duration_cast(conditionalEnd - conditionalStart).count() << "ms."); - return std::unique_ptr(new ExplicitQuantitativeCheckResult( - initialState, dir == OptimizationDirection::Maximize - ? goalProbabilities[numberOfStatesBeforeRelevantStates[initialState]] - : storm::utility::one() - goalProbabilities[numberOfStatesBeforeRelevantStates[initialState]])); + return std::unique_ptr(new ExplicitQuantitativeCheckResult( + initialState, dir == OptimizationDirection::Maximize + ? goalProbabilities[numberOfStatesBeforeRelevantStates[initialState]] + : storm::utility::one() - goalProbabilities[numberOfStatesBeforeRelevantStates[initialState]])); + } } template class SparseMdpPrctlHelper; @@ -1548,6 +1623,23 @@ template MDPSparseModelCheckingHelperReturnType SparseMdp storm::models::sparse::StandardRewardModel const& rewardModel, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint); #endif + +template class SparseMdpPrctlHelper; +template std::vector SparseMdpPrctlHelper::computeInstantaneousRewards( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, + storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepCount); +template std::vector SparseMdpPrctlHelper::computeCumulativeRewards( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, + storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepBound); +template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, + storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint); +template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeTotalRewards( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, + bool qualitative, bool produceScheduler, ModelCheckerHint const& hint); + } // namespace helper } // namespace modelchecker } // namespace storm diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h index f40359f435..5510b92c13 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h @@ -5,7 +5,6 @@ #include "MDPModelCheckingHelperReturnType.h" #include "storm/modelchecker/hints/ModelCheckerHint.h" -#include "storm/modelchecker/prctl/helper/SolutionType.h" #include "storm/modelchecker/prctl/helper/rewardbounded/MultiDimensionalRewardUnfolding.h" #include "storm/storage/MaximalEndComponent.h" #include "storm/storage/SparseMatrix.h" @@ -35,74 +34,73 @@ class CheckResult; namespace helper { -template +template class SparseMdpPrctlHelper { public: - static std::map computeRewardBoundedValues( + static std::map computeRewardBoundedValues( Environment const& env, OptimizationDirection dir, rewardbounded::MultiDimensionalRewardUnfolding& rewardUnfolding, storm::storage::BitVector const& initialStates); - static std::vector computeNextProbabilities(Environment const& env, OptimizationDirection dir, - storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::BitVector const& nextStates); + static std::vector computeNextProbabilities(Environment const& env, OptimizationDirection dir, + storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::BitVector const& nextStates); - static MDPSparseModelCheckingHelperReturnType computeUntilProbabilities( - Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, + static MDPSparseModelCheckingHelperReturnType computeUntilProbabilities( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); - static MDPSparseModelCheckingHelperReturnType computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, - storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::SparseMatrix const& backwardTransitions, - storm::storage::BitVector const& psiStates, bool qualitative, - bool produceScheduler, bool useMecBasedTechnique = false); + static MDPSparseModelCheckingHelperReturnType computeGloballyProbabilities(Environment const& env, + storm::solver::SolveGoal&& goal, + storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& psiStates, bool qualitative, + bool produceScheduler, bool useMecBasedTechnique = false); template - static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, - storm::storage::SparseMatrix const& transitionMatrix, - RewardModelType const& rewardModel, uint_fast64_t stepCount); + static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, + storm::storage::SparseMatrix const& transitionMatrix, + RewardModelType const& rewardModel, uint_fast64_t stepCount); template - static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, - storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, - uint_fast64_t stepBound); + static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, + storm::storage::SparseMatrix const& transitionMatrix, + RewardModelType const& rewardModel, uint_fast64_t stepBound); template - static MDPSparseModelCheckingHelperReturnType computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, - storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::SparseMatrix const& backwardTransitions, - RewardModelType const& rewardModel, bool qualitative, bool produceScheduler, - ModelCheckerHint const& hint = ModelCheckerHint()); + static MDPSparseModelCheckingHelperReturnType computeTotalRewards(Environment const& env, + storm::solver::SolveGoal&& goal, + storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::SparseMatrix const& backwardTransitions, + RewardModelType const& rewardModel, bool qualitative, bool produceScheduler, + ModelCheckerHint const& hint = ModelCheckerHint()); template - static MDPSparseModelCheckingHelperReturnType computeReachabilityRewards( - Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, + static MDPSparseModelCheckingHelperReturnType computeReachabilityRewards( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); - static MDPSparseModelCheckingHelperReturnType computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, - storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::SparseMatrix const& backwardTransitions, - storm::storage::BitVector const& targetStates, bool qualitative, - bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); - -#ifdef STORM_HAVE_CARL - static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, - storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::SparseMatrix const& backwardTransitions, - storm::models::sparse::StandardRewardModel const& intervalRewardModel, - bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative); -#endif - - static std::unique_ptr computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, + static MDPSparseModelCheckingHelperReturnType computeReachabilityTimes( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, bool qualitative, + bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); + + static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, + storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::SparseMatrix const& backwardTransitions, + storm::models::sparse::StandardRewardModel const& intervalRewardModel, + bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative); + + static std::unique_ptr computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates); private: - static MDPSparseModelCheckingHelperReturnType computeReachabilityRewardsHelper( - Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, + static MDPSparseModelCheckingHelperReturnType computeReachabilityRewardsHelper( + Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, diff --git a/src/storm/modelchecker/propositional/SparsePropositionalModelChecker.cpp b/src/storm/modelchecker/propositional/SparsePropositionalModelChecker.cpp index f6e249f37f..094a2332cf 100644 --- a/src/storm/modelchecker/propositional/SparsePropositionalModelChecker.cpp +++ b/src/storm/modelchecker/propositional/SparsePropositionalModelChecker.cpp @@ -25,14 +25,14 @@ SparsePropositionalModelChecker::SparsePropositionalModelChecke } template -bool SparsePropositionalModelChecker::canHandle(CheckTask const& checkTask) const { +bool SparsePropositionalModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); return formula.isInFragment(storm::logic::propositional()); } template std::unique_ptr SparsePropositionalModelChecker::checkBooleanLiteralFormula( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::BooleanLiteralFormula const& stateFormula = checkTask.getFormula(); if (stateFormula.isTrueFormula()) { return std::unique_ptr(new ExplicitQualitativeCheckResult(storm::storage::BitVector(model.getNumberOfStates(), true))); @@ -43,7 +43,7 @@ std::unique_ptr SparsePropositionalModelChecker::c template std::unique_ptr SparsePropositionalModelChecker::checkAtomicLabelFormula( - Environment const& env, CheckTask const& checkTask) { + Environment const& env, CheckTask const& checkTask) { storm::logic::AtomicLabelFormula const& stateFormula = checkTask.getFormula(); STORM_LOG_THROW(model.hasLabel(stateFormula.getLabel()), storm::exceptions::InvalidPropertyException, "The property refers to unknown label '" << stateFormula.getLabel() << "'."); @@ -82,6 +82,8 @@ template class SparsePropositionalModelChecker>; template class SparsePropositionalModelChecker>; template class SparsePropositionalModelChecker>; + +template class SparsePropositionalModelChecker>; #endif } // namespace modelchecker } // namespace storm diff --git a/src/storm/modelchecker/propositional/SparsePropositionalModelChecker.h b/src/storm/modelchecker/propositional/SparsePropositionalModelChecker.h index 567a43ecb2..52a6c3c137 100644 --- a/src/storm/modelchecker/propositional/SparsePropositionalModelChecker.h +++ b/src/storm/modelchecker/propositional/SparsePropositionalModelChecker.h @@ -11,15 +11,16 @@ class SparsePropositionalModelChecker : public AbstractModelChecker, double, ValueType>::type; explicit SparsePropositionalModelChecker(SparseModelType const& model); // The implemented methods of the AbstractModelChecker interface. - virtual bool canHandle(CheckTask const& checkTask) const override; + virtual bool canHandle(CheckTask const& checkTask) const override; virtual std::unique_ptr checkBooleanLiteralFormula(Environment const& env, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; virtual std::unique_ptr checkAtomicLabelFormula(Environment const& env, - CheckTask const& checkTask) override; + CheckTask const& checkTask) override; protected: /*! diff --git a/src/storm/models/sparse/Ctmc.cpp b/src/storm/models/sparse/Ctmc.cpp index 6492ee5ee5..28aaaeaaa5 100644 --- a/src/storm/models/sparse/Ctmc.cpp +++ b/src/storm/models/sparse/Ctmc.cpp @@ -97,6 +97,7 @@ template class Ctmc; template class Ctmc>; template class Ctmc; +template class Ctmc; #endif } // namespace sparse } // namespace models diff --git a/src/storm/models/sparse/DeterministicModel.cpp b/src/storm/models/sparse/DeterministicModel.cpp index 0c5b010c74..11925869a9 100644 --- a/src/storm/models/sparse/DeterministicModel.cpp +++ b/src/storm/models/sparse/DeterministicModel.cpp @@ -66,6 +66,7 @@ template class DeterministicModel; template class DeterministicModel>; template class DeterministicModel; +template class DeterministicModel; #endif } // namespace sparse } // namespace models diff --git a/src/storm/models/sparse/Dtmc.cpp b/src/storm/models/sparse/Dtmc.cpp index 20f470c216..a477daf6bb 100644 --- a/src/storm/models/sparse/Dtmc.cpp +++ b/src/storm/models/sparse/Dtmc.cpp @@ -51,6 +51,7 @@ template class Dtmc; template class Dtmc>; template class Dtmc; +template class Dtmc; #endif } // namespace sparse } // namespace models diff --git a/src/storm/models/sparse/MarkovAutomaton.cpp b/src/storm/models/sparse/MarkovAutomaton.cpp index af916ae11d..279671ac79 100644 --- a/src/storm/models/sparse/MarkovAutomaton.cpp +++ b/src/storm/models/sparse/MarkovAutomaton.cpp @@ -265,6 +265,7 @@ template class MarkovAutomaton; template class MarkovAutomaton>; template class MarkovAutomaton; +template class MarkovAutomaton; #endif } // namespace sparse } // namespace models diff --git a/src/storm/models/sparse/Mdp.cpp b/src/storm/models/sparse/Mdp.cpp index 1e8db0b5a1..4d8b3b83d0 100644 --- a/src/storm/models/sparse/Mdp.cpp +++ b/src/storm/models/sparse/Mdp.cpp @@ -47,6 +47,7 @@ template class Mdp; template class Mdp>; template class Mdp; +template class Mdp; } // namespace sparse } // namespace models } // namespace storm diff --git a/src/storm/models/sparse/Model.cpp b/src/storm/models/sparse/Model.cpp index ab21ad8c00..79e19a5b2a 100644 --- a/src/storm/models/sparse/Model.cpp +++ b/src/storm/models/sparse/Model.cpp @@ -57,7 +57,11 @@ void Model::assertValidityOfComponents( // general components for all model types. STORM_LOG_THROW(this->getTransitionMatrix().getColumnCount() == stateCount, storm::exceptions::IllegalArgumentException, "Invalid column count of transition matrix."); - STORM_LOG_ASSERT(components.rateTransitions || this->hasParameters() || this->getTransitionMatrix().isProbabilistic(), "The matrix is not probabilistic."); + STORM_LOG_ASSERT(components.rateTransitions || this->hasParameters() || this->hasUncertainty() || this->getTransitionMatrix().isProbabilistic(), + "The matrix is not probabilistic."); + if (this->hasUncertainty()) { + STORM_LOG_ASSERT(this->getTransitionMatrix().hasOnlyPositiveEntries(), "Not all entries are (strictly) positive."); + } STORM_LOG_THROW(this->getStateLabeling().getNumberOfItems() == stateCount, storm::exceptions::IllegalArgumentException, "Invalid item count (" << this->getStateLabeling().getNumberOfItems() << ") of state labeling (states: " << stateCount << ")."); for (auto const& rewardModel : this->getRewardModels()) { @@ -646,6 +650,11 @@ bool Model::supportsParameters() const { return std::is_same::value; } +template +bool Model::supportsUncertainty() const { + return std::is_same::value; +} + template bool Model::hasParameters() const { if (!this->supportsParameters()) { @@ -661,6 +670,21 @@ bool Model::hasParameters() const { return false; } +template +bool Model::hasUncertainty() const { + if (!this->supportsUncertainty()) { + return false; + } + // Check for intervals + for (auto const& entry : this->getTransitionMatrix()) { + if (!storm::utility::isConstant(entry.getValue())) { + return true; + } + } + // Only constant values present + return false; +} + template bool Model::isExact() const { return storm::NumberTraits::IsExact && storm::NumberTraits::IsExact; @@ -676,7 +700,6 @@ std::unordered_map const& ModelrewardModels; } -#ifdef STORM_HAVE_CARL std::set getProbabilityParameters(Model const& model) { return storm::storage::getVariables(model.getTransitionMatrix()); } @@ -710,16 +733,13 @@ std::set getAllParameters(Model; +template class Model; -#ifdef STORM_HAVE_CARL template class Model; - template class Model>; template class Model; -#endif } // namespace sparse } // namespace models } // namespace storm diff --git a/src/storm/models/sparse/Model.h b/src/storm/models/sparse/Model.h index a3df75288f..58bb0fe2e1 100644 --- a/src/storm/models/sparse/Model.h +++ b/src/storm/models/sparse/Model.h @@ -1,5 +1,4 @@ -#ifndef STORM_MODELS_SPARSE_MODEL_H_ -#define STORM_MODELS_SPARSE_MODEL_H_ +#pragma once #include #include @@ -384,6 +383,23 @@ class Model : public storm::models::Model { virtual bool isExact() const override; + /*! + * Does it support uncertainty (e.g., via interval-valued entries). + * Notice that while parametric Markov models may be seen as uncertain, within storm,these models are not called uncertain. + * + * @return + */ + virtual bool supportsUncertainty() const; + + /*! + * Checks whether the model actually is uncertain, i.e., whether there is a non-singleton transition relation. + * Performance warning: the worst-case complexity is linear in the number of transitions. + * Notice that while parametric Markov models may be seen as uncertain, within storm,these models are not called uncertain. + * + * @return True iff the model can be instantiated in more than one way. + */ + virtual bool hasUncertainty() const; + virtual std::size_t hash() const; protected: @@ -454,7 +470,6 @@ class Model : public storm::models::Model { std::optional> choiceOrigins; }; -#ifdef STORM_HAVE_CARL /*! * Get all probability parameters occurring on transitions. * @param model Model. @@ -482,9 +497,6 @@ std::set getRateParameters(Model getAllParameters(Model const& model); -#endif } // namespace sparse } // namespace models } // namespace storm - -#endif /* STORM_MODELS_SPARSE_MODEL_H_ */ diff --git a/src/storm/models/sparse/NondeterministicModel.cpp b/src/storm/models/sparse/NondeterministicModel.cpp index 9bc38e6ba7..668927963a 100644 --- a/src/storm/models/sparse/NondeterministicModel.cpp +++ b/src/storm/models/sparse/NondeterministicModel.cpp @@ -193,6 +193,7 @@ template class NondeterministicModel; template class NondeterministicModel; template class NondeterministicModel>; template class NondeterministicModel; +template class NondeterministicModel; #endif } // namespace sparse } // namespace models diff --git a/src/storm/models/sparse/Pomdp.cpp b/src/storm/models/sparse/Pomdp.cpp index cdaf42d948..219d007edc 100644 --- a/src/storm/models/sparse/Pomdp.cpp +++ b/src/storm/models/sparse/Pomdp.cpp @@ -155,7 +155,7 @@ template class Pomdp; template class Pomdp; template class Pomdp>; template class Pomdp; - +template class Pomdp; } // namespace sparse } // namespace models } // namespace storm diff --git a/src/storm/models/sparse/Smg.cpp b/src/storm/models/sparse/Smg.cpp index 11124b2584..cff8895756 100644 --- a/src/storm/models/sparse/Smg.cpp +++ b/src/storm/models/sparse/Smg.cpp @@ -83,6 +83,8 @@ template class Smg; template class Smg>; template class Smg; +template class Smg; + } // namespace sparse } // namespace models } // namespace storm diff --git a/src/storm/models/sparse/StandardRewardModel.cpp b/src/storm/models/sparse/StandardRewardModel.cpp index 23cb8c280e..f38bbcb565 100644 --- a/src/storm/models/sparse/StandardRewardModel.cpp +++ b/src/storm/models/sparse/StandardRewardModel.cpp @@ -567,19 +567,37 @@ template std::vector StandardRewardModel::getT storm::storage::SparseMatrix const& transitionMatrix) const; template std::vector StandardRewardModel::getTotalRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& weights) const; +template std::vector StandardRewardModel::getTotalRewardVector( + uint_fast64_t numberOfRows, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& filter) const; +template std::vector StandardRewardModel::getTotalRewardVector( + storm::storage::SparseMatrix const& transitionMatrix) const; +template std::vector StandardRewardModel::getTotalRewardVector( + storm::storage::SparseMatrix const& transitionMatrix, std::vector const& weights) const; template std::vector StandardRewardModel::getTotalActionRewardVector( storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewardWeights) const; template storm::storage::BitVector StandardRewardModel::getStatesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; +template storm::storage::BitVector StandardRewardModel::getStatesWithFilter( + storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template storm::storage::BitVector StandardRewardModel::getChoicesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; +template storm::storage::BitVector StandardRewardModel::getChoicesWithFilter( + storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template void StandardRewardModel::setStateActionReward(uint_fast64_t choiceIndex, double const& newValue); template void StandardRewardModel::setStateActionReward(uint_fast64_t choiceIndex, storm::Interval const& newValue); template void StandardRewardModel::setStateReward(uint_fast64_t state, double const& newValue); template void StandardRewardModel::setStateReward(uint_fast64_t state, storm::Interval const& newValue); template void StandardRewardModel::clearRewardAtState(uint_fast64_t state, storm::storage::SparseMatrix const& transitionMatrix); +template void StandardRewardModel::clearRewardAtState(uint_fast64_t state, + storm::storage::SparseMatrix const& transitionMatrix); template void StandardRewardModel::reduceToStateBasedRewards(storm::storage::SparseMatrix const& transitionMatrix, bool reduceToStateRewards, std::vector const* weights); +template void StandardRewardModel::reduceToStateBasedRewards(storm::storage::SparseMatrix const& transitionMatrix, + bool reduceToStateRewards, std::vector const* weights); +template storm::storage::BitVector StandardRewardModel::getStatesWithZeroReward( + storm::storage::SparseMatrix const& transitionMatrix) const; +template storm::storage::BitVector StandardRewardModel::getChoicesWithZeroReward( + storm::storage::SparseMatrix const& transitionMatrix) const; template class StandardRewardModel; template std::ostream& operator<< (std::ostream& out, StandardRewardModel const& rewardModel); #endif diff --git a/src/storm/models/sparse/StochasticTwoPlayerGame.cpp b/src/storm/models/sparse/StochasticTwoPlayerGame.cpp index 896627cc99..5fd740d680 100644 --- a/src/storm/models/sparse/StochasticTwoPlayerGame.cpp +++ b/src/storm/models/sparse/StochasticTwoPlayerGame.cpp @@ -66,6 +66,8 @@ template class StochasticTwoPlayerGame; template class StochasticTwoPlayerGame>; template class StochasticTwoPlayerGame; template class StochasticTwoPlayerGame; +template class StochasticTwoPlayerGame; + #endif } // namespace sparse diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 0c8e942fa8..7f497452d4 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -23,29 +23,35 @@ namespace storm { namespace solver { -template -IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver( +template +IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver() : linearEquationSolverFactory(nullptr) { + STORM_LOG_ASSERT(static_cast(std::is_same_v), + "Only for interval models"); // This constructor is only meant for intervals where we can not pass a good factory yet. +} + +template +IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver( std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { // Intentionally left empty } -template -IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver( +template +IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver( storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory) - : StandardMinMaxLinearEquationSolver(A), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { + : StandardMinMaxLinearEquationSolver(A), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { // Intentionally left empty. } -template -IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver( +template +IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver( storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory) - : StandardMinMaxLinearEquationSolver(std::move(A)), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { + : StandardMinMaxLinearEquationSolver(std::move(A)), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { // Intentionally left empty. } -template -MinMaxMethod IterativeMinMaxLinearEquationSolver::getMethod(Environment const& env, bool isExactMode) const { +template +MinMaxMethod IterativeMinMaxLinearEquationSolver::getMethod(Environment const& env, bool isExactMode) const { // Adjust the method if none was specified and we want exact or sound computations. auto method = env.solver().minMax().getMethod(); @@ -73,13 +79,13 @@ MinMaxMethod IterativeMinMaxLinearEquationSolver::getMethod(Environme STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::SoundValueIteration || method == MinMaxMethod::IntervalIteration || method == MinMaxMethod::OptimisticValueIteration || method == MinMaxMethod::ViToPi, - storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); + storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method '" << toString(method) << "'."); return method; } -template -bool IterativeMinMaxLinearEquationSolver::internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, - std::vector const& b) const { +template +bool IterativeMinMaxLinearEquationSolver::internalSolveEquations(Environment const& env, OptimizationDirection dir, + std::vector& x, std::vector const& b) const { bool result = false; switch (getMethod(env, storm::NumberTraits::IsExact || env.solver().isForceExact())) { case MinMaxMethod::ValueIteration: @@ -110,10 +116,10 @@ bool IterativeMinMaxLinearEquationSolver::internalSolveEquations(Envi return result; } -template -void IterativeMinMaxLinearEquationSolver::setUpViOperator() const { +template +void IterativeMinMaxLinearEquationSolver::setUpViOperator() const { if (!viOperator) { - viOperator = std::make_shared>(); + viOperator = std::make_shared>(); viOperator->setMatrixBackwards(*this->A); } if (this->choiceFixedForRowGroup) { @@ -126,9 +132,9 @@ void IterativeMinMaxLinearEquationSolver::setUpViOperator() const { } } -template -void IterativeMinMaxLinearEquationSolver::extractScheduler(std::vector& x, std::vector const& b, - OptimizationDirection const& dir, bool updateX) const { +template +void IterativeMinMaxLinearEquationSolver::extractScheduler(std::vector& x, std::vector const& b, + OptimizationDirection const& dir, bool updateX, bool robust) const { // Make sure that storage for scheduler choices is available if (!this->schedulerChoices) { this->schedulerChoices = std::vector(x.size(), 0); @@ -140,153 +146,167 @@ void IterativeMinMaxLinearEquationSolver::extractScheduler(std::vecto if (!viOperator) { setUpViOperator(); } - storm::solver::helper::SchedulerTrackingHelper schedHelper(viOperator); - schedHelper.computeScheduler(x, b, dir, *this->schedulerChoices, updateX ? &x : nullptr); + storm::solver::helper::SchedulerTrackingHelper schedHelper(viOperator); + schedHelper.computeScheduler(x, b, dir, *this->schedulerChoices, robust, updateX ? &x : nullptr); } -template -bool IterativeMinMaxLinearEquationSolver::solveInducedEquationSystem(Environment const& env, - std::unique_ptr>& linearEquationSolver, - std::vector const& scheduler, std::vector& x, - std::vector& subB, std::vector const& originalB) const { - assert(subB.size() == x.size()); +template +bool IterativeMinMaxLinearEquationSolver::solveInducedEquationSystem( + Environment const& env, std::unique_ptr>& linearEquationSolver, std::vector const& scheduler, + std::vector& x, std::vector& subB, std::vector const& originalB) const { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We did not implement solving induced equation systems for interval-based models."); + // Implementing this requires linear equation systems with different value types and solution types (or some appropriate casting) + return false; + } else { + STORM_LOG_ASSERT(subB.size() == x.size(), "Sizes of subB and x do not coincide."); + STORM_LOG_ASSERT(this->linearEquationSolverFactory != nullptr, "Wrong constructor was called."); - // Resolve the nondeterminism according to the given scheduler. - bool convertToEquationSystem = this->linearEquationSolverFactory->getEquationProblemFormat(env) == LinearEquationSolverProblemFormat::EquationSystem; - storm::storage::SparseMatrix submatrix; + // Resolve the nondeterminism according to the given scheduler. + bool convertToEquationSystem = this->linearEquationSolverFactory->getEquationProblemFormat(env) == LinearEquationSolverProblemFormat::EquationSystem; + storm::storage::SparseMatrix submatrix; - submatrix = this->A->selectRowsFromRowGroups(scheduler, convertToEquationSystem); - if (convertToEquationSystem) { - submatrix.convertToEquationSystem(); - } - storm::utility::vector::selectVectorValues(subB, scheduler, this->A->getRowGroupIndices(), originalB); - - // Check whether the linear equation solver is already initialized - if (!linearEquationSolver) { - // Initialize the equation solver - linearEquationSolver = this->linearEquationSolverFactory->create(env, std::move(submatrix)); - linearEquationSolver->setBoundsFromOtherSolver(*this); - linearEquationSolver->setCachingEnabled(true); - } else { - // If the equation solver is already initialized, it suffices to update the matrix - linearEquationSolver->setMatrix(std::move(submatrix)); + submatrix = this->A->selectRowsFromRowGroups(scheduler, convertToEquationSystem); + if (convertToEquationSystem) { + submatrix.convertToEquationSystem(); + } + storm::utility::vector::selectVectorValues(subB, scheduler, this->A->getRowGroupIndices(), originalB); + + // Check whether the linear equation solver is already initialized + if (!linearEquationSolver) { + // Initialize the equation solver + linearEquationSolver = this->linearEquationSolverFactory->create(env, std::move(submatrix)); + linearEquationSolver->setBoundsFromOtherSolver(*this); + linearEquationSolver->setCachingEnabled(true); + } else { + // If the equation solver is already initialized, it suffices to update the matrix + linearEquationSolver->setMatrix(std::move(submatrix)); + } + // Solve the equation system for the 'DTMC' and return true upon success + return linearEquationSolver->solveEquations(env, x, subB); } - // Solve the equation system for the 'DTMC' and return true upon success - return linearEquationSolver->solveEquations(env, x, subB); } -template -bool IterativeMinMaxLinearEquationSolver::solveEquationsPolicyIteration(Environment const& env, OptimizationDirection dir, std::vector& x, - std::vector const& b) const { +template +bool IterativeMinMaxLinearEquationSolver::solveEquationsPolicyIteration(Environment const& env, OptimizationDirection dir, + std::vector& x, + std::vector const& b) const { std::vector scheduler = this->hasInitialScheduler() ? this->getInitialScheduler() : std::vector(this->A->getRowGroupCount()); return performPolicyIteration(env, dir, x, b, std::move(scheduler)); } -template -bool IterativeMinMaxLinearEquationSolver::performPolicyIteration(Environment const& env, OptimizationDirection dir, std::vector& x, - std::vector const& b, - std::vector&& initialPolicy) const { - std::vector scheduler = std::move(initialPolicy); - // Get a vector for storing the right-hand side of the inner equation system. - if (!auxiliaryRowGroupVector) { - auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount()); - } - std::vector& subB = *auxiliaryRowGroupVector; - - // The solver that we will use throughout the procedure. - std::unique_ptr> solver; - // The linear equation solver should be at least as precise as this solver - std::unique_ptr environmentOfSolverStorage; - auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); - if (!storm::NumberTraits::IsExact) { - bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision(); - bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion(); - if (changePrecision || changeRelative) { - environmentOfSolverStorage = std::make_unique(env); - boost::optional newPrecision; - boost::optional newRelative; - if (changePrecision) { - newPrecision = env.solver().minMax().getPrecision(); - } - if (changeRelative) { - newRelative = true; - } - environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative); +template +bool IterativeMinMaxLinearEquationSolver::performPolicyIteration( + Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b, + std::vector&& initialPolicy) const { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We did not implement policy iteration for interval-based models."); + return false; + } else { + std::vector scheduler = std::move(initialPolicy); + // Get a vector for storing the right-hand side of the inner equation system. + if (!auxiliaryRowGroupVector) { + auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount()); } - } - storm::Environment const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env; + std::vector& subB = *auxiliaryRowGroupVector; - SolverStatus status = SolverStatus::InProgress; - uint64_t iterations = 0; - this->startMeasureProgress(); - do { - // Solve the equation system for the 'DTMC'. - solveInducedEquationSystem(environmentOfSolver, solver, scheduler, x, subB, b); - - // Go through the multiplication result and see whether we can improve any of the choices. - bool schedulerImproved = false; - // Group refers to the state number - for (uint_fast64_t group = 0; group < this->A->getRowGroupCount(); ++group) { - if (!this->choiceFixedForRowGroup || !this->choiceFixedForRowGroup.get()[group]) { - // Only update when the choice is not fixed - uint_fast64_t currentChoice = scheduler[group]; - for (uint_fast64_t choice = this->A->getRowGroupIndices()[group]; choice < this->A->getRowGroupIndices()[group + 1]; ++choice) { - // If the choice is the currently selected one, we can skip it. - if (choice - this->A->getRowGroupIndices()[group] == currentChoice) { - continue; - } + // The solver that we will use throughout the procedure. + std::unique_ptr> solver; + // The linear equation solver should be at least as precise as this solver + std::unique_ptr environmentOfSolverStorage; + auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); + if (!storm::NumberTraits::IsExact) { + bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision(); + bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion(); + if (changePrecision || changeRelative) { + environmentOfSolverStorage = std::make_unique(env); + boost::optional newPrecision; + boost::optional newRelative; + if (changePrecision) { + newPrecision = env.solver().minMax().getPrecision(); + } + if (changeRelative) { + newRelative = true; + } + environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative); + } + } + storm::Environment const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env; - // Create the value of the choice. - ValueType choiceValue = storm::utility::zero(); - for (auto const& entry : this->A->getRow(choice)) { - choiceValue += entry.getValue() * x[entry.getColumn()]; - } - choiceValue += b[choice]; - - // If the value is strictly better than the solution of the inner system, we need to improve the scheduler. - // TODO: If the underlying solver is not precise, this might run forever (i.e. when a state has two choices where the (exact) values are - // equal). only changing the scheduler if the values are not equal (modulo precision) would make this unsound. - if (valueImproved(dir, x[group], choiceValue)) { - schedulerImproved = true; - scheduler[group] = choice - this->A->getRowGroupIndices()[group]; - x[group] = std::move(choiceValue); + SolverStatus status = SolverStatus::InProgress; + uint64_t iterations = 0; + this->startMeasureProgress(); + do { + // Solve the equation system for the 'DTMC'. + solveInducedEquationSystem(environmentOfSolver, solver, scheduler, x, subB, b); + + // Go through the multiplication result and see whether we can improve any of the choices. + bool schedulerImproved = false; + // Group refers to the state number + for (uint_fast64_t group = 0; group < this->A->getRowGroupCount(); ++group) { + if (!this->choiceFixedForRowGroup || !this->choiceFixedForRowGroup.get()[group]) { + // Only update when the choice is not fixed + uint_fast64_t currentChoice = scheduler[group]; + for (uint_fast64_t choice = this->A->getRowGroupIndices()[group]; choice < this->A->getRowGroupIndices()[group + 1]; ++choice) { + // If the choice is the currently selected one, we can skip it. + if (choice - this->A->getRowGroupIndices()[group] == currentChoice) { + continue; + } + + // Create the value of the choice. + ValueType choiceValue = storm::utility::zero(); + for (auto const& entry : this->A->getRow(choice)) { + choiceValue += entry.getValue() * x[entry.getColumn()]; + } + choiceValue += b[choice]; + + // If the value is strictly better than the solution of the inner system, we need to improve the scheduler. + // TODO: If the underlying solver is not precise, this might run forever (i.e. when a state has two choices where the (exact) values are + // equal). only changing the scheduler if the values are not equal (modulo precision) would make this unsound. + if (valueImproved(dir, x[group], choiceValue)) { + schedulerImproved = true; + scheduler[group] = choice - this->A->getRowGroupIndices()[group]; + x[group] = std::move(choiceValue); + } } } } - } - // If the scheduler did not improve, we are done. - if (!schedulerImproved) { - status = SolverStatus::Converged; - } + // If the scheduler did not improve, we are done. + if (!schedulerImproved) { + status = SolverStatus::Converged; + } - // Update environment variables. - ++iterations; - status = this->updateStatus(status, x, dir == storm::OptimizationDirection::Minimize ? SolverGuarantee::GreaterOrEqual : SolverGuarantee::LessOrEqual, - iterations, env.solver().minMax().getMaximalNumberOfIterations()); + // Update environment variables. + ++iterations; + status = + this->updateStatus(status, x, dir == storm::OptimizationDirection::Minimize ? SolverGuarantee::GreaterOrEqual : SolverGuarantee::LessOrEqual, + iterations, env.solver().minMax().getMaximalNumberOfIterations()); - // Potentially show progress. - this->showProgressIterative(iterations); - } while (status == SolverStatus::InProgress); + // Potentially show progress. + this->showProgressIterative(iterations); + } while (status == SolverStatus::InProgress); - STORM_LOG_INFO("Number of iterations: " << iterations); - this->reportStatus(status, iterations); + STORM_LOG_INFO("Number of iterations: " << iterations); + this->reportStatus(status, iterations); - // If requested, we store the scheduler for retrieval. - if (this->isTrackSchedulerSet()) { - this->schedulerChoices = std::move(scheduler); - } + // If requested, we store the scheduler for retrieval. + if (this->isTrackSchedulerSet()) { + this->schedulerChoices = std::move(scheduler); + } - if (!this->isCachingEnabled()) { - clearCache(); - } + if (!this->isCachingEnabled()) { + clearCache(); + } - return status == SolverStatus::Converged || status == SolverStatus::TerminatedEarly; + return status == SolverStatus::Converged || status == SolverStatus::TerminatedEarly; + } } -template -bool IterativeMinMaxLinearEquationSolver::valueImproved(OptimizationDirection dir, ValueType const& value1, ValueType const& value2) const { +template +bool IterativeMinMaxLinearEquationSolver::valueImproved(OptimizationDirection dir, ValueType const& value1, + ValueType const& value2) const { if (dir == OptimizationDirection::Minimize) { return value2 < value1; } else { @@ -294,8 +314,8 @@ bool IterativeMinMaxLinearEquationSolver::valueImproved(OptimizationD } } -template -MinMaxLinearEquationSolverRequirements IterativeMinMaxLinearEquationSolver::getRequirements( +template +MinMaxLinearEquationSolverRequirements IterativeMinMaxLinearEquationSolver::getRequirements( Environment const& env, boost::optional const& direction, bool const& hasInitialScheduler) const { auto method = getMethod(env, storm::NumberTraits::IsExact || env.solver().isForceExact()); @@ -304,9 +324,16 @@ MinMaxLinearEquationSolverRequirements IterativeMinMaxLinearEquationSolverhasInitialScheduler() || hasInitialScheduler); needsLinEqSolver |= method == MinMaxMethod::ViToPi; - MinMaxLinearEquationSolverRequirements requirements = needsLinEqSolver - ? MinMaxLinearEquationSolverRequirements(this->linearEquationSolverFactory->getRequirements(env)) - : MinMaxLinearEquationSolverRequirements(); + + MinMaxLinearEquationSolverRequirements requirements; + if constexpr (std::is_same_v) { + STORM_LOG_ASSERT(!needsLinEqSolver, "Intervals should not require a linear equation solver."); + // nothing to be done; + } else if (needsLinEqSolver) { + requirements = MinMaxLinearEquationSolverRequirements(this->linearEquationSolverFactory->getRequirements(env)); + } else { + // nothing to be done. + } if (method == MinMaxMethod::ValueIteration) { if (!this->hasUniqueSolution()) { // Traditional value iteration has no requirements if the solution is unique. @@ -368,7 +395,7 @@ MinMaxLinearEquationSolverRequirements IterativeMinMaxLinearEquationSolver +template ValueType computeMaxAbsDiff(std::vector const& allValues, storm::storage::BitVector const& relevantValues, std::vector const& oldValues) { ValueType result = storm::utility::zero(); auto oldValueIt = oldValues.begin(); @@ -379,7 +406,7 @@ ValueType computeMaxAbsDiff(std::vector const& allValues, storm::stor return result; } -template +template ValueType computeMaxAbsDiff(std::vector const& allOldValues, std::vector const& allNewValues, storm::storage::BitVector const& relevantValues) { ValueType result = storm::utility::zero(); @@ -389,61 +416,67 @@ ValueType computeMaxAbsDiff(std::vector const& allOldValues, std::vec return result; } -template -bool IterativeMinMaxLinearEquationSolver::solveEquationsOptimisticValueIteration(Environment const& env, OptimizationDirection dir, - std::vector& x, std::vector const& b) const { - if (!storm::utility::vector::hasNonZeroEntry(b)) { - // If all entries are zero, OVI might run in an endless loop. However, the result is easy in this case. - x.assign(x.size(), storm::utility::zero()); - if (this->isTrackSchedulerSet()) { - this->schedulerChoices = std::vector(x.size(), 0); +template +bool IterativeMinMaxLinearEquationSolver::solveEquationsOptimisticValueIteration(Environment const& env, OptimizationDirection dir, + std::vector& x, + std::vector const& b) const { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We did not implement optimistic value iteration for interval-based models."); + return false; + } else { + if (!storm::utility::vector::hasNonZeroEntry(b)) { + // If all entries are zero, OVI might run in an endless loop. However, the result is easy in this case. + x.assign(x.size(), storm::utility::zero()); + if (this->isTrackSchedulerSet()) { + this->schedulerChoices = std::vector(x.size(), 0); + } + return true; } - return true; - } - setUpViOperator(); + setUpViOperator(); - helper::OptimisticValueIterationHelper oviHelper(viOperator); - auto prec = storm::utility::convertNumber(env.solver().minMax().getPrecision()); - std::optional lowerBound, upperBound; - if (this->hasLowerBound()) { - lowerBound = this->getLowerBound(true); - } - if (this->hasUpperBound()) { - upperBound = this->getUpperBound(true); - } - uint64_t numIterations{0}; - auto oviCallback = [&](SolverStatus const& current, std::vector const& v) { - this->showProgressIterative(numIterations); - return this->updateStatus(current, v, SolverGuarantee::LessOrEqual, numIterations, env.solver().minMax().getMaximalNumberOfIterations()); - }; - this->createLowerBoundsVector(x); - std::optional guessingFactor; - if (env.solver().ovi().getUpperBoundGuessingFactor()) { - guessingFactor = storm::utility::convertNumber(*env.solver().ovi().getUpperBoundGuessingFactor()); - } - this->startMeasureProgress(); - auto status = oviHelper.OVI(x, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(), prec, dir, guessingFactor, lowerBound, upperBound, - oviCallback); - this->reportStatus(status, numIterations); + helper::OptimisticValueIterationHelper oviHelper(viOperator); + auto prec = storm::utility::convertNumber(env.solver().minMax().getPrecision()); + std::optional lowerBound, upperBound; + if (this->hasLowerBound()) { + lowerBound = this->getLowerBound(true); + } + if (this->hasUpperBound()) { + upperBound = this->getUpperBound(true); + } + uint64_t numIterations{0}; + auto oviCallback = [&](SolverStatus const& current, std::vector const& v) { + this->showProgressIterative(numIterations); + return this->updateStatus(current, v, SolverGuarantee::LessOrEqual, numIterations, env.solver().minMax().getMaximalNumberOfIterations()); + }; + this->createLowerBoundsVector(x); + std::optional guessingFactor; + if (env.solver().ovi().getUpperBoundGuessingFactor()) { + guessingFactor = storm::utility::convertNumber(*env.solver().ovi().getUpperBoundGuessingFactor()); + } + this->startMeasureProgress(); + auto status = oviHelper.OVI(x, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(), prec, dir, guessingFactor, lowerBound, + upperBound, oviCallback); + this->reportStatus(status, numIterations); - // If requested, we store the scheduler for retrieval. - if (this->isTrackSchedulerSet()) { - this->extractScheduler(x, b, dir); - } + // If requested, we store the scheduler for retrieval. + if (this->isTrackSchedulerSet()) { + this->extractScheduler(x, b, dir, this->isUncertaintyRobust()); + } - if (!this->isCachingEnabled()) { - clearCache(); - } + if (!this->isCachingEnabled()) { + clearCache(); + } - return status == SolverStatus::Converged || status == SolverStatus::TerminatedEarly; + return status == SolverStatus::Converged || status == SolverStatus::TerminatedEarly; + } } -template -bool IterativeMinMaxLinearEquationSolver::solveEquationsValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, - std::vector const& b) const { +template +bool IterativeMinMaxLinearEquationSolver::solveEquationsValueIteration(Environment const& env, OptimizationDirection dir, + std::vector& x, + std::vector const& b) const { setUpViOperator(); - // By default, we can not provide any guarantee SolverGuarantee guarantee = SolverGuarantee::None; @@ -496,7 +529,7 @@ bool IterativeMinMaxLinearEquationSolver::solveEquationsValueIteratio } } - storm::solver::helper::ValueIterationHelper viHelper(viOperator); + storm::solver::helper::ValueIterationHelper viHelper(viOperator); uint64_t numIterations{0}; auto viCallback = [&](SolverStatus const& current) { this->showProgressIterative(numIterations); @@ -504,14 +537,13 @@ bool IterativeMinMaxLinearEquationSolver::solveEquationsValueIteratio }; this->startMeasureProgress(); auto status = viHelper.VI(x, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(), - storm::utility::convertNumber(env.solver().minMax().getPrecision()), dir, viCallback, - env.solver().minMax().getMultiplicationStyle()); - + storm::utility::convertNumber(env.solver().minMax().getPrecision()), dir, viCallback, + env.solver().minMax().getMultiplicationStyle(), this->isUncertaintyRobust()); this->reportStatus(status, numIterations); // If requested, we store the scheduler for retrieval. if (this->isTrackSchedulerSet()) { - this->extractScheduler(x, b, dir); + this->extractScheduler(x, b, dir, this->isUncertaintyRobust()); } if (!this->isCachingEnabled()) { @@ -521,7 +553,7 @@ bool IterativeMinMaxLinearEquationSolver::solveEquationsValueIteratio return status == SolverStatus::Converged || status == SolverStatus::TerminatedEarly; } -template +template void preserveOldRelevantValues(std::vector const& allValues, storm::storage::BitVector const& relevantValues, std::vector& oldValues) { storm::utility::vector::selectVectorValues(oldValues, relevantValues, allValues); } @@ -532,93 +564,109 @@ void preserveOldRelevantValues(std::vector const& allValues, storm::s * extended to rewards by Baier, Klein, Leuschner, Parker and Wunderlich (Ensuring the Reliability of Your * Model Checker: Interval Iteration for Markov Decision Processes, CAV 2017). */ -template -bool IterativeMinMaxLinearEquationSolver::solveEquationsIntervalIteration(Environment const& env, OptimizationDirection dir, - std::vector& x, std::vector const& b) const { - setUpViOperator(); - helper::IntervalIterationHelper iiHelper(viOperator); - auto prec = storm::utility::convertNumber(env.solver().minMax().getPrecision()); - auto lowerBoundsCallback = [&](std::vector& vector) { this->createLowerBoundsVector(vector); }; - auto upperBoundsCallback = [&](std::vector& vector) { this->createUpperBoundsVector(vector); }; +template +bool IterativeMinMaxLinearEquationSolver::solveEquationsIntervalIteration(Environment const& env, OptimizationDirection dir, + std::vector& x, + std::vector const& b) const { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We did not implement intervaliteration for interval-based models"); + return false; + } else { + setUpViOperator(); + helper::IntervalIterationHelper iiHelper(viOperator); + auto prec = storm::utility::convertNumber(env.solver().minMax().getPrecision()); + auto lowerBoundsCallback = [&](std::vector& vector) { this->createLowerBoundsVector(vector); }; + auto upperBoundsCallback = [&](std::vector& vector) { this->createUpperBoundsVector(vector); }; + + uint64_t numIterations{0}; + auto iiCallback = [&](helper::IIData const& data) { + this->showProgressIterative(numIterations); + bool terminateEarly = this->hasCustomTerminationCondition() && this->getTerminationCondition().terminateNow(data.x, SolverGuarantee::LessOrEqual) && + this->getTerminationCondition().terminateNow(data.y, SolverGuarantee::GreaterOrEqual); + return this->updateStatus(data.status, terminateEarly, numIterations, env.solver().minMax().getMaximalNumberOfIterations()); + }; + std::optional optionalRelevantValues; + if (this->hasRelevantValues()) { + optionalRelevantValues = this->getRelevantValues(); + } + this->startMeasureProgress(); + auto status = iiHelper.II(x, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(), prec, lowerBoundsCallback, upperBoundsCallback, + dir, iiCallback, optionalRelevantValues); + this->reportStatus(status, numIterations); - uint64_t numIterations{0}; - auto iiCallback = [&](helper::IIData const& data) { - this->showProgressIterative(numIterations); - bool terminateEarly = this->hasCustomTerminationCondition() && this->getTerminationCondition().terminateNow(data.x, SolverGuarantee::LessOrEqual) && - this->getTerminationCondition().terminateNow(data.y, SolverGuarantee::GreaterOrEqual); - return this->updateStatus(data.status, terminateEarly, numIterations, env.solver().minMax().getMaximalNumberOfIterations()); - }; - std::optional optionalRelevantValues; - if (this->hasRelevantValues()) { - optionalRelevantValues = this->getRelevantValues(); - } - this->startMeasureProgress(); - auto status = iiHelper.II(x, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(), prec, lowerBoundsCallback, upperBoundsCallback, dir, - iiCallback, optionalRelevantValues); - this->reportStatus(status, numIterations); + // If requested, we store the scheduler for retrieval. + if (this->isTrackSchedulerSet()) { + this->extractScheduler(x, b, dir, this->isUncertaintyRobust()); + } - // If requested, we store the scheduler for retrieval. - if (this->isTrackSchedulerSet()) { - this->extractScheduler(x, b, dir); - } + if (!this->isCachingEnabled()) { + clearCache(); + } - if (!this->isCachingEnabled()) { - clearCache(); + return status == SolverStatus::Converged || status == SolverStatus::TerminatedEarly; } - - return status == SolverStatus::Converged || status == SolverStatus::TerminatedEarly; } -template -bool IterativeMinMaxLinearEquationSolver::solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, - std::vector& x, std::vector const& b) const { - // Prepare the solution vectors and the helper. - assert(x.size() == this->A->getRowGroupCount()); +template +bool IterativeMinMaxLinearEquationSolver::solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, + std::vector& x, + std::vector const& b) const { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "SoundVI does not handle interval-based models"); + return false; + } else { + // Prepare the solution vectors and the helper. + assert(x.size() == this->A->getRowGroupCount()); - std::optional lowerBound, upperBound; - if (this->hasLowerBound()) { - lowerBound = this->getLowerBound(true); - } - if (this->hasUpperBound()) { - upperBound = this->getUpperBound(true); - } + std::optional lowerBound, upperBound; + if (this->hasLowerBound()) { + lowerBound = this->getLowerBound(true); + } + if (this->hasUpperBound()) { + upperBound = this->getUpperBound(true); + } - setUpViOperator(); + setUpViOperator(); - auto precision = storm::utility::convertNumber(env.solver().minMax().getPrecision()); - uint64_t numIterations{0}; - auto sviCallback = [&](typename helper::SoundValueIterationHelper::SVIData const& current) { - this->showProgressIterative(numIterations); - return this->updateStatus(current.status, - this->hasCustomTerminationCondition() && current.checkCustomTerminationCondition(this->getTerminationCondition()), - numIterations, env.solver().minMax().getMaximalNumberOfIterations()); - }; - this->startMeasureProgress(); - helper::SoundValueIterationHelper sviHelper(viOperator); - std::optional optionalRelevantValues; - if (this->hasRelevantValues()) { - optionalRelevantValues = this->getRelevantValues(); - } - auto status = sviHelper.SVI(x, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(), precision, dir, lowerBound, upperBound, - sviCallback, optionalRelevantValues); + auto precision = storm::utility::convertNumber(env.solver().minMax().getPrecision()); + uint64_t numIterations{0}; + auto sviCallback = [&](typename helper::SoundValueIterationHelper::SVIData const& current) { + this->showProgressIterative(numIterations); + return this->updateStatus(current.status, + this->hasCustomTerminationCondition() && current.checkCustomTerminationCondition(this->getTerminationCondition()), + numIterations, env.solver().minMax().getMaximalNumberOfIterations()); + }; + this->startMeasureProgress(); + helper::SoundValueIterationHelper sviHelper(viOperator); + std::optional optionalRelevantValues; + if (this->hasRelevantValues()) { + optionalRelevantValues = this->getRelevantValues(); + } + auto status = sviHelper.SVI(x, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(), precision, dir, lowerBound, upperBound, + sviCallback, optionalRelevantValues); - // If requested, we store the scheduler for retrieval. - if (this->isTrackSchedulerSet()) { - this->extractScheduler(x, b, dir); - } + // If requested, we store the scheduler for retrieval. + if (this->isTrackSchedulerSet()) { + this->extractScheduler(x, b, dir, this->isUncertaintyRobust()); + } - this->reportStatus(status, numIterations); + this->reportStatus(status, numIterations); - if (!this->isCachingEnabled()) { - clearCache(); - } + if (!this->isCachingEnabled()) { + clearCache(); + } - return status == SolverStatus::Converged || status == SolverStatus::TerminatedEarly; + return status == SolverStatus::Converged || status == SolverStatus::TerminatedEarly; + } } -template -bool IterativeMinMaxLinearEquationSolver::solveEquationsViToPi(Environment const& env, OptimizationDirection dir, std::vector& x, - std::vector const& b) const { +template +bool IterativeMinMaxLinearEquationSolver::solveEquationsViToPi(Environment const& env, OptimizationDirection dir, + std::vector& x, std::vector const& b) const { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "ViToPi does not handle interval-based models"); + return false; + } // First create an (inprecise) vi solver to get a good initial strategy for the (potentially precise) policy iteration solver. std::vector initialSched; { @@ -642,72 +690,77 @@ bool IterativeMinMaxLinearEquationSolver::solveEquationsViToPi(Enviro return performPolicyIteration(env, dir, x, b, std::move(initialSched)); } -template -bool IterativeMinMaxLinearEquationSolver::solveEquationsRationalSearch(Environment const& env, OptimizationDirection dir, std::vector& x, - std::vector const& b) const { - // Set up two value iteration operators. One for exact and one for imprecise computations - setUpViOperator(); - std::shared_ptr> exactOp; - std::shared_ptr> impreciseOp; - std::function fixedChoicesCallback; - if (this->choiceFixedForRowGroup) { - // Ignore those rows that are not selected - assert(this->initialScheduler); - fixedChoicesCallback = [&](uint64_t groupIndex, uint64_t localRowIndex) { - return this->choiceFixedForRowGroup->get(groupIndex) && this->initialScheduler->at(groupIndex) != localRowIndex; - }; - } - - if constexpr (std::is_same_v) { - exactOp = viOperator; - impreciseOp = std::make_shared>(); - impreciseOp->setMatrixBackwards(this->A->template toValueType(), &this->A->getRowGroupIndices()); - if (this->choiceFixedForRowGroup) { - impreciseOp->setIgnoredRows(true, fixedChoicesCallback); - } +template +bool IterativeMinMaxLinearEquationSolver::solveEquationsRationalSearch(Environment const& env, OptimizationDirection dir, + std::vector& x, + std::vector const& b) const { + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Rational search does not handle interval-based models"); + return false; } else { - impreciseOp = viOperator; - exactOp = std::make_shared>(); - exactOp->setMatrixBackwards(this->A->template toValueType(), &this->A->getRowGroupIndices()); + // Set up two value iteration operators. One for exact and one for imprecise computations + setUpViOperator(); + std::shared_ptr> exactOp; + std::shared_ptr> impreciseOp; + std::function fixedChoicesCallback; if (this->choiceFixedForRowGroup) { - exactOp->setIgnoredRows(true, fixedChoicesCallback); + // Ignore those rows that are not selected + assert(this->initialScheduler); + fixedChoicesCallback = [&](uint64_t groupIndex, uint64_t localRowIndex) { + return this->choiceFixedForRowGroup->get(groupIndex) && this->initialScheduler->at(groupIndex) != localRowIndex; + }; } - } - storm::solver::helper::RationalSearchHelper rsHelper(exactOp, impreciseOp); - uint64_t numIterations{0}; - auto rsCallback = [&](SolverStatus const& current) { - this->showProgressIterative(numIterations); - return this->updateStatus(current, x, SolverGuarantee::None, numIterations, env.solver().minMax().getMaximalNumberOfIterations()); - }; - this->startMeasureProgress(); - auto status = rsHelper.RS(x, b, numIterations, storm::utility::convertNumber(env.solver().minMax().getPrecision()), dir, rsCallback); + if constexpr (std::is_same_v) { + exactOp = viOperator; + impreciseOp = std::make_shared>(); + impreciseOp->setMatrixBackwards(this->A->template toValueType(), &this->A->getRowGroupIndices()); + if (this->choiceFixedForRowGroup) { + impreciseOp->setIgnoredRows(true, fixedChoicesCallback); + } + } else if constexpr (std::is_same_v) { + impreciseOp = viOperator; + exactOp = std::make_shared>(); + exactOp->setMatrixBackwards(this->A->template toValueType(), &this->A->getRowGroupIndices()); + if (this->choiceFixedForRowGroup) { + exactOp->setIgnoredRows(true, fixedChoicesCallback); + } + } - this->reportStatus(status, numIterations); + storm::solver::helper::RationalSearchHelper rsHelper(exactOp, impreciseOp); + uint64_t numIterations{0}; + auto rsCallback = [&](SolverStatus const& current) { + this->showProgressIterative(numIterations); + return this->updateStatus(current, x, SolverGuarantee::None, numIterations, env.solver().minMax().getMaximalNumberOfIterations()); + }; + this->startMeasureProgress(); + auto status = rsHelper.RS(x, b, numIterations, storm::utility::convertNumber(env.solver().minMax().getPrecision()), dir, rsCallback); - // If requested, we store the scheduler for retrieval. - if (this->isTrackSchedulerSet()) { - this->extractScheduler(x, b, dir); - } + this->reportStatus(status, numIterations); - if (!this->isCachingEnabled()) { - clearCache(); - } + // If requested, we store the scheduler for retrieval. + if (this->isTrackSchedulerSet()) { + this->extractScheduler(x, b, dir, this->isUncertaintyRobust()); + } - return status == SolverStatus::Converged || status == SolverStatus::TerminatedEarly; + if (!this->isCachingEnabled()) { + clearCache(); + } + + return status == SolverStatus::Converged || status == SolverStatus::TerminatedEarly; + } } -template -void IterativeMinMaxLinearEquationSolver::clearCache() const { +template +void IterativeMinMaxLinearEquationSolver::clearCache() const { auxiliaryRowGroupVector.reset(); viOperator.reset(); - StandardMinMaxLinearEquationSolver::clearCache(); + StandardMinMaxLinearEquationSolver::clearCache(); } -template class IterativeMinMaxLinearEquationSolver; +template class IterativeMinMaxLinearEquationSolver; +template class IterativeMinMaxLinearEquationSolver; +template class IterativeMinMaxLinearEquationSolver; -#ifdef STORM_HAVE_CARL -template class IterativeMinMaxLinearEquationSolver; -#endif } // namespace solver } // namespace storm diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h index f3a1bd96c9..ac8fe0cd8b 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h @@ -17,16 +17,17 @@ class Environment; namespace solver { -template -class IterativeMinMaxLinearEquationSolver : public StandardMinMaxLinearEquationSolver { +template +class IterativeMinMaxLinearEquationSolver : public StandardMinMaxLinearEquationSolver { public: + IterativeMinMaxLinearEquationSolver(); IterativeMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory); IterativeMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory); IterativeMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory); - virtual bool internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, + virtual bool internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const override; virtual void clearCache() const override; @@ -39,24 +40,27 @@ class IterativeMinMaxLinearEquationSolver : public StandardMinMaxLinearEquationS MinMaxMethod getMethod(Environment const& env, bool isExactMode) const; bool solveInducedEquationSystem(Environment const& env, std::unique_ptr>& linearEquationSolver, - std::vector const& scheduler, std::vector& x, std::vector& subB, + std::vector const& scheduler, std::vector& x, std::vector& subB, std::vector const& originalB) const; - bool solveEquationsPolicyIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; - bool performPolicyIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b, + bool solveEquationsPolicyIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; + bool performPolicyIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b, std::vector&& initialPolicy) const; bool valueImproved(OptimizationDirection dir, ValueType const& value1, ValueType const& value2) const; - bool solveEquationsValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; - bool solveEquationsOptimisticValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, + bool solveEquationsValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; + bool solveEquationsOptimisticValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; - bool solveEquationsIntervalIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; - bool solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; - bool solveEquationsViToPi(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; + bool solveEquationsIntervalIteration(Environment const& env, OptimizationDirection dir, std::vector& x, + std::vector const& b) const; + bool solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, + std::vector const& b) const; + bool solveEquationsViToPi(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; - bool solveEquationsRationalSearch(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; + bool solveEquationsRationalSearch(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; void setUpViOperator() const; - void extractScheduler(std::vector& x, std::vector const& b, OptimizationDirection const& dir, bool updateX = true) const; + void extractScheduler(std::vector& x, std::vector const& b, OptimizationDirection const& dir, bool robust, + bool updateX = true) const; void createLinearEquationSolver(Environment const& env) const; @@ -64,7 +68,7 @@ class IterativeMinMaxLinearEquationSolver : public StandardMinMaxLinearEquationS std::unique_ptr> linearEquationSolverFactory; // possibly cached data - mutable std::shared_ptr> viOperator; + mutable std::shared_ptr> viOperator; mutable std::unique_ptr> auxiliaryRowGroupVector; // A.rowGroupCount() entries }; diff --git a/src/storm/solver/LinearEquationSolver.cpp b/src/storm/solver/LinearEquationSolver.cpp index 2fc6375927..a0afd56f88 100644 --- a/src/storm/solver/LinearEquationSolver.cpp +++ b/src/storm/solver/LinearEquationSolver.cpp @@ -153,6 +153,10 @@ template std::unique_ptr> GeneralLinearEquationSolverFactory::create(Environment const& env) const { EquationSolverType type = env.solver().getLinearEquationSolverType(); + if constexpr (std::is_same_v) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We have not implemented interval-based linear equation solvers"); + } + // Adjust the solver type if none was specified and we want sound/exact computations if (env.solver().isForceExact() && type != EquationSolverType::Native && type != EquationSolverType::Eigen && type != EquationSolverType::Elimination && type != EquationSolverType::Topological && type != EquationSolverType::Acyclic) { diff --git a/src/storm/solver/MinMaxLinearEquationSolver.cpp b/src/storm/solver/MinMaxLinearEquationSolver.cpp index e1dfc95f01..a7a5531dad 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/MinMaxLinearEquationSolver.cpp @@ -15,85 +15,85 @@ #include "storm/exceptions/NotImplementedException.h" #include "storm/utility/macros.h" -namespace storm { -namespace solver { +namespace storm::solver { -template -MinMaxLinearEquationSolver::MinMaxLinearEquationSolver(OptimizationDirectionSetting direction) +template +MinMaxLinearEquationSolver::MinMaxLinearEquationSolver(OptimizationDirectionSetting direction) : direction(direction), trackScheduler(false), uniqueSolution(false), noEndComponents(false), cachingEnabled(false), requirementsChecked(false) { // Intentionally left empty. } -template -MinMaxLinearEquationSolver::~MinMaxLinearEquationSolver() { +template +MinMaxLinearEquationSolver::~MinMaxLinearEquationSolver() { // Intentionally left empty. } -template -bool MinMaxLinearEquationSolver::solveEquations(Environment const& env, OptimizationDirection d, std::vector& x, - std::vector const& b) const { +template +bool MinMaxLinearEquationSolver::solveEquations(Environment const& env, OptimizationDirection d, std::vector& x, + std::vector const& b) const { STORM_LOG_WARN_COND_DEBUG(this->isRequirementsCheckedSet(), "The requirements of the solver have not been marked as checked. Please provide the appropriate check or mark the requirements " "as checked (if applicable)."); return internalSolveEquations(env, d, x, b); } -template -void MinMaxLinearEquationSolver::solveEquations(Environment const& env, std::vector& x, std::vector const& b) const { +template +void MinMaxLinearEquationSolver::solveEquations(Environment const& env, std::vector& x, + std::vector const& b) const { STORM_LOG_THROW(isSet(this->direction), storm::exceptions::IllegalFunctionCallException, "Optimization direction not set."); solveEquations(env, convert(this->direction), x, b); } -template -void MinMaxLinearEquationSolver::setOptimizationDirection(OptimizationDirection d) { +template +void MinMaxLinearEquationSolver::setOptimizationDirection(OptimizationDirection d) { direction = convert(d); } -template -void MinMaxLinearEquationSolver::unsetOptimizationDirection() { +template +void MinMaxLinearEquationSolver::unsetOptimizationDirection() { direction = OptimizationDirectionSetting::Unset; } -template -void MinMaxLinearEquationSolver::setHasUniqueSolution(bool value) { +template +void MinMaxLinearEquationSolver::setHasUniqueSolution(bool value) { uniqueSolution = value; } -template -bool MinMaxLinearEquationSolver::hasUniqueSolution() const { +template +bool MinMaxLinearEquationSolver::hasUniqueSolution() const { return uniqueSolution || noEndComponents; } -template -void MinMaxLinearEquationSolver::setHasNoEndComponents(bool value) { +template +void MinMaxLinearEquationSolver::setHasNoEndComponents(bool value) { noEndComponents = value; } -template -bool MinMaxLinearEquationSolver::hasNoEndComponents() const { +template +bool MinMaxLinearEquationSolver::hasNoEndComponents() const { return noEndComponents; } -template -void MinMaxLinearEquationSolver::setTrackScheduler(bool trackScheduler) { +template +void MinMaxLinearEquationSolver::setTrackScheduler(bool trackScheduler) { this->trackScheduler = trackScheduler; if (!this->trackScheduler) { schedulerChoices = boost::none; } } -template -bool MinMaxLinearEquationSolver::isTrackSchedulerSet() const { +template +bool MinMaxLinearEquationSolver::isTrackSchedulerSet() const { return this->trackScheduler; } -template -bool MinMaxLinearEquationSolver::hasScheduler() const { +template +bool MinMaxLinearEquationSolver::hasScheduler() const { return static_cast(schedulerChoices); } -template -storm::storage::Scheduler MinMaxLinearEquationSolver::computeScheduler() const { +template +storm::storage::Scheduler MinMaxLinearEquationSolver::computeScheduler() const { STORM_LOG_THROW(hasScheduler(), storm::exceptions::IllegalFunctionCallException, "Cannot retrieve scheduler, because none was generated."); storm::storage::Scheduler result(schedulerChoices->size()); uint_fast64_t state = 0; @@ -104,14 +104,14 @@ storm::storage::Scheduler MinMaxLinearEquationSolver::comp return result; } -template -std::vector const& MinMaxLinearEquationSolver::getSchedulerChoices() const { +template +std::vector const& MinMaxLinearEquationSolver::getSchedulerChoices() const { STORM_LOG_THROW(hasScheduler(), storm::exceptions::IllegalFunctionCallException, "Cannot retrieve scheduler choices, because they were not generated."); return schedulerChoices.get(); } -template -void MinMaxLinearEquationSolver::setCachingEnabled(bool value) { +template +void MinMaxLinearEquationSolver::setCachingEnabled(bool value) { if (cachingEnabled && !value) { // caching will be turned off. Hence we clear the cache at this point clearCache(); @@ -119,120 +119,139 @@ void MinMaxLinearEquationSolver::setCachingEnabled(bool value) { cachingEnabled = value; } -template -bool MinMaxLinearEquationSolver::isCachingEnabled() const { +template +bool MinMaxLinearEquationSolver::isCachingEnabled() const { return cachingEnabled; } -template -void MinMaxLinearEquationSolver::clearCache() const { +template +void MinMaxLinearEquationSolver::clearCache() const { // Intentionally left empty. } -template -void MinMaxLinearEquationSolver::setInitialScheduler(std::vector&& choices) { +template +void MinMaxLinearEquationSolver::setInitialScheduler(std::vector&& choices) { initialScheduler = std::move(choices); } -template -bool MinMaxLinearEquationSolver::hasInitialScheduler() const { +template +bool MinMaxLinearEquationSolver::hasInitialScheduler() const { return static_cast(initialScheduler); } -template -std::vector const& MinMaxLinearEquationSolver::getInitialScheduler() const { +template +std::vector const& MinMaxLinearEquationSolver::getInitialScheduler() const { return initialScheduler.get(); } -template -MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolver::getRequirements( +template +MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolver::getRequirements( Environment const&, boost::optional const& direction, bool const& hasInitialScheduler) const { return MinMaxLinearEquationSolverRequirements(); } -template -void MinMaxLinearEquationSolver::setRequirementsChecked(bool value) { +template +void MinMaxLinearEquationSolver::setRequirementsChecked(bool value) { this->requirementsChecked = value; } -template -bool MinMaxLinearEquationSolver::isRequirementsCheckedSet() const { +template +bool MinMaxLinearEquationSolver::isRequirementsCheckedSet() const { return requirementsChecked; } -template -void MinMaxLinearEquationSolver::setSchedulerFixedForRowGroup(storm::storage::BitVector&& schedulerFixedForRowGroup) { +template +void MinMaxLinearEquationSolver::setSchedulerFixedForRowGroup(storm::storage::BitVector&& schedulerFixedForRowGroup) { STORM_LOG_ASSERT(this->hasInitialScheduler(), "Expecting an initial scheduler to be set before setting the states for which the choices are fixed"); this->choiceFixedForRowGroup = std::move(schedulerFixedForRowGroup); } -template -MinMaxLinearEquationSolverFactory::MinMaxLinearEquationSolverFactory() : requirementsChecked(false) { +template +MinMaxLinearEquationSolverFactory::MinMaxLinearEquationSolverFactory() : requirementsChecked(false) { // Intentionally left empty } -template -void MinMaxLinearEquationSolverFactory::setRequirementsChecked(bool value) { +template +void MinMaxLinearEquationSolverFactory::setRequirementsChecked(bool value) { this->requirementsChecked = value; } -template -bool MinMaxLinearEquationSolverFactory::isRequirementsCheckedSet() const { +template +bool MinMaxLinearEquationSolverFactory::isRequirementsCheckedSet() const { return this->requirementsChecked; } -template -MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolverFactory::getRequirements( +template +void MinMaxLinearEquationSolver::setUncertaintyIsRobust(bool robust) { + this->robustUncertainty = robust; +} + +template +bool MinMaxLinearEquationSolver::isUncertaintyRobust() const { + return this->robustUncertainty; +} + +template +MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolverFactory::getRequirements( Environment const& env, bool hasUniqueSolution, bool hasNoEndComponents, boost::optional const& direction, bool hasInitialScheduler, bool trackScheduler) const { // Create dummy solver and ask it for requirements. - std::unique_ptr> solver = this->create(env); + std::unique_ptr> solver = this->create(env); solver->setTrackScheduler(trackScheduler); solver->setHasUniqueSolution(hasUniqueSolution); solver->setHasNoEndComponents(hasNoEndComponents); return solver->getRequirements(env, direction, hasInitialScheduler); } -template -std::unique_ptr> MinMaxLinearEquationSolverFactory::create( +template +std::unique_ptr> MinMaxLinearEquationSolverFactory::create( Environment const& env, storm::storage::SparseMatrix const& matrix) const { - std::unique_ptr> solver = this->create(env); + std::unique_ptr> solver = this->create(env); solver->setMatrix(matrix); return solver; } -template -std::unique_ptr> MinMaxLinearEquationSolverFactory::create( +template +std::unique_ptr> MinMaxLinearEquationSolverFactory::create( Environment const& env, storm::storage::SparseMatrix&& matrix) const { - std::unique_ptr> solver = this->create(env); + std::unique_ptr> solver = this->create(env); solver->setMatrix(std::move(matrix)); return solver; } -template -GeneralMinMaxLinearEquationSolverFactory::GeneralMinMaxLinearEquationSolverFactory() : MinMaxLinearEquationSolverFactory() { +template +GeneralMinMaxLinearEquationSolverFactory::GeneralMinMaxLinearEquationSolverFactory() + : MinMaxLinearEquationSolverFactory() { // Intentionally left empty. } -template -std::unique_ptr> GeneralMinMaxLinearEquationSolverFactory::create(Environment const& env) const { - std::unique_ptr> result; - auto method = env.solver().minMax().getMethod(); - if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || - method == MinMaxMethod::IntervalIteration || method == MinMaxMethod::SoundValueIteration || method == MinMaxMethod::OptimisticValueIteration || - method == MinMaxMethod::ViToPi) { - result = std::make_unique>(std::make_unique>()); - } else if (method == MinMaxMethod::Topological) { - result = std::make_unique>(); - } else if (method == MinMaxMethod::LinearProgramming) { - result = std::make_unique>(storm::utility::solver::getLpSolverFactory()); - } else if (method == MinMaxMethod::Acyclic) { - result = std::make_unique>(); +template +std::unique_ptr> GeneralMinMaxLinearEquationSolverFactory::create( + Environment const& env) const { + std::unique_ptr> result; + if constexpr (std::is_same_v) { + // TODO: consider robust minMax solver methods and corresponding entries in the environment. + return std::make_unique>(); } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique."); + // TODO some minmax linear equation solvers only support SolutionType == ValueType. + auto method = env.solver().minMax().getMethod(); + if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || + method == MinMaxMethod::IntervalIteration || method == MinMaxMethod::SoundValueIteration || method == MinMaxMethod::OptimisticValueIteration || + method == MinMaxMethod::ViToPi) { + result = std::make_unique>( + std::make_unique>()); + } else if (method == MinMaxMethod::Topological) { + result = std::make_unique>(); + } else if (method == MinMaxMethod::LinearProgramming) { + result = std::make_unique>(storm::utility::solver::getLpSolverFactory()); + } else if (method == MinMaxMethod::Acyclic) { + result = std::make_unique>(); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique."); + } + result->setRequirementsChecked(this->isRequirementsCheckedSet()); + return result; } - result->setRequirementsChecked(this->isRequirementsCheckedSet()); - return result; } template<> @@ -263,10 +282,11 @@ template class MinMaxLinearEquationSolver; template class MinMaxLinearEquationSolverFactory; template class GeneralMinMaxLinearEquationSolverFactory; -#ifdef STORM_HAVE_CARL template class MinMaxLinearEquationSolver; template class MinMaxLinearEquationSolverFactory; template class GeneralMinMaxLinearEquationSolverFactory; -#endif -} // namespace solver -} // namespace storm + +template class MinMaxLinearEquationSolver; +template class MinMaxLinearEquationSolverFactory; +template class GeneralMinMaxLinearEquationSolverFactory; +} // namespace storm::solver diff --git a/src/storm/solver/MinMaxLinearEquationSolver.h b/src/storm/solver/MinMaxLinearEquationSolver.h index e53a22d489..8a8175e249 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.h +++ b/src/storm/solver/MinMaxLinearEquationSolver.h @@ -1,5 +1,4 @@ -#ifndef STORM_SOLVER_MINMAXLINEAREQUATIONSOLVER_H_ -#define STORM_SOLVER_MINMAXLINEAREQUATIONSOLVER_H_ +#pragma once #include #include @@ -31,8 +30,8 @@ namespace solver { /*! * A class representing the interface that all min-max linear equation solvers shall implement. */ -template -class MinMaxLinearEquationSolver : public AbstractEquationSolver { +template +class MinMaxLinearEquationSolver : public AbstractEquationSolver { protected: MinMaxLinearEquationSolver(OptimizationDirectionSetting direction = OptimizationDirectionSetting::Unset); @@ -52,14 +51,14 @@ class MinMaxLinearEquationSolver : public AbstractEquationSolver { * solver, but may be ignored. * @param b The vector to add after matrix-vector multiplication. */ - bool solveEquations(Environment const& env, OptimizationDirection d, std::vector& x, std::vector const& b) const; + bool solveEquations(Environment const& env, OptimizationDirection d, std::vector& x, std::vector const& b) const; /*! * Behaves the same as the other variant of solveEquations, with the distinction that * instead of providing the optimization direction as an argument, the internally set optimization direction * is used. Note: this method can only be called after setting the optimization direction. */ - void solveEquations(Environment const& env, std::vector& x, std::vector const& b) const; + void solveEquations(Environment const& env, std::vector& x, std::vector const& b) const; /*! * Sets an optimization direction to use for calls to methods that do not explicitly provide one. @@ -71,6 +70,16 @@ class MinMaxLinearEquationSolver : public AbstractEquationSolver { */ void unsetOptimizationDirection(); + /*! + * Set whether uncertainty should be interpreted adverserially (robust) or not + */ + void setUncertaintyIsRobust(bool robust); + + /*! + * Is the uncertainty to be interpreted robustly (adverserially) or not? + */ + bool isUncertaintyRobust() const; + /*! * Sets the states for which the choices are fixed. * @param schedulerFixedForRowGroup bitvector with the states where the choices are fixed. @@ -138,7 +147,7 @@ class MinMaxLinearEquationSolver : public AbstractEquationSolver { */ bool isCachingEnabled() const; - /* + /*! * Clears the currently cached data that has been stored during previous calls of the solver. */ virtual void clearCache() const; @@ -178,7 +187,8 @@ class MinMaxLinearEquationSolver : public AbstractEquationSolver { bool isRequirementsCheckedSet() const; protected: - virtual bool internalSolveEquations(Environment const& env, OptimizationDirection d, std::vector& x, std::vector const& b) const = 0; + virtual bool internalSolveEquations(Environment const& env, OptimizationDirection d, std::vector& x, + std::vector const& b) const = 0; /// The optimization direction to use for calls to functions that do not provide it explicitly. Can also be unset. OptimizationDirectionSetting direction; @@ -189,9 +199,10 @@ class MinMaxLinearEquationSolver : public AbstractEquationSolver { /// The scheduler choices that induce the optimal values (if they could be successfully generated). mutable boost::optional> schedulerChoices; - // A scheduler that can be used by solvers that require a valid initial scheduler. + /// A scheduler that can be used by solvers that require a valid initial scheduler. boost::optional> initialScheduler; + /// boost::optional choiceFixedForRowGroup; private: @@ -206,17 +217,21 @@ class MinMaxLinearEquationSolver : public AbstractEquationSolver { /// A flag storing whether the requirements of the solver were checked. bool requirementsChecked; + + /// For uncertain models, if this flag is set to true, the uncertainty is resolved adverserially and angelically otherwise. + bool robustUncertainty; }; -template +template class MinMaxLinearEquationSolverFactory { public: MinMaxLinearEquationSolverFactory(); virtual ~MinMaxLinearEquationSolverFactory() = default; - std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix const& matrix) const; - std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix&& matrix) const; - virtual std::unique_ptr> create(Environment const& env) const = 0; + std::unique_ptr> create(Environment const& env, + storm::storage::SparseMatrix const& matrix) const; + std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix&& matrix) const; + virtual std::unique_ptr> create(Environment const& env) const = 0; /*! * Retrieves the requirements of the solver that would be created when calling create() right now. The @@ -232,18 +247,16 @@ class MinMaxLinearEquationSolverFactory { bool requirementsChecked; }; -template -class GeneralMinMaxLinearEquationSolverFactory : public MinMaxLinearEquationSolverFactory { +template +class GeneralMinMaxLinearEquationSolverFactory : public MinMaxLinearEquationSolverFactory { public: GeneralMinMaxLinearEquationSolverFactory(); // Make the other create methods visible. - using MinMaxLinearEquationSolverFactory::create; + using MinMaxLinearEquationSolverFactory::create; - virtual std::unique_ptr> create(Environment const& env) const override; + virtual std::unique_ptr> create(Environment const& env) const override; }; } // namespace solver } // namespace storm - -#endif /* STORM_SOLVER_MINMAXLINEAREQUATIONSOLVER_H_ */ diff --git a/src/storm/solver/SolveGoal.cpp b/src/storm/solver/SolveGoal.cpp index 5d4772b178..82eae70775 100644 --- a/src/storm/solver/SolveGoal.cpp +++ b/src/storm/solver/SolveGoal.cpp @@ -19,41 +19,42 @@ class SparseMatrix; namespace solver { -template -SolveGoal::SolveGoal() { +template +SolveGoal::SolveGoal() { // Intentionally left empty. } -template -SolveGoal::SolveGoal(bool minimize) : optimizationDirection(minimize ? OptimizationDirection::Minimize : OptimizationDirection::Maximize) { +template +SolveGoal::SolveGoal(bool minimize) + : optimizationDirection(minimize ? OptimizationDirection::Minimize : OptimizationDirection::Maximize) { // Intentionally left empty. } -template -SolveGoal::SolveGoal(OptimizationDirection optimizationDirection) : optimizationDirection(optimizationDirection) { +template +SolveGoal::SolveGoal(OptimizationDirection optimizationDirection) : optimizationDirection(optimizationDirection) { // Intentionally left empty. } -template -SolveGoal::SolveGoal(OptimizationDirection optimizationDirection, storm::logic::ComparisonType boundComparisonType, ValueType const& boundThreshold, - storm::storage::BitVector const& relevantValues) +template +SolveGoal::SolveGoal(OptimizationDirection optimizationDirection, storm::logic::ComparisonType boundComparisonType, + SolutionType const& boundThreshold, storm::storage::BitVector const& relevantValues) : optimizationDirection(optimizationDirection), comparisonType(boundComparisonType), threshold(boundThreshold), relevantValueVector(relevantValues) { // Intentionally left empty. } -template -SolveGoal::SolveGoal(OptimizationDirection optimizationDirection, storm::storage::BitVector const& relevantValues) +template +SolveGoal::SolveGoal(OptimizationDirection optimizationDirection, storm::storage::BitVector const& relevantValues) : optimizationDirection(optimizationDirection), relevantValueVector(relevantValues) { // Intentionally left empty. } -template -bool SolveGoal::hasDirection() const { +template +bool SolveGoal::hasDirection() const { return static_cast(optimizationDirection); } -template -void SolveGoal::oneMinus() { +template +void SolveGoal::oneMinus() { if (optimizationDirection) { if (optimizationDirection == storm::solver::OptimizationDirection::Minimize) { optimizationDirection = storm::solver::OptimizationDirection::Maximize; @@ -62,7 +63,7 @@ void SolveGoal::oneMinus() { } } if (threshold) { - this->threshold = storm::utility::one() - this->threshold.get(); + this->threshold = storm::utility::one() - this->threshold.get(); } if (comparisonType) { switch (comparisonType.get()) { @@ -82,68 +83,72 @@ void SolveGoal::oneMinus() { } } -template -bool SolveGoal::minimize() const { +template +bool SolveGoal::minimize() const { return optimizationDirection == OptimizationDirection::Minimize; } -template -OptimizationDirection SolveGoal::direction() const { +template +OptimizationDirection SolveGoal::direction() const { return optimizationDirection.get(); } -template -bool SolveGoal::isBounded() const { +template +bool SolveGoal::isBounded() const { return comparisonType && threshold && relevantValueVector; } -template -bool SolveGoal::boundIsALowerBound() const { +template +bool SolveGoal::boundIsALowerBound() const { return (comparisonType.get() == storm::logic::ComparisonType::Greater || comparisonType.get() == storm::logic::ComparisonType::GreaterEqual); } -template -bool SolveGoal::boundIsStrict() const { +template +bool SolveGoal::boundIsStrict() const { return (comparisonType.get() == storm::logic::ComparisonType::Greater || comparisonType.get() == storm::logic::ComparisonType::Less); } -template -ValueType const& SolveGoal::thresholdValue() const { +template +bool SolveGoal::isRobust() const { + return robustAgainstUncertainty; +} + +template +SolutionType const& SolveGoal::thresholdValue() const { return threshold.get(); } -template -bool SolveGoal::hasRelevantValues() const { +template +bool SolveGoal::hasRelevantValues() const { return static_cast(relevantValueVector); } -template -storm::storage::BitVector const& SolveGoal::relevantValues() const { +template +storm::storage::BitVector const& SolveGoal::relevantValues() const { return relevantValueVector.get(); } -template -storm::storage::BitVector& SolveGoal::relevantValues() { +template +storm::storage::BitVector& SolveGoal::relevantValues() { return relevantValueVector.get(); } -template -void SolveGoal::restrictRelevantValues(storm::storage::BitVector const& filter) { +template +void SolveGoal::restrictRelevantValues(storm::storage::BitVector const& filter) { if (relevantValueVector) { relevantValueVector = relevantValueVector.get() % filter; } } -template -void SolveGoal::setRelevantValues(storm::storage::BitVector&& values) { +template +void SolveGoal::setRelevantValues(storm::storage::BitVector&& values) { relevantValueVector = std::move(values); } template class SolveGoal; - -#ifdef STORM_HAVE_CARL template class SolveGoal; template class SolveGoal; -#endif +template class SolveGoal; + } // namespace solver } // namespace storm diff --git a/src/storm/solver/SolveGoal.h b/src/storm/solver/SolveGoal.h index 796f72b8c5..f5f672f8e1 100644 --- a/src/storm/solver/SolveGoal.h +++ b/src/storm/solver/SolveGoal.h @@ -18,8 +18,7 @@ class SparseMatrix; } namespace solver { -template -class MinMaxLinearEquationSolverFactory; + template class LinearEquationSolverFactory; } // namespace solver @@ -37,17 +36,16 @@ class Model; namespace solver { template -class MinMaxLinearEquationSolver; -template class LinearEquationSolver; -template +template class SolveGoal { public: SolveGoal(); template - SolveGoal(storm::models::sparse::Model const& model, storm::modelchecker::CheckTask const& checkTask) { + SolveGoal(storm::models::sparse::Model const& model, + storm::modelchecker::CheckTask const& checkTask) { if (checkTask.isOptimizationDirectionSet()) { optimizationDirection = checkTask.getOptimizationDirection(); } @@ -58,11 +56,12 @@ class SolveGoal { comparisonType = checkTask.getBoundComparisonType(); threshold = checkTask.getBoundThreshold(); } + robustAgainstUncertainty = checkTask.getRobustUncertainty(); } SolveGoal(bool minimize); SolveGoal(OptimizationDirection d); - SolveGoal(OptimizationDirection d, storm::logic::ComparisonType boundComparisonType, ValueType const& boundThreshold, + SolveGoal(OptimizationDirection d, storm::logic::ComparisonType boundComparisonType, SolutionType const& boundThreshold, storm::storage::BitVector const& relevantValues); SolveGoal(OptimizationDirection d, storm::storage::BitVector const& relevantValues); @@ -77,13 +76,15 @@ class SolveGoal { OptimizationDirection direction() const; + bool isRobust() const; + bool isBounded() const; bool boundIsALowerBound() const; bool boundIsStrict() const; - ValueType const& thresholdValue() const; + SolutionType const& thresholdValue() const; bool hasRelevantValues() const; @@ -97,22 +98,24 @@ class SolveGoal { boost::optional optimizationDirection; boost::optional comparisonType; - boost::optional threshold; + boost::optional threshold; boost::optional relevantValueVector; + bool robustAgainstUncertainty = true; // If set to false, the uncertainty is interpreted as controllable. }; -template -std::unique_ptr> configureMinMaxLinearEquationSolver( - Environment const& env, SolveGoal&& goal, storm::solver::MinMaxLinearEquationSolverFactory const& factory, MatrixType&& matrix) { - std::unique_ptr> solver = factory.create(env, std::forward(matrix)); +template +std::unique_ptr> configureMinMaxLinearEquationSolver( + Environment const& env, SolveGoal&& goal, storm::solver::MinMaxLinearEquationSolverFactory const& factory, + MatrixType&& matrix) { + std::unique_ptr> solver = factory.create(env, std::forward(matrix)); solver->setOptimizationDirection(goal.direction()); if (goal.isBounded()) { if (goal.boundIsALowerBound()) { - solver->setTerminationCondition(std::make_unique>( + solver->setTerminationCondition(std::make_unique>( goal.relevantValues(), goal.boundIsStrict(), goal.thresholdValue(), true)); } else { - solver->setTerminationCondition(std::make_unique>(goal.relevantValues(), goal.boundIsStrict(), - goal.thresholdValue(), false)); + solver->setTerminationCondition(std::make_unique>( + goal.relevantValues(), goal.boundIsStrict(), goal.thresholdValue(), false)); } } if (goal.hasRelevantValues()) { @@ -121,9 +124,10 @@ std::unique_ptr> configureM return solver; } -template +template std::unique_ptr> configureLinearEquationSolver( - Environment const& env, SolveGoal&& goal, storm::solver::LinearEquationSolverFactory const& factory, MatrixType&& matrix) { + Environment const& env, SolveGoal&& goal, storm::solver::LinearEquationSolverFactory const& factory, + MatrixType&& matrix) { std::unique_ptr> solver = factory.create(env, std::forward(matrix)); if (goal.isBounded()) { solver->setTerminationCondition(std::make_unique>(goal.relevantValues(), goal.boundIsStrict(), diff --git a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp index 9fa8c54255..e65879631c 100644 --- a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp @@ -14,43 +14,41 @@ #include "storm/exceptions/NotImplementedException.h" #include "storm/utility/macros.h" #include "storm/utility/vector.h" -namespace storm { -namespace solver { +namespace storm::solver { -template -StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver() : A(nullptr) { +template +StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver() : A(nullptr) { // Intentionally left empty. } -template -StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) : localA(nullptr), A(&A) { +template +StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) + : localA(nullptr), A(&A) { // Intentionally left empty. } -template -StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A) +template +StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A) : localA(std::make_unique>(std::move(A))), A(localA.get()) { // Intentionally left empty. } -template -void StandardMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& matrix) { +template +void StandardMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& matrix) { this->localA = nullptr; this->A = &matrix; this->clearCache(); } -template -void StandardMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& matrix) { +template +void StandardMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& matrix) { this->localA = std::make_unique>(std::move(matrix)); this->A = this->localA.get(); this->clearCache(); } template class StandardMinMaxLinearEquationSolver; - -#ifdef STORM_HAVE_CARL template class StandardMinMaxLinearEquationSolver; -#endif -} // namespace solver -} // namespace storm +template class StandardMinMaxLinearEquationSolver; + +} // namespace storm::solver diff --git a/src/storm/solver/StandardMinMaxLinearEquationSolver.h b/src/storm/solver/StandardMinMaxLinearEquationSolver.h index 35e7e8e0ab..507ee7f4f0 100644 --- a/src/storm/solver/StandardMinMaxLinearEquationSolver.h +++ b/src/storm/solver/StandardMinMaxLinearEquationSolver.h @@ -9,8 +9,8 @@ class Environment; namespace solver { -template -class StandardMinMaxLinearEquationSolver : public MinMaxLinearEquationSolver { +template +class StandardMinMaxLinearEquationSolver : public MinMaxLinearEquationSolver { public: StandardMinMaxLinearEquationSolver(); explicit StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A); diff --git a/src/storm/solver/TerminationCondition.cpp b/src/storm/solver/TerminationCondition.cpp index 05b3061af2..edb9890f12 100644 --- a/src/storm/solver/TerminationCondition.cpp +++ b/src/storm/solver/TerminationCondition.cpp @@ -163,13 +163,18 @@ template class NoTerminationCondition; template class TerminateIfFilteredSumExceedsThreshold; template class TerminateIfFilteredExtremumExceedsThreshold; template class TerminateIfFilteredExtremumBelowThreshold; -#ifdef STORM_HAVE_CARL + template class TerminationCondition; template class NoTerminationCondition; template class TerminateIfFilteredSumExceedsThreshold; template class TerminateIfFilteredExtremumExceedsThreshold; template class TerminateIfFilteredExtremumBelowThreshold; -#endif + +template class TerminationCondition; +template class NoTerminationCondition; +template class TerminateIfFilteredSumExceedsThreshold; +template class TerminateIfFilteredExtremumExceedsThreshold; +template class TerminateIfFilteredExtremumBelowThreshold; } // namespace solver } // namespace storm diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index a77a84e9fb..23cd46de66 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -16,26 +16,26 @@ namespace storm { namespace solver { -template -TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver() { +template +TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver() { // Intentionally left empty. } -template -TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) - : StandardMinMaxLinearEquationSolver(A) { +template +TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) + : StandardMinMaxLinearEquationSolver(A) { // Intentionally left empty. } -template -TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A) - : StandardMinMaxLinearEquationSolver(std::move(A)) { +template +TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A) + : StandardMinMaxLinearEquationSolver(std::move(A)) { // Intentionally left empty. } -template -storm::Environment TopologicalMinMaxLinearEquationSolver::getEnvironmentForUnderlyingSolver(storm::Environment const& env, - bool adaptPrecision) const { +template +storm::Environment TopologicalMinMaxLinearEquationSolver::getEnvironmentForUnderlyingSolver(storm::Environment const& env, + bool adaptPrecision) const { storm::Environment subEnv(env); subEnv.solver().minMax().setMethod(env.solver().topological().getUnderlyingMinMaxMethod(), env.solver().topological().isUnderlyingMinMaxMethodSetFromDefault()); @@ -48,9 +48,10 @@ storm::Environment TopologicalMinMaxLinearEquationSolver::getEnvironm return subEnv; } -template -bool TopologicalMinMaxLinearEquationSolver::internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, - std::vector const& b) const { +template +bool TopologicalMinMaxLinearEquationSolver::internalSolveEquations(Environment const& env, OptimizationDirection dir, + std::vector& x, + std::vector const& b) const { STORM_LOG_ASSERT(x.size() == this->A->getRowGroupCount(), "Provided x-vector has invalid size."); STORM_LOG_ASSERT(b.size() == this->A->getRowCount(), "Provided b-vector has invalid size."); @@ -151,8 +152,8 @@ bool TopologicalMinMaxLinearEquationSolver::internalSolveEquations(En return returnValue; } -template -void TopologicalMinMaxLinearEquationSolver::createSortedSccDecomposition(bool needLongestChainSize) const { +template +void TopologicalMinMaxLinearEquationSolver::createSortedSccDecomposition(bool needLongestChainSize) const { // Obtain the scc decomposition this->sortedSccDecomposition = std::make_unique>( *this->A, storm::storage::StronglyConnectedComponentDecompositionOptions().forceTopologicalSort().computeSccDepths(needLongestChainSize)); @@ -161,9 +162,10 @@ void TopologicalMinMaxLinearEquationSolver::createSortedSccDecomposit } } -template -bool TopologicalMinMaxLinearEquationSolver::solveTrivialScc(uint64_t const& sccState, OptimizationDirection dir, std::vector& globalX, - std::vector const& globalB) const { +template +bool TopologicalMinMaxLinearEquationSolver::solveTrivialScc(uint64_t const& sccState, OptimizationDirection dir, + std::vector& globalX, + std::vector const& globalB) const { ValueType& xi = globalX[sccState]; if (this->choiceFixedForRowGroup && this->choiceFixedForRowGroup.get()[sccState]) { // if the choice in the scheduler is fixed we only update for the fixed choice @@ -246,10 +248,10 @@ bool TopologicalMinMaxLinearEquationSolver::solveTrivialScc(uint64_t return true; } -template -bool TopologicalMinMaxLinearEquationSolver::solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, - OptimizationDirection dir, std::vector& x, - std::vector const& b) const { +template +bool TopologicalMinMaxLinearEquationSolver::solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, + OptimizationDirection dir, std::vector& x, + std::vector const& b) const { STORM_LOG_ASSERT(!this->choiceFixedForRowGroup || this->choiceFixedForRowGroup.get().empty(), "Expecting no fixed choices for states when solving the fully connected equation system"); if (!this->sccSolver) { @@ -289,10 +291,11 @@ bool TopologicalMinMaxLinearEquationSolver::solveFullyConnectedEquati return res; } -template -bool TopologicalMinMaxLinearEquationSolver::solveScc(storm::Environment const& sccSolverEnvironment, OptimizationDirection dir, - storm::storage::BitVector const& sccRowGroups, storm::storage::BitVector const& sccRows, - std::vector& globalX, std::vector const& globalB) const { +template +bool TopologicalMinMaxLinearEquationSolver::solveScc(storm::Environment const& sccSolverEnvironment, OptimizationDirection dir, + storm::storage::BitVector const& sccRowGroups, + storm::storage::BitVector const& sccRows, std::vector& globalX, + std::vector const& globalB) const { // Set up the SCC solver if (!this->sccSolver) { this->sccSolver = GeneralMinMaxLinearEquationSolverFactory().create(sccSolverEnvironment); @@ -389,8 +392,8 @@ bool TopologicalMinMaxLinearEquationSolver::solveScc(storm::Environme return res; } -template -MinMaxLinearEquationSolverRequirements TopologicalMinMaxLinearEquationSolver::getRequirements( +template +MinMaxLinearEquationSolverRequirements TopologicalMinMaxLinearEquationSolver::getRequirements( Environment const& env, boost::optional const& direction, bool const& hasInitialScheduler) const { // Return the requirements of the underlying solver return GeneralMinMaxLinearEquationSolverFactory().getRequirements(getEnvironmentForUnderlyingSolver(env), this->hasUniqueSolution(), @@ -398,20 +401,18 @@ MinMaxLinearEquationSolverRequirements TopologicalMinMaxLinearEquationSolverisTrackSchedulerSet()); } -template -void TopologicalMinMaxLinearEquationSolver::clearCache() const { +template +void TopologicalMinMaxLinearEquationSolver::clearCache() const { sortedSccDecomposition.reset(); longestSccChainSize = boost::none; sccSolver.reset(); auxiliaryRowGroupVector.reset(); - StandardMinMaxLinearEquationSolver::clearCache(); + StandardMinMaxLinearEquationSolver::clearCache(); } // Explicitly instantiate the min max linear equation solver. template class TopologicalMinMaxLinearEquationSolver; - -#ifdef STORM_HAVE_CARL template class TopologicalMinMaxLinearEquationSolver; -#endif + } // namespace solver } // namespace storm diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h index 061f1fa77b..281da93cd4 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h @@ -11,8 +11,8 @@ class Environment; namespace solver { -template -class TopologicalMinMaxLinearEquationSolver : public StandardMinMaxLinearEquationSolver { +template +class TopologicalMinMaxLinearEquationSolver : public StandardMinMaxLinearEquationSolver { public: TopologicalMinMaxLinearEquationSolver(); TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A); @@ -27,7 +27,7 @@ class TopologicalMinMaxLinearEquationSolver : public StandardMinMaxLinearEquatio bool const& hasInitialScheduler = false) const override; protected: - virtual bool internalSolveEquations(storm::Environment const& env, OptimizationDirection d, std::vector& x, + virtual bool internalSolveEquations(storm::Environment const& env, OptimizationDirection d, std::vector& x, std::vector const& b) const override; private: @@ -40,7 +40,7 @@ class TopologicalMinMaxLinearEquationSolver : public StandardMinMaxLinearEquatio // ... for the case that the SCC is trivial bool solveTrivialScc(uint64_t const& sccState, OptimizationDirection d, std::vector& globalX, std::vector const& globalB) const; // ... for the case that there is just one large SCC - bool solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, OptimizationDirection d, std::vector& x, + bool solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, OptimizationDirection d, std::vector& x, std::vector const& b) const; // ... for the remaining cases (1 < scc.size() < x.size()) bool solveScc(storm::Environment const& sccSolverEnvironment, OptimizationDirection d, storm::storage::BitVector const& sccRowGroups, diff --git a/src/storm/solver/helper/IntervalterationHelper.h b/src/storm/solver/helper/IntervalterationHelper.h index 6ed00770fd..760053a2d3 100644 --- a/src/storm/solver/helper/IntervalterationHelper.h +++ b/src/storm/solver/helper/IntervalterationHelper.h @@ -5,13 +5,11 @@ #include "storm/solver/OptimizationDirection.h" #include "storm/solver/SolverStatus.h" +#include "storm/solver/helper/ValueIterationOperatorForward.h" #include "storm/storage/BitVector.h" namespace storm::solver::helper { -template -class ValueIterationOperator; - template struct IIData { std::vector const& x; diff --git a/src/storm/solver/helper/OptimisticValueIterationHelper.h b/src/storm/solver/helper/OptimisticValueIterationHelper.h index 08b421ee0b..c292c5a6d5 100644 --- a/src/storm/solver/helper/OptimisticValueIterationHelper.h +++ b/src/storm/solver/helper/OptimisticValueIterationHelper.h @@ -8,10 +8,9 @@ #include "storm/solver/OptimizationDirection.h" #include "storm/solver/SolverStatus.h" -namespace storm::solver::helper { +#include "storm/solver/helper/ValueIterationOperatorForward.h" -template -class ValueIterationOperator; +namespace storm::solver::helper { /*! * Implements Optimistic value iteration diff --git a/src/storm/solver/helper/RationalSearchHelper.h b/src/storm/solver/helper/RationalSearchHelper.h index a5b7548c37..45af97a247 100644 --- a/src/storm/solver/helper/RationalSearchHelper.h +++ b/src/storm/solver/helper/RationalSearchHelper.h @@ -9,10 +9,9 @@ #include "storm/solver/OptimizationDirection.h" #include "storm/solver/SolverStatus.h" -namespace storm::solver::helper { +#include "storm/solver/helper/ValueIterationOperatorForward.h" -template -class ValueIterationOperator; +namespace storm::solver::helper { enum class RSResult { InProgress, Converged, PrecisionExceeded }; diff --git a/src/storm/solver/helper/SchedulerTrackingHelper.cpp b/src/storm/solver/helper/SchedulerTrackingHelper.cpp index f9f04adb4f..0995db7de3 100644 --- a/src/storm/solver/helper/SchedulerTrackingHelper.cpp +++ b/src/storm/solver/helper/SchedulerTrackingHelper.cpp @@ -66,36 +66,48 @@ class SchedulerTrackingBackend { uint64_t currChoice; }; -template -SchedulerTrackingHelper::SchedulerTrackingHelper(std::shared_ptr> viOperator) : viOperator(viOperator) { +template +SchedulerTrackingHelper::SchedulerTrackingHelper(std::shared_ptr> viOperator) + : viOperator(viOperator) { // Intentionally left empty } -template -template -bool SchedulerTrackingHelper::computeScheduler(std::vector& operandIn, std::vector const& offsets, - std::vector& schedulerStorage, std::vector* operandOut) const { +template +template +bool SchedulerTrackingHelper::computeScheduler(std::vector& operandIn, std::vector const& offsets, + std::vector& schedulerStorage, std::vector* operandOut) const { bool const applyUpdates = operandOut != nullptr; - SchedulerTrackingBackend backend(schedulerStorage, viOperator->getRowGroupIndices(), applyUpdates); + SchedulerTrackingBackend backend(schedulerStorage, viOperator->getRowGroupIndices(), applyUpdates); if (applyUpdates) { - return viOperator->template apply(*operandOut, operandIn, offsets, backend); + return viOperator->template applyRobust(*operandOut, operandIn, offsets, backend); } else { - return viOperator->template applyInPlace(operandIn, offsets, backend); + return viOperator->template applyInPlaceRobust(operandIn, offsets, backend); } } -template -bool SchedulerTrackingHelper::computeScheduler(std::vector& operandIn, std::vector const& offsets, - storm::OptimizationDirection const& dir, std::vector& schedulerStorage, - std::vector* operandOut) const { +template +bool SchedulerTrackingHelper::computeScheduler(std::vector& operandIn, std::vector const& offsets, + storm::OptimizationDirection const& dir, std::vector& schedulerStorage, + bool robust, std::vector* operandOut) const { if (maximize(dir)) { - return computeScheduler(operandIn, offsets, schedulerStorage, operandOut); + if (robust) { + return computeScheduler(operandIn, offsets, schedulerStorage, + operandOut); + } else { + return computeScheduler(operandIn, offsets, schedulerStorage, + operandOut); + } } else { - return computeScheduler(operandIn, offsets, schedulerStorage, operandOut); + if (robust) { + return computeScheduler(operandIn, offsets, schedulerStorage, operandOut); + } else { + return computeScheduler(operandIn, offsets, schedulerStorage, operandOut); + } } } template class SchedulerTrackingHelper; template class SchedulerTrackingHelper; +template class SchedulerTrackingHelper; } // namespace storm::solver::helper diff --git a/src/storm/solver/helper/SchedulerTrackingHelper.h b/src/storm/solver/helper/SchedulerTrackingHelper.h index 01ad5aad75..b12d2bcaa0 100644 --- a/src/storm/solver/helper/SchedulerTrackingHelper.h +++ b/src/storm/solver/helper/SchedulerTrackingHelper.h @@ -3,22 +3,20 @@ #include #include "storm/solver/OptimizationDirection.h" +#include "storm/solver/helper/ValueIterationOperatorForward.h" namespace storm::solver::helper { -template -class ValueIterationOperator; - /*! * Helper class to extract optimal scheduler choices from a MinMax equation system solution */ -template +template class SchedulerTrackingHelper { public: /*! * Initializes this helper with the given value iteration operator */ - SchedulerTrackingHelper(std::shared_ptr> viOperator); + SchedulerTrackingHelper(std::shared_ptr> viOperator); /*! * Computes the optimal choices from the given solution. @@ -27,25 +25,26 @@ class SchedulerTrackingHelper { * @param offsets Offsets that are added to each choice result. * @param dir Optimization direction to consider. * @param schedulerStorage where the scheduler choices will be stored. Should have the same size as the operand(s). + * @param robust Flag whether any uncertainty should be interpreted robustly. * @param operandOut if given, the result values of the performed value iteration step will be stored in this vector. Can be the same as operandIn. * @return True if the scheduler coincides with the provided scheduler encoded in schedulerStorage * * @note: schedulers are encoded using row indices that are local to their row group, i.e. schedulerStorage[i]==j means that we choose the j'th row of row * group i */ - bool computeScheduler(std::vector& operandIn, std::vector const& offsets, storm::OptimizationDirection const& dir, - std::vector& schedulerStorage, std::vector* operandOut = nullptr) const; + bool computeScheduler(std::vector& operandIn, std::vector const& offsets, storm::OptimizationDirection const& dir, + std::vector& schedulerStorage, bool robust, std::vector* operandOut = nullptr) const; private: /*! * Internal variant of computeScheduler */ - template - bool computeScheduler(std::vector& operandIn, std::vector const& offsets, std::vector& schedulerStorage, - std::vector* operandOut) const; + template + bool computeScheduler(std::vector& operandIn, std::vector const& offsets, std::vector& schedulerStorage, + std::vector* operandOut) const; private: - std::shared_ptr> viOperator; + std::shared_ptr> viOperator; }; } // namespace storm::solver::helper diff --git a/src/storm/solver/helper/SoundValueIterationHelper.h b/src/storm/solver/helper/SoundValueIterationHelper.h index 3317588584..f0bb50907a 100644 --- a/src/storm/solver/helper/SoundValueIterationHelper.h +++ b/src/storm/solver/helper/SoundValueIterationHelper.h @@ -8,12 +8,10 @@ #include "storm/solver/OptimizationDirection.h" #include "storm/solver/SolverStatus.h" #include "storm/solver/TerminationCondition.h" +#include "storm/solver/helper/ValueIterationOperatorForward.h" namespace storm::solver::helper { -template -class ValueIterationOperator; - /*! * Implements sound value iteration * @see https://doi.org/10.1007/978-3-319-96145-3_37 diff --git a/src/storm/solver/helper/ValueIterationHelper.cpp b/src/storm/solver/helper/ValueIterationHelper.cpp index 9a93c72916..4b6f049007 100644 --- a/src/storm/solver/helper/ValueIterationHelper.cpp +++ b/src/storm/solver/helper/ValueIterationHelper.cpp @@ -54,21 +54,22 @@ class VIOperatorBackend { bool isConverged{true}; }; -template -ValueIterationHelper::ValueIterationHelper(std::shared_ptr> viOperator) +template +ValueIterationHelper::ValueIterationHelper( + std::shared_ptr> viOperator) : viOperator(viOperator) { // Intentionally left empty } -template -template -SolverStatus ValueIterationHelper::VI(std::vector& operand, std::vector const& offsets, - uint64_t& numIterations, ValueType const& precision, - std::function const& iterationCallback, - MultiplicationStyle mult) const { - VIOperatorBackend backend{precision}; - std::vector* operand1{&operand}; - std::vector* operand2{&operand}; +template +template +SolverStatus ValueIterationHelper::VI(std::vector& operand, std::vector const& offsets, + uint64_t& numIterations, SolutionType const& precision, + std::function const& iterationCallback, + MultiplicationStyle mult) const { + VIOperatorBackend backend{precision}; + std::vector* operand1{&operand}; + std::vector* operand2{&operand}; if (mult == MultiplicationStyle::Regular) { operand2 = &viOperator->allocateAuxiliaryVector(operand.size()); } @@ -76,7 +77,8 @@ SolverStatus ValueIterationHelper::VI(std::vector SolverStatus status{SolverStatus::InProgress}; while (status == SolverStatus::InProgress) { ++numIterations; - if (viOperator->template apply(*operand1, *operand2, offsets, backend)) { + bool applyResult = viOperator->template applyRobust(*operand1, *operand2, offsets, backend); + if (applyResult) { status = SolverStatus::Converged; } else if (iterationCallback) { status = iterationCallback(status); @@ -96,40 +98,56 @@ SolverStatus ValueIterationHelper::VI(std::vector return status; } -template -SolverStatus ValueIterationHelper::VI(std::vector& operand, std::vector const& offsets, - uint64_t& numIterations, bool relative, ValueType const& precision, - std::optional const& dir, - std::function const& iterationCallback, - MultiplicationStyle mult) const { +template +template +SolverStatus ValueIterationHelper::VI(std::vector& operand, std::vector const& offsets, + uint64_t& numIterations, SolutionType const& precision, + std::function const& iterationCallback, + MultiplicationStyle mult, bool robust) const { + if (robust) { + return VI(operand, offsets, numIterations, precision, iterationCallback, mult); + } else { + return VI(operand, offsets, numIterations, precision, iterationCallback, mult); + } +} + +template +SolverStatus ValueIterationHelper::VI(std::vector& operand, std::vector const& offsets, + uint64_t& numIterations, bool relative, SolutionType const& precision, + std::optional const& dir, + std::function const& iterationCallback, + MultiplicationStyle mult, bool robust) const { STORM_LOG_ASSERT(TrivialRowGrouping || dir.has_value(), "no optimization direction given!"); if (!dir.has_value() || maximize(*dir)) { if (relative) { - return VI(operand, offsets, numIterations, precision, iterationCallback, mult); + return VI(operand, offsets, numIterations, precision, iterationCallback, mult, robust); } else { - return VI(operand, offsets, numIterations, precision, iterationCallback, mult); + return VI(operand, offsets, numIterations, precision, iterationCallback, mult, robust); } } else { if (relative) { - return VI(operand, offsets, numIterations, precision, iterationCallback, mult); + return VI(operand, offsets, numIterations, precision, iterationCallback, mult, robust); } else { - return VI(operand, offsets, numIterations, precision, iterationCallback, mult); + return VI(operand, offsets, numIterations, precision, iterationCallback, mult, robust); } } } -template -SolverStatus ValueIterationHelper::VI(std::vector& operand, std::vector const& offsets, bool relative, - ValueType const& precision, std::optional const& dir, - std::function const& iterationCallback, - MultiplicationStyle mult) const { +template +SolverStatus ValueIterationHelper::VI(std::vector& operand, std::vector const& offsets, + bool relative, SolutionType const& precision, + std::optional const& dir, + std::function const& iterationCallback, + MultiplicationStyle mult, bool robust) const { uint64_t numIterations = 0; - return VI(operand, offsets, numIterations, relative, precision, dir, iterationCallback, mult); + return VI(operand, offsets, numIterations, relative, precision, dir, iterationCallback, mult, robust); } template class ValueIterationHelper; template class ValueIterationHelper; template class ValueIterationHelper; template class ValueIterationHelper; +template class ValueIterationHelper; +template class ValueIterationHelper; } // namespace storm::solver::helper diff --git a/src/storm/solver/helper/ValueIterationHelper.h b/src/storm/solver/helper/ValueIterationHelper.h index 112ae872e7..e29c2f193e 100644 --- a/src/storm/solver/helper/ValueIterationHelper.h +++ b/src/storm/solver/helper/ValueIterationHelper.h @@ -8,32 +8,36 @@ #include "storm/solver/MultiplicationStyle.h" #include "storm/solver/OptimizationDirection.h" #include "storm/solver/SolverStatus.h" +#include "storm/solver/helper/ValueIterationOperatorForward.h" namespace storm::solver::helper { -template -class ValueIterationOperator; - -template +template class ValueIterationHelper { public: - explicit ValueIterationHelper(std::shared_ptr> viOperator); + explicit ValueIterationHelper(std::shared_ptr> viOperator); - template - SolverStatus VI(std::vector& operand, std::vector const& offsets, uint64_t& numIterations, ValueType const& precision, + template + SolverStatus VI(std::vector& operand, std::vector const& offsets, uint64_t& numIterations, SolutionType const& precision, std::function const& iterationCallback = {}, MultiplicationStyle mult = MultiplicationStyle::GaussSeidel) const; - SolverStatus VI(std::vector& operand, std::vector const& offsets, uint64_t& numIterations, bool relative, ValueType const& precision, - std::optional const& dir = {}, std::function const& iterationCallback = {}, - MultiplicationStyle mult = MultiplicationStyle::GaussSeidel) const; + template + SolverStatus VI(std::vector& operand, std::vector const& offsets, uint64_t& numIterations, SolutionType const& precision, + std::function const& iterationCallback = {}, MultiplicationStyle mult = MultiplicationStyle::GaussSeidel, + bool robust = true) const; + + SolverStatus VI(std::vector& operand, std::vector const& offsets, uint64_t& numIterations, bool relative, + SolutionType const& precision, std::optional const& dir = {}, + std::function const& iterationCallback = {}, MultiplicationStyle mult = MultiplicationStyle::GaussSeidel, + bool robust = true) const; - SolverStatus VI(std::vector& operand, std::vector const& offsets, bool relative, ValueType const& precision, + SolverStatus VI(std::vector& operand, std::vector const& offsets, bool relative, SolutionType const& precision, std::optional const& dir = {}, std::function const& iterationCallback = {}, - MultiplicationStyle mult = MultiplicationStyle::GaussSeidel) const; + MultiplicationStyle mult = MultiplicationStyle::GaussSeidel, bool robust = true) const; private: - std::shared_ptr> viOperator; + std::shared_ptr> viOperator; }; } // namespace storm::solver::helper diff --git a/src/storm/solver/helper/ValueIterationOperator.cpp b/src/storm/solver/helper/ValueIterationOperator.cpp index 7bbe1f6a4c..02d73954a8 100644 --- a/src/storm/solver/helper/ValueIterationOperator.cpp +++ b/src/storm/solver/helper/ValueIterationOperator.cpp @@ -7,10 +7,10 @@ namespace storm::solver::helper { -template +template template -void ValueIterationOperator::setMatrix(storm::storage::SparseMatrix const& matrix, - std::vector const* rowGroupIndices) { +void ValueIterationOperator::setMatrix(storm::storage::SparseMatrix const& matrix, + std::vector const* rowGroupIndices) { if constexpr (TrivialRowGrouping) { STORM_LOG_ASSERT(matrix.hasTrivialRowGrouping(), "Expected a matrix with trivial row grouping"); STORM_LOG_ASSERT(rowGroupIndices == nullptr, "Row groups given, but grouping is supposed to be trivial."); @@ -55,20 +55,20 @@ void ValueIterationOperator::setMatrix(storm::sto } } -template -void ValueIterationOperator::setMatrixForwards(storm::storage::SparseMatrix const& matrix, - std::vector const* rowGroupIndices) { +template +void ValueIterationOperator::setMatrixForwards(storm::storage::SparseMatrix const& matrix, + std::vector const* rowGroupIndices) { setMatrix(matrix, rowGroupIndices); } -template -void ValueIterationOperator::setMatrixBackwards(storm::storage::SparseMatrix const& matrix, - std::vector const* rowGroupIndices) { +template +void ValueIterationOperator::setMatrixBackwards(storm::storage::SparseMatrix const& matrix, + std::vector const* rowGroupIndices) { setMatrix(matrix, rowGroupIndices); } -template -void ValueIterationOperator::unsetIgnoredRows() { +template +void ValueIterationOperator::unsetIgnoredRows() { for (auto& c : matrixColumns) { if (c >= StartOfRowIndicator) { c &= StartOfRowGroupIndicator; @@ -77,9 +77,10 @@ void ValueIterationOperator::unsetIgnoredRows() { hasSkippedRows = false; } -template +template template -void ValueIterationOperator::setIgnoredRows(bool useLocalRowIndices, std::function const& ignore) { +void ValueIterationOperator::setIgnoredRows(bool useLocalRowIndices, + std::function const& ignore) { STORM_LOG_ASSERT(!TrivialRowGrouping, "Tried to ignroe rows but the row grouping is trivial."); auto colIt = matrixColumns.begin(); for (auto groupIndex : indexRange(0, this->rowGroupIndices->size() - 1)) { @@ -107,8 +108,9 @@ void ValueIterationOperator::setIgnoredRows(bool hasSkippedRows = true; } -template -void ValueIterationOperator::setIgnoredRows(bool useLocalRowIndices, std::function const& ignore) { +template +void ValueIterationOperator::setIgnoredRows(bool useLocalRowIndices, + std::function const& ignore) { if (backwards) { setIgnoredRows(useLocalRowIndices, ignore); } else { @@ -116,16 +118,16 @@ void ValueIterationOperator::setIgnoredRows(bool } } -template -std::vector::IndexType> const& -ValueIterationOperator::getRowGroupIndices() const { +template +std::vector::IndexType> const& +ValueIterationOperator::getRowGroupIndices() const { STORM_LOG_ASSERT(!TrivialRowGrouping, "Tried to get row group indices for trivial row grouping"); return *rowGroupIndices; } -template -std::vector& ValueIterationOperator::allocateAuxiliaryVector(uint64_t size, - std::optional const& initialValue) { +template +std::vector& ValueIterationOperator::allocateAuxiliaryVector( + uint64_t size, std::optional const& initialValue) { STORM_LOG_ASSERT(!auxiliaryVectorUsedExternally, "Auxiliary vector already in use."); if (initialValue) { auxiliaryVector.assign(size, *initialValue); @@ -136,21 +138,21 @@ std::vector& ValueIterationOperator::a return auxiliaryVector; } -template -void ValueIterationOperator::freeAuxiliaryVector() { +template +void ValueIterationOperator::freeAuxiliaryVector() { auxiliaryVectorUsedExternally = false; } -template -void ValueIterationOperator::moveToEndOfRow(std::vector::iterator& matrixColumnIt) const { +template +void ValueIterationOperator::moveToEndOfRow(std::vector::iterator& matrixColumnIt) const { do { ++matrixColumnIt; } while (*matrixColumnIt < StartOfRowIndicator); } -template -bool ValueIterationOperator::skipIgnoredRow(std::vector::const_iterator& matrixColumnIt, - typename std::vector::const_iterator& matrixValueIt) const { +template +bool ValueIterationOperator::skipIgnoredRow(std::vector::const_iterator& matrixColumnIt, + typename std::vector::const_iterator& matrixValueIt) const { if (IndexType entriesToSkip = (*matrixColumnIt & SkipNumEntriesMask)) { matrixColumnIt += entriesToSkip; matrixValueIt += entriesToSkip - 1; @@ -159,9 +161,9 @@ bool ValueIterationOperator::skipIgnoredRow(std:: return false; } -template -uint64_t ValueIterationOperator::skipMultipleIgnoredRows(std::vector::const_iterator& matrixColumnIt, - typename std::vector::const_iterator& matrixValueIt) const { +template +uint64_t ValueIterationOperator::skipMultipleIgnoredRows( + std::vector::const_iterator& matrixColumnIt, typename std::vector::const_iterator& matrixValueIt) const { IndexType result{0ull}; while (skipIgnoredRow(matrixColumnIt, matrixValueIt)) { ++result; @@ -176,5 +178,7 @@ template class ValueIterationOperator; template class ValueIterationOperator; template class ValueIterationOperator; template class ValueIterationOperator; +template class ValueIterationOperator; +template class ValueIterationOperator; } // namespace storm::solver::helper diff --git a/src/storm/solver/helper/ValueIterationOperator.h b/src/storm/solver/helper/ValueIterationOperator.h index 52ce2d7d7b..6226439b4a 100644 --- a/src/storm/solver/helper/ValueIterationOperator.h +++ b/src/storm/solver/helper/ValueIterationOperator.h @@ -7,6 +7,7 @@ #include #include +#include "storm/solver/helper/ValueIterationOperatorForward.h" #include "storm/storage/sparse/StateType.h" #include "storm/utility/macros.h" #include "storm/utility/vector.h" // TODO @@ -27,8 +28,9 @@ namespace solver::helper { * The application of the operator is heavily templated so that many different flavours of value iteration and related algorithms can be implemented using this. * @tparam ValueType The type of the matrix entries * @tparam TrivialRowGrouping True iff the underlying model is deterministic + * @tparam SolutionType The type of the operand entries. Default is ValueType, see ValueIterationOperatorForward.h */ -template +template class ValueIterationOperator { public: using IndexType = storm::storage::sparse::state_type; @@ -90,17 +92,23 @@ class ValueIterationOperator { */ template bool apply(OperandType const& operandIn, OperandType& operandOut, OffsetType const& offsets, BackendType& backend) const { + // We assume in the normal apply case that we can just maximize. + return applyRobust(operandIn, operandOut, offsets, backend); + } + + template + bool applyRobust(OperandType const& operandIn, OperandType& operandOut, OffsetType const& offsets, BackendType& backend) const { if (hasSkippedRows) { if (backwards) { - return apply(operandOut, operandIn, offsets, backend); + return apply(operandOut, operandIn, offsets, backend); } else { - return apply(operandOut, operandIn, offsets, backend); + return apply(operandOut, operandIn, offsets, backend); } } else { if (backwards) { - return apply(operandOut, operandIn, offsets, backend); + return apply(operandOut, operandIn, offsets, backend); } else { - return apply(operandOut, operandIn, offsets, backend); + return apply(operandOut, operandIn, offsets, backend); } } } @@ -113,6 +121,11 @@ class ValueIterationOperator { return apply(operand, operand, offsets, backend); } + template + bool applyInPlaceRobust(OperandType& operand, OffsetType const& offsets, BackendType& backend) const { + return applyRobust(operand, operand, offsets, backend); + } + /*! * Sets rows that will be skipped when applying the operator. * @note each row group shall have at least one row that is not ignored @@ -138,7 +151,7 @@ class ValueIterationOperator { * @param initialValue optional initial value * @return a reference to the auxiliary vector */ - std::vector& allocateAuxiliaryVector(uint64_t size, std::optional const& initialValue = {}); + std::vector& allocateAuxiliaryVector(uint64_t size, std::optional const& initialValue = {}); /*! * Clears the auxiliary vector, invalidating any references to it @@ -150,7 +163,7 @@ class ValueIterationOperator { * Internal variant of `apply` * @note This and other apply methods are intentionally implemented in the header file as there are potentially many different BackendTypes */ - template + template bool apply(OperandType& operandOut, OperandType const& operandIn, OffsetType const& offsets, BackendType& backend) const { STORM_LOG_ASSERT(getSize(operandIn) == getSize(operandOut), "Input and Output Operands have different sizes."); auto const operandSize = getSize(operandIn); @@ -163,17 +176,17 @@ class ValueIterationOperator { STORM_LOG_ASSERT(*matrixColumnIt >= StartOfRowIndicator, "VI Operator in invalid state."); // STORM_LOG_ASSERT(matrixValueIt != matrixValues.end(), "VI Operator in invalid state."); if constexpr (TrivialRowGrouping) { - backend.firstRow(applyRow(matrixColumnIt, matrixValueIt, operandIn, offsets, groupIndex), groupIndex, groupIndex); + backend.firstRow(applyRow(matrixColumnIt, matrixValueIt, operandIn, offsets, groupIndex), groupIndex, groupIndex); } else { IndexType rowIndex = (*rowGroupIndices)[groupIndex]; if constexpr (SkipIgnoredRows) { rowIndex += skipMultipleIgnoredRows(matrixColumnIt, matrixValueIt); } - backend.firstRow(applyRow(matrixColumnIt, matrixValueIt, operandIn, offsets, rowIndex), groupIndex, rowIndex); + backend.firstRow(applyRow(matrixColumnIt, matrixValueIt, operandIn, offsets, rowIndex), groupIndex, rowIndex); while (*matrixColumnIt < StartOfRowGroupIndicator) { ++rowIndex; if (!SkipIgnoredRows || !skipIgnoredRow(matrixColumnIt, matrixValueIt)) { - backend.nextRow(applyRow(matrixColumnIt, matrixValueIt, operandIn, offsets, rowIndex), groupIndex, rowIndex); + backend.nextRow(applyRow(matrixColumnIt, matrixValueIt, operandIn, offsets, rowIndex), groupIndex, rowIndex); } } } @@ -211,12 +224,43 @@ class ValueIterationOperator { return {(*offsets.first)[offsetIndex], offsets.second}; } + template + OpT robustInitializeRowRes(std::vector const&, std::vector const& offsets, uint64_t offsetIndex) const { + return offsets[offsetIndex].upper(); + } + + template + std::pair robustInitializeRowRes(std::pair, std::vector> const&, std::vector const& offsets, + uint64_t offsetIndex) const { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Value Iteration is not implemented with pairs and interval-models."); + + return {offsets[offsetIndex].upper(), offsets[offsetIndex].upper()}; + } + + template + std::pair robustInitializeRowRes(std::pair, std::vector> const&, + std::pair const*, OffT2> const& offsets, uint64_t offsetIndex) const { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Value Iteration is not implemented with pairs and interval-models."); + + return {(*offsets.first)[offsetIndex], offsets.second}; + } + /*! * Computes the result for a single row and advances the given iterators to the end of the row */ - template + template auto applyRow(std::vector::const_iterator& matrixColumnIt, typename std::vector::const_iterator& matrixValueIt, OperandType const& operand, OffsetType const& offsets, uint64_t offsetIndex) const { + if constexpr (std::is_same_v) { + return applyRowRobust(matrixColumnIt, matrixValueIt, operand, offsets, offsetIndex); + } else { + return applyRowStandard(matrixColumnIt, matrixValueIt, operand, offsets, offsetIndex); + } + } + + template + auto applyRowStandard(std::vector::const_iterator& matrixColumnIt, typename std::vector::const_iterator& matrixValueIt, + OperandType const& operand, OffsetType const& offsets, uint64_t offsetIndex) const { STORM_LOG_ASSERT(*matrixColumnIt >= StartOfRowIndicator, "VI Operator in invalid state."); auto result{initializeRowRes(operand, offsets, offsetIndex)}; for (++matrixColumnIt; *matrixColumnIt < StartOfRowIndicator; ++matrixColumnIt, ++matrixValueIt) { @@ -230,6 +274,55 @@ class ValueIterationOperator { return result; } + // Aux function for applyRowRobust + template + struct AuxCompare { + bool operator()(const std::pair& a, const std::pair& b) const { + if constexpr (RobustDirection == OptimizationDirection::Maximize) { + return a.first > b.first; + } else { + return a.first < b.first; + } + } + }; + + template + auto applyRowRobust(std::vector::const_iterator& matrixColumnIt, typename std::vector::const_iterator& matrixValueIt, + OperandType const& operand, OffsetType const& offsets, uint64_t offsetIndex) const { + STORM_LOG_ASSERT(*matrixColumnIt >= StartOfRowIndicator, "VI Operator in invalid state."); + auto result{robustInitializeRowRes(operand, offsets, offsetIndex)}; + std::vector> tmp; // TODO this reallocation is too costly. + SolutionType remainingValue{storm::utility::one()}; + for (++matrixColumnIt; *matrixColumnIt < StartOfRowIndicator; ++matrixColumnIt, ++matrixValueIt) { + if constexpr (isPair::value) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Value Iteration is not implemented with pairs and interval-models."); + // Notice the unclear semantics here in terms of how to order things. + } else { + result += operand[*matrixColumnIt] * (matrixValueIt->lower()); + } + remainingValue -= matrixValueIt->lower(); + if (!storm::utility::isZero(matrixValueIt->diameter())) { + tmp.emplace_back(operand[*matrixColumnIt], matrixValueIt->diameter()); + } + } + if (storm::utility::isZero(remainingValue) || storm::utility::isOne(remainingValue)) { + return result; + } + AuxCompare compare; + std::sort(tmp.begin(), tmp.end(), compare); + + for (auto const& valWidthPair : tmp) { + auto availableMass = std::min(valWidthPair.second, remainingValue); + result += availableMass * valWidthPair.first; + remainingValue -= availableMass; + if (storm::utility::isZero(remainingValue)) { + return result; + } + } + STORM_LOG_ASSERT(storm::utility::isZero(remainingValue), "Should be zero (all prob mass taken)"); + return result; + } + // Auxiliary helpers used for metaprogramming template auto indexRange(IndexType start, IndexType end) const { @@ -307,7 +400,7 @@ class ValueIterationOperator { /*! * Storage for the auxiliary vector */ - std::vector auxiliaryVector; + std::vector auxiliaryVector; /*! * True, if an auxiliary vector exists diff --git a/src/storm/solver/helper/ValueIterationOperatorForward.h b/src/storm/solver/helper/ValueIterationOperatorForward.h new file mode 100644 index 0000000000..65ba63232c --- /dev/null +++ b/src/storm/solver/helper/ValueIterationOperatorForward.h @@ -0,0 +1,6 @@ +#pragma once + +namespace storm::solver::helper { +template +class ValueIterationOperator; +} diff --git a/src/storm/solver/multiplier/Multiplier.cpp b/src/storm/solver/multiplier/Multiplier.cpp index ca97b6ca63..531e4846c8 100644 --- a/src/storm/solver/multiplier/Multiplier.cpp +++ b/src/storm/solver/multiplier/Multiplier.cpp @@ -10,6 +10,8 @@ #include "NativeMultiplier.h" #include "storm/environment/solver/MultiplierEnvironment.h" #include "storm/exceptions/IllegalArgumentException.h" +#include "storm/exceptions/NotImplementedException.h" + #include "storm/solver/SolverSelectionOptions.h" #include "storm/solver/multiplier/GmmxxMultiplier.h" #include "storm/utility/ProgressMeasurement.h" @@ -99,6 +101,9 @@ std::unique_ptr> MultiplierFactory::create(Envi switch (type) { case MultiplierType::Gmmxx: + if constexpr (std::is_same_v) { + throw storm::exceptions::NotImplementedException() << "Gmm not supported with intervals."; + } return std::make_unique>(matrix); case MultiplierType::Native: return std::make_unique>(matrix); @@ -108,13 +113,12 @@ std::unique_ptr> MultiplierFactory::create(Envi template class Multiplier; template class MultiplierFactory; - -#ifdef STORM_HAVE_CARL template class Multiplier; template class MultiplierFactory; template class Multiplier; template class MultiplierFactory; -#endif +template class Multiplier; +template class MultiplierFactory; } // namespace solver } // namespace storm diff --git a/src/storm/solver/multiplier/NativeMultiplier.cpp b/src/storm/solver/multiplier/NativeMultiplier.cpp index 2e144b8b35..c4947261ca 100644 --- a/src/storm/solver/multiplier/NativeMultiplier.cpp +++ b/src/storm/solver/multiplier/NativeMultiplier.cpp @@ -142,10 +142,9 @@ void NativeMultiplier::multAddReduceParallel(storm::solver::Optimizat } template class NativeMultiplier; -#ifdef STORM_HAVE_CARL template class NativeMultiplier; template class NativeMultiplier; -#endif +template class NativeMultiplier; } // namespace solver } // namespace storm diff --git a/src/storm/storage/BitVector.cpp b/src/storm/storage/BitVector.cpp index e2f194cff6..54a228759b 100644 --- a/src/storm/storage/BitVector.cpp +++ b/src/storm/storage/BitVector.cpp @@ -531,6 +531,14 @@ void BitVector::set(uint_fast64_t bitIndex, BitVector const& other) { } } +void BitVector::setMultiple(uint64_t bitIndex, uint64_t nrOfBits, bool newValue) { + // TODO we may want to optimize this code for large nrs of bits. + uint64_t endPos = std::min(bitIndex + nrOfBits, bitCount); + for (uint64_t tmpIndex = bitIndex; tmpIndex < endPos; ++tmpIndex) { + set(tmpIndex, newValue); + } +} + storm::storage::BitVector BitVector::get(uint_fast64_t bitIndex, uint_fast64_t numberOfBits) const { uint64_t numberOfBuckets = numberOfBits >> 6; uint64_t index = bitIndex >> 6; diff --git a/src/storm/storage/BitVector.h b/src/storm/storage/BitVector.h index 437f0f2f24..b10c4b4456 100644 --- a/src/storm/storage/BitVector.h +++ b/src/storm/storage/BitVector.h @@ -472,6 +472,11 @@ class BitVector { */ void set(uint_fast64_t bitIndex, BitVector const& other); + /*! + * Sets multiple bits to the given value. + */ + void setMultiple(uint64_t bitIndex, uint64_t nrOfBits, bool newValue = true); + /*! * Apply a permutation of entries. That is, in row i, write the entry of row inversePermutation[i]. * @param inversePermutation. diff --git a/src/storm/storage/Distribution.cpp b/src/storm/storage/Distribution.cpp index 58f96fcbdb..d7796fbeb8 100644 --- a/src/storm/storage/Distribution.cpp +++ b/src/storm/storage/Distribution.cpp @@ -208,19 +208,25 @@ StateType Distribution::sampleFromDistribution(const Value template class Distribution; template std::ostream& operator<<(std::ostream& out, Distribution const& distribution); -template class Distribution; +template class Distribution; template std::ostream& operator<<(std::ostream& out, Distribution const& distribution); #ifdef STORM_HAVE_CARL template class Distribution; template std::ostream& operator<<(std::ostream& out, Distribution const& distribution); -template class Distribution; +template class Distribution; template std::ostream& operator<<(std::ostream& out, Distribution const& distribution); template class Distribution; template std::ostream& operator<<(std::ostream& out, Distribution const& distribution); -template class Distribution; -template std::ostream& operator<<(std::ostream& out, Distribution const& distribution); +template class Distribution; +template std::ostream& operator<<(std::ostream& out, Distribution const& distribution); + +template class Distribution; +template std::ostream& operator<<(std::ostream& out, Distribution const& distribution); +template class Distribution; +template std::ostream& operator<<(std::ostream& out, Distribution const& distribution); + #endif } // namespace storage } // namespace storm diff --git a/src/storm/storage/MaximalEndComponentDecomposition.cpp b/src/storm/storage/MaximalEndComponentDecomposition.cpp index 888a4159eb..982600d741 100644 --- a/src/storm/storage/MaximalEndComponentDecomposition.cpp +++ b/src/storm/storage/MaximalEndComponentDecomposition.cpp @@ -170,14 +170,17 @@ void MaximalEndComponentDecomposition::performMaximalEndComponentDeco template class MaximalEndComponentDecomposition; template MaximalEndComponentDecomposition::MaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel const& model); -#ifdef STORM_HAVE_CARL template class MaximalEndComponentDecomposition; template MaximalEndComponentDecomposition::MaximalEndComponentDecomposition( storm::models::sparse::NondeterministicModel const& model); +template class MaximalEndComponentDecomposition; +template MaximalEndComponentDecomposition::MaximalEndComponentDecomposition( + storm::models::sparse::NondeterministicModel const& model); + template class MaximalEndComponentDecomposition; template MaximalEndComponentDecomposition::MaximalEndComponentDecomposition( storm::models::sparse::NondeterministicModel const& model); -#endif + } // namespace storage } // namespace storm diff --git a/src/storm/storage/Scheduler.cpp b/src/storm/storage/Scheduler.cpp index 2f2e123ec7..84652762df 100644 --- a/src/storm/storage/Scheduler.cpp +++ b/src/storm/storage/Scheduler.cpp @@ -384,6 +384,7 @@ void Scheduler::printJsonToStream(std::ostream& out, std::shared_ptr< template class Scheduler; template class Scheduler; template class Scheduler; +template class Scheduler; } // namespace storage } // namespace storm diff --git a/src/storm/storage/SchedulerChoice.cpp b/src/storm/storage/SchedulerChoice.cpp index c7cd791815..cf810cd8d6 100644 --- a/src/storm/storage/SchedulerChoice.cpp +++ b/src/storm/storage/SchedulerChoice.cpp @@ -73,6 +73,8 @@ template class SchedulerChoice; template std::ostream& operator<<(std::ostream& out, SchedulerChoice const& schedulerChoice); template class SchedulerChoice; template std::ostream& operator<<(std::ostream& out, SchedulerChoice const& schedulerChoice); +template class SchedulerChoice; +template std::ostream& operator<<(std::ostream& out, SchedulerChoice const& schedulerChoice); } // namespace storage } // namespace storm diff --git a/src/storm/storage/SparseMatrix.cpp b/src/storm/storage/SparseMatrix.cpp index a4f60f042d..1dabffd458 100644 --- a/src/storm/storage/SparseMatrix.cpp +++ b/src/storm/storage/SparseMatrix.cpp @@ -317,7 +317,8 @@ SparseMatrix SparseMatrixBuilder::build(index_type overrid if (rowCount > 0) { rowIndications.push_back(currentEntryCount); } - STORM_LOG_ASSERT(rowCount == rowIndications.size() - 1, "Wrong sizes of vectors: " << rowCount << " != " << (rowIndications.size() - 1) << "."); + STORM_LOG_ASSERT(rowCount == rowIndications.size() - 1, + "Wrong sizes of row indications vector: (Rowcount) " << rowCount << " != " << (rowIndications.size() - 1) << " (Vector)."); uint_fast64_t columnCount = hasEntries ? highestColumn + 1 : 0; if (initialColumnCountSet && forceInitialDimensions) { STORM_LOG_THROW(columnCount <= initialColumnCount, storm::exceptions::InvalidStateException, @@ -820,9 +821,7 @@ template storm::storage::BitVector SparseMatrix::getRowFilter(storm::storage::BitVector const& groupConstraint) const { storm::storage::BitVector res(this->getRowCount(), false); for (auto group : groupConstraint) { - for (auto row : this->getRowGroupIndices(group)) { - res.set(row, true); - } + res.setMultiple(getRowGroupIndices()[group], getRowGroupSize(group)); } return res; } @@ -2435,6 +2434,17 @@ bool SparseMatrix::isProbabilistic() const { return true; } +template +bool SparseMatrix::hasOnlyPositiveEntries() const { + storm::utility::ConstantsComparator comparator; + for (auto const& entry : *this) { + if (!comparator.isLess(storm::utility::zero(), entry.getValue())) { + return false; + } + } + return true; +} + template template bool SparseMatrix::isSubmatrixOf(SparseMatrix const& matrix) const { diff --git a/src/storm/storage/SparseMatrix.h b/src/storm/storage/SparseMatrix.h index 25e632c3ac..27ce218799 100644 --- a/src/storm/storage/SparseMatrix.h +++ b/src/storm/storage/SparseMatrix.h @@ -627,7 +627,8 @@ class SparseMatrix { void makeRowGroupingTrivial(); /*! - * Returns the indices of the rows that belong to one of the selected row groups. + * Returns a bitvector representing the set of rows, + * with all indices set that correspond to one of the selected row groups. * * @param groups the selected row groups * @return a bit vector that is true at position i iff the row group of row i is selected. @@ -684,14 +685,14 @@ class SparseMatrix { */ void makeRowDirac(index_type row, index_type column, bool dropZeroEntries = false); - /* + /*! * Sums the entries in all rows. * * @return The vector of sums of the entries in the respective rows. */ std::vector getRowSumVector() const; - /* + /*! * Sums the entries in the given row and columns. * * @param row The row whose entries to add. @@ -1025,6 +1026,12 @@ class SparseMatrix { * Checks for each row whether it sums to one. */ bool isProbabilistic() const; + + /*! + * Checks whether each present entry is strictly positive (omitted entries are not considered). + */ + bool hasOnlyPositiveEntries() const; + /*! * Checks if the current matrix is a submatrix of the given matrix, where a matrix A is called a submatrix * of B if B has no entries in position where A has none. Additionally, the matrices must be of equal size. diff --git a/src/storm/storage/StronglyConnectedComponentDecomposition.cpp b/src/storm/storage/StronglyConnectedComponentDecomposition.cpp index 366499634d..e6013c4d5a 100644 --- a/src/storm/storage/StronglyConnectedComponentDecomposition.cpp +++ b/src/storm/storage/StronglyConnectedComponentDecomposition.cpp @@ -342,4 +342,6 @@ std::vector StronglyConnectedComponentDecomposition::comput template class StronglyConnectedComponentDecomposition; template class StronglyConnectedComponentDecomposition; template class StronglyConnectedComponentDecomposition; +template class StronglyConnectedComponentDecomposition; + } // namespace storm::storage diff --git a/src/storm/storage/memorystructure/MemoryStructureBuilder.cpp b/src/storm/storage/memorystructure/MemoryStructureBuilder.cpp index e29981f310..d1a20376f3 100644 --- a/src/storm/storage/memorystructure/MemoryStructureBuilder.cpp +++ b/src/storm/storage/memorystructure/MemoryStructureBuilder.cpp @@ -135,6 +135,7 @@ template class MemoryStructureBuilder; template class MemoryStructureBuilder>; template class MemoryStructureBuilder; template class MemoryStructureBuilder; +template class MemoryStructureBuilder; } // namespace storage } // namespace storm diff --git a/src/storm/storage/memorystructure/SparseModelMemoryProduct.cpp b/src/storm/storage/memorystructure/SparseModelMemoryProduct.cpp index 2d3ce8c6df..24cedff50f 100644 --- a/src/storm/storage/memorystructure/SparseModelMemoryProduct.cpp +++ b/src/storm/storage/memorystructure/SparseModelMemoryProduct.cpp @@ -558,6 +558,7 @@ template class SparseModelMemoryProduct; template class SparseModelMemoryProduct>; template class SparseModelMemoryProduct; template class SparseModelMemoryProduct; +template class SparseModelMemoryProduct; } // namespace storage } // namespace storm diff --git a/src/storm/transformer/AddUncertainty.cpp b/src/storm/transformer/AddUncertainty.cpp new file mode 100644 index 0000000000..7db11d701d --- /dev/null +++ b/src/storm/transformer/AddUncertainty.cpp @@ -0,0 +1,81 @@ +#include "storm/transformer/AddUncertainty.h" +#include "storm/adapters/RationalNumberAdapter.h" +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/NotImplementedException.h" +#include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/Mdp.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/storage/SparseMatrix.h" +#include "storm/utility/macros.h" +#include "storm/utility/vector.h" + +namespace storm::transformer { + +template +AddUncertainty::AddUncertainty(std::shared_ptr> const& originalModel) : origModel(originalModel) {} + +template +std::shared_ptr> AddUncertainty::transform(double additiveUncertainty, double minimalTransitionProbability) { + // we first build the matrix and later copy the row grouping. + auto newMatrixBuilder = + storage::SparseMatrixBuilder(origModel->getTransitionMatrix().getRowCount(), origModel->getTransitionMatrix().getColumnCount(), + origModel->getTransitionMatrix().getNonzeroEntryCount(), true, false); + // Build transition matrix (without row grouping) + for (uint64_t rowIndex = 0; rowIndex < origModel->getTransitionMatrix().getRowCount(); ++rowIndex) { + for (auto const& entry : origModel->getTransitionMatrix().getRow(rowIndex)) { + newMatrixBuilder.addNextValue(rowIndex, entry.getColumn(), addUncertainty(entry.getValue(), additiveUncertainty, minimalTransitionProbability)); + } + } + storm::storage::sparse::ModelComponents modelComponents(newMatrixBuilder.build(), origModel->getStateLabeling()); + if (!origModel->getTransitionMatrix().hasTrivialRowGrouping()) { + modelComponents.transitionMatrix.setRowGroupIndices(origModel->getTransitionMatrix().getRowGroupIndices()); + } + // Change value type of standard reward model. + std::unordered_map> newRewardModels; + for (auto const& rewModel : origModel->getRewardModels()) { + auto const& oldRewModel = rewModel.second; + std::optional> stateRewards; + std::optional> stateActionRewards; + if (oldRewModel.hasStateRewards()) { + stateRewards = utility::vector::convertNumericVector(oldRewModel.getStateRewardVector()); + } + if (oldRewModel.hasStateActionRewards()) { + stateActionRewards = utility::vector::convertNumericVector(oldRewModel.getStateActionRewardVector()); + } + STORM_LOG_THROW(!oldRewModel.hasTransitionRewards(), exceptions::NotImplementedException, "Transition rewards are not supported."); + models::sparse::StandardRewardModel newRewModel(std::move(stateRewards), std::move(stateActionRewards)); + newRewardModels.emplace(rewModel.first, std::move(newRewModel)); + } + + // remaining model components. + modelComponents.rewardModels = std::move(newRewardModels); + modelComponents.stateValuations = origModel->getOptionalStateValuations(); + modelComponents.choiceLabeling = origModel->getOptionalChoiceLabeling(); + modelComponents.choiceOrigins = origModel->getOptionalChoiceOrigins(); + + switch (origModel->getType()) { + case storm::models::ModelType::Dtmc: + return std::make_shared>(std::move(modelComponents)); + case storm::models::ModelType::Mdp: + return std::make_shared>(std::move(modelComponents)); + default: + STORM_LOG_THROW(false, exceptions::NotImplementedException, "Only DTMC and MDP model types are currently supported."); + } +} + +template +storm::Interval AddUncertainty::addUncertainty(ValueType const& vt, double additiveUncertainty, double minimalValue) { + if (utility::isOne(vt)) { + return storm::Interval(1.0, 1.0); + } + double center = storm::utility::convertNumber(vt); + STORM_LOG_THROW(center >= minimalValue, storm::exceptions::InvalidArgumentException, "Transition probability is smaller than minimal value"); + double lowerBound = std::max(center - additiveUncertainty, minimalValue); + double upperBound = std::min(center + additiveUncertainty, 1.0 - minimalValue); + STORM_LOG_ASSERT(lowerBound > 0, "Lower bound must be strictly above zero."); + STORM_LOG_ASSERT(upperBound < 1, "Upper bound must be strictly below one."); + return storm::Interval(lowerBound, upperBound); +} + +template class AddUncertainty; +} // namespace storm::transformer \ No newline at end of file diff --git a/src/storm/transformer/AddUncertainty.h b/src/storm/transformer/AddUncertainty.h new file mode 100644 index 0000000000..9655559eec --- /dev/null +++ b/src/storm/transformer/AddUncertainty.h @@ -0,0 +1,23 @@ +#include "storm/models/sparse/Model.h" + +namespace storm::transformer { + +/** + * This class is a convenience transformer to add uncertainty. + * We currently support only one type of self-defined uncertainty, although additional types of uncertainty are imaginable. + * The transformer does maintain reward models, state labels, state valuations, choice labels and choice origins. + * + * @tparam ValueType + */ +template +class AddUncertainty { + public: + AddUncertainty(std::shared_ptr> const& originalModel); + std::shared_ptr> transform(double additiveUncertainty, double minimalValue = 0.0001); + + private: + storm::Interval addUncertainty(ValueType const& vt, double additiveUncertainty, double minimalValue); + std::shared_ptr> origModel; +}; + +} // namespace storm::transformer \ No newline at end of file diff --git a/src/storm/transformer/SubsystemBuilder.cpp b/src/storm/transformer/SubsystemBuilder.cpp index 4333a8c6a0..67e00add30 100644 --- a/src/storm/transformer/SubsystemBuilder.cpp +++ b/src/storm/transformer/SubsystemBuilder.cpp @@ -238,5 +238,10 @@ template SubsystemBuilderReturnType buildSubsystem(stor storm::storage::BitVector const& subsystemActions, bool keepUnreachableStates = true, SubsystemBuilderOptions options = SubsystemBuilderOptions()); +template SubsystemBuilderReturnType buildSubsystem(storm::models::sparse::Model const& originalModel, + storm::storage::BitVector const& subsystemStates, + storm::storage::BitVector const& subsystemActions, bool keepUnreachableStates = true, + SubsystemBuilderOptions options = SubsystemBuilderOptions()); + } // namespace transformer } // namespace storm diff --git a/src/storm/utility/VectorHelper.cpp b/src/storm/utility/VectorHelper.cpp index 208e395603..08b6aa0276 100644 --- a/src/storm/utility/VectorHelper.cpp +++ b/src/storm/utility/VectorHelper.cpp @@ -50,10 +50,8 @@ void VectorHelper::reduceVector(storm::solver::Optimiza } template class VectorHelper; - -#ifdef STORM_HAVE_CARL template class VectorHelper; template class VectorHelper; -#endif +template class VectorHelper; } // namespace utility } // namespace storm diff --git a/src/storm/utility/builder.cpp b/src/storm/utility/builder.cpp index 5e589ac955..8a354bcf55 100644 --- a/src/storm/utility/builder.cpp +++ b/src/storm/utility/builder.cpp @@ -46,6 +46,9 @@ template std::shared_ptr> bu storm::models::ModelType modelType, storm::storage::sparse::ModelComponents&& components); template std::shared_ptr> buildModelFromComponents( storm::models::ModelType modelType, storm::storage::sparse::ModelComponents&& components); +template std::shared_ptr> buildModelFromComponents( + storm::models::ModelType modelType, storm::storage::sparse::ModelComponents&& components); + } // namespace builder } // namespace utility } // namespace storm diff --git a/src/storm/utility/constants.cpp b/src/storm/utility/constants.cpp index beeb72b22e..60fd2ae326 100644 --- a/src/storm/utility/constants.cpp +++ b/src/storm/utility/constants.cpp @@ -719,6 +719,11 @@ bool isConstant(storm::Polynomial const& a) { return a.isConstant(); } +template<> +bool isConstant(storm::Interval const& a) { + return a.isPointInterval(); +} + template<> bool isInfinity(storm::RationalFunction const& a) { // FIXME: this should be treated more properly. @@ -893,6 +898,33 @@ double convertNumber(std::string const& value) { return convertNumber(convertNumber(value)); } +template<> +storm::Interval convertNumber(double const& number) { + return storm::Interval(number); +} + +template<> +storm::Interval convertNumber(storm::RationalNumber const& n) { + return storm::Interval(convertNumber(n)); +} + +template<> +storm::RationalNumber convertNumber(storm::Interval const& number) { + STORM_LOG_ASSERT(number.isPointInterval(), "Interval must be a point interval to convert"); + return convertNumber(number.lower()); +} + +template<> +double convertNumber(storm::Interval const& number) { + STORM_LOG_ASSERT(number.isPointInterval(), "Interval must be a point interval to convert"); + return number.lower(); +} + +template<> +storm::Interval abs(storm::Interval const& interval) { + return interval.abs(); +} + // Explicit instantiations. // double @@ -1015,6 +1047,8 @@ template std::string to_string(storm::GmpRationalNumber const& value); template RationalFunction one(); template RationalFunction zero(); +template bool isNan(RationalFunction const&); + // Instantiations for polynomials. template Polynomial one(); template Polynomial zero(); @@ -1024,8 +1058,10 @@ template Interval one(); template Interval zero(); template bool isOne(Interval const& value); template bool isZero(Interval const& value); -template bool isConstant(Interval const& value); template bool isInfinity(Interval const& value); +template bool isAlmostZero(Interval const& value); + +template std::string to_string(storm::Interval const& value); #endif } // namespace utility diff --git a/src/storm/utility/graph.cpp b/src/storm/utility/graph.cpp index 433ea3951d..b91322afb5 100644 --- a/src/storm/utility/graph.cpp +++ b/src/storm/utility/graph.cpp @@ -32,6 +32,18 @@ namespace storm { namespace utility { namespace graph { +template +storm::storage::BitVector getReachableOneStep(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates) { + storm::storage::BitVector result{initialStates.size()}; + for (uint64_t currentState : initialStates) { + for (auto const& successor : transitionMatrix.getRowGroup(currentState)) { + STORM_LOG_ASSERT(!storm::utility::isZero(successor.getValue()), "Matrix should not have zero entries."); + result.set(successor.getColumn()); + } + } + return result; +} + template storm::storage::BitVector getReachableStates(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, @@ -474,9 +486,9 @@ std::pair, storm::dd::Bdd> performProb01(storm::model return result; } -template +template void computeSchedulerStayingInStates(storm::storage::BitVector const& states, storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::Scheduler& scheduler, boost::optional const& rowFilter) { + storm::storage::Scheduler& scheduler, boost::optional const& rowFilter) { std::vector const& nondeterministicChoiceIndices = transitionMatrix.getRowGroupIndices(); for (auto state : states) { @@ -499,9 +511,9 @@ void computeSchedulerStayingInStates(storm::storage::BitVector const& states, st } } -template +template void computeSchedulerWithOneSuccessorInStates(storm::storage::BitVector const& states, storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::Scheduler& scheduler) { + storm::storage::Scheduler& scheduler) { std::vector const& nondeterministicChoiceIndices = transitionMatrix.getRowGroupIndices(); for (auto state : states) { @@ -526,10 +538,10 @@ void computeSchedulerWithOneSuccessorInStates(storm::storage::BitVector const& s } } -template +template void computeSchedulerProbGreater0E(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, - storm::storage::Scheduler& scheduler, boost::optional const& rowFilter) { + storm::storage::Scheduler& scheduler, boost::optional const& rowFilter) { // Perform backwards DFS from psiStates and find a valid choice for each visited state. std::vector stack; @@ -577,15 +589,15 @@ void computeSchedulerProbGreater0E(storm::storage::SparseMatrix const& transi } } -template +template void computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::Scheduler& scheduler) { + storm::storage::Scheduler& scheduler) { computeSchedulerStayingInStates(prob0EStates, transitionMatrix, scheduler); } -template +template void computeSchedulerRewInf(storm::storage::BitVector const& rewInfStates, storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::SparseMatrix const& backwardTransitions, storm::storage::Scheduler& scheduler) { + storm::storage::SparseMatrix const& backwardTransitions, storm::storage::Scheduler& scheduler) { // Get the states from which we can never exit the rewInfStates, i.e. the states satisfying Pmax=1 [ G "rewInfStates"] // Also set a corresponding choice for all those states storm::storage::BitVector trapStates(rewInfStates.size(), false); @@ -608,10 +620,10 @@ void computeSchedulerRewInf(storm::storage::BitVector const& rewInfStates, storm computeSchedulerProbGreater0E(transitionMatrix, backwardTransitions, rewInfStates, trapStates, scheduler); } -template +template void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, - storm::storage::BitVector const& psiStates, storm::storage::Scheduler& scheduler, + storm::storage::BitVector const& psiStates, storm::storage::Scheduler& scheduler, boost::optional const& rowFilter) { // set an arbitrary (valid) choice for the psi states. for (auto psiState : psiStates) { @@ -2146,6 +2158,135 @@ template ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix getTopologicalSort(storm::storage::SparseMatrix const& matrix, std::vector const& firstStates); // End of instantiations for storm::RationalNumber. +// Instantiations for storm::interval + +template storm::storage::BitVector getReachableOneStep(storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::BitVector const& initialStates); + +template storm::storage::BitVector getReachableStates(storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, + storm::storage::BitVector const& targetStates, bool useStepBound, uint_fast64_t maximalSteps, + boost::optional const& choiceFilter); + +template storm::storage::BitVector getBsccCover(storm::storage::SparseMatrix const& transitionMatrix); + +template bool hasCycle(storm::storage::SparseMatrix const& transitionMatrix, boost::optional const& subsystem); + +template bool checkIfECWithChoiceExists(storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& subsystem, + storm::storage::BitVector const& choices); + +template std::vector getDistances(storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::BitVector const& initialStates, boost::optional const& subsystem); + +template storm::storage::BitVector performProbGreater0(storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, + bool useStepBound = false, uint_fast64_t maximalSteps = 0); + +template storm::storage::BitVector performProb1(storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, + storm::storage::BitVector const& statesWithProbabilityGreater0); + +template storm::storage::BitVector performProb1(storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); + +template std::pair performProb01(storm::models::sparse::DeterministicModel const& model, + storm::storage::BitVector const& phiStates, + storm::storage::BitVector const& psiStates); + +template std::pair performProb01(storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& phiStates, + storm::storage::BitVector const& psiStates); + +template void computeSchedulerProbGreater0E(storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, + storm::storage::Scheduler& scheduler, boost::optional const& rowFilter); + +template void computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::Scheduler& scheduler); + +template void computeSchedulerRewInf(storm::storage::BitVector const& rewInfStates, storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::SparseMatrix const& backwardTransitions, storm::storage::Scheduler& scheduler); + +template void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix const& transitionMatrix, + storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, + storm::storage::BitVector const& psiStates, storm::storage::Scheduler& scheduler, + boost::optional const& rowFilter = boost::none); + +template storm::storage::BitVector performProbGreater0E(storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, + bool useStepBound = false, uint_fast64_t maximalSteps = 0); + +template storm::storage::BitVector performProb0A(storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); + +template storm::storage::BitVector performProb1E(storm::storage::SparseMatrix const& transitionMatrix, + std::vector const& nondeterministicChoiceIndices, + storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, + boost::optional const& choiceConstraint = boost::none); + +template storm::storage::BitVector performProb1E(storm::models::sparse::NondeterministicModel const& model, + storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); + +template std::pair performProb01Max( + storm::storage::SparseMatrix const& transitionMatrix, std::vector const& nondeterministicChoiceIndices, + storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, + storm::storage::BitVector const& psiStates); + +template std::pair performProb01Max( + storm::models::sparse::NondeterministicModel const& model, storm::storage::BitVector const& phiStates, + storm::storage::BitVector const& psiStates); + +template storm::storage::BitVector performProbGreater0A(storm::storage::SparseMatrix const& transitionMatrix, + std::vector const& nondeterministicChoiceIndices, + storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, + bool useStepBound = false, uint_fast64_t maximalSteps = 0, + boost::optional const& choiceConstraint = boost::none); + +template storm::storage::BitVector performProb0E(storm::models::sparse::NondeterministicModel const& model, + storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); + +template storm::storage::BitVector performProb0E(storm::storage::SparseMatrix const& transitionMatrix, + std::vector const& nondeterministicChoiceIndices, + storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); + +template storm::storage::BitVector performProb1A(storm::storage::SparseMatrix const& transitionMatrix, + std::vector const& nondeterministicChoiceIndices, + storm::storage::SparseMatrix const& backwardTransitions, + storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); + +template std::pair performProb01Min( + storm::storage::SparseMatrix const& transitionMatrix, std::vector const& nondeterministicChoiceIndices, + storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, + storm::storage::BitVector const& psiStates); + +template std::pair performProb01Min( + storm::models::sparse::NondeterministicModel const& model, storm::storage::BitVector const& phiStates, + storm::storage::BitVector const& psiStates); + +template ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, + std::vector const& player1RowGrouping, + storm::storage::SparseMatrix const& player1BackwardTransitions, + std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, + storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, + storm::OptimizationDirection const& player2Direction, storm::storage::ExplicitGameStrategyPair* strategyPair); + +template ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, + std::vector const& player1RowGrouping, + storm::storage::SparseMatrix const& player1BackwardTransitions, + std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, + storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, + storm::OptimizationDirection const& player2Direction, storm::storage::ExplicitGameStrategyPair* strategyPair, + boost::optional const& player1Candidates); + +template std::vector getTopologicalSort(storm::storage::SparseMatrix const& matrix, std::vector const& firstStates); +// End storm::interval template storm::storage::BitVector getReachableStates(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, diff --git a/src/storm/utility/graph.h b/src/storm/utility/graph.h index 8572110c37..ffb93f92ee 100644 --- a/src/storm/utility/graph.h +++ b/src/storm/utility/graph.h @@ -58,6 +58,13 @@ class ExplicitGameStrategyPair; namespace utility { namespace graph { +/*! + * Computes the states reachable in one step from the states indicated by the bitvector. + * Assumes that no zero entries exist in the transition matrix. + */ +template +storm::storage::BitVector getReachableOneStep(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates); + /*! * Performs a forward depth-first search through the underlying graph structure to identify the states that * are reachable from the given set only passing through a constrained set of states until some target @@ -285,9 +292,10 @@ std::pair, storm::dd::Bdd> performProb01(storm::model * @param scheduler The resulting scheduler. The scheduler is only set at the given states. * @param rowFilter If given, the returned scheduler will only pick choices such that rowFilter is true for the corresponding matrixrow. */ -template +template void computeSchedulerStayingInStates(storm::storage::BitVector const& states, storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::Scheduler& scheduler, boost::optional const& rowFilter = boost::none); + storm::storage::Scheduler& scheduler, + boost::optional const& rowFilter = boost::none); /*! * Computes a scheduler for the given states that chooses an action that has at least one successor in the @@ -315,10 +323,11 @@ void computeSchedulerWithOneSuccessorInStates(storm::storage::BitVector const& s * @note No choice is defined for ProbGreater0E-States if all the probGreater0-choices violate the row filter. * This also holds for states that only reach psi via such states. */ -template +template void computeSchedulerProbGreater0E(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, - storm::storage::Scheduler& scheduler, boost::optional const& rowFilter = boost::none); + storm::storage::Scheduler& scheduler, + boost::optional const& rowFilter = boost::none); /*! * Computes a scheduler for the given states that have a scheduler that has a reward infinity. @@ -328,9 +337,9 @@ void computeSchedulerProbGreater0E(storm::storage::SparseMatrix const& transi * @param backwardTransitions The reversed transition relation. * @param scheduler The resulting scheduler for the rewInf States. The scheduler is not set at other states. */ -template +template void computeSchedulerRewInf(storm::storage::BitVector const& rewInfStates, storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::SparseMatrix const& backwardTransitions, storm::storage::Scheduler& scheduler); + storm::storage::SparseMatrix const& backwardTransitions, storm::storage::Scheduler& scheduler); /*! * Computes a scheduler for the given states that have a scheduler that has a probability 0. @@ -339,9 +348,9 @@ void computeSchedulerRewInf(storm::storage::BitVector const& rewInfStates, storm * @param transitionMatrix The transition matrix of the system. * @param scheduler The resulting scheduler for the prob0EStates States. The scheduler is not set at probGreater0A states. */ -template +template void computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix const& transitionMatrix, - storm::storage::Scheduler& scheduler); + storm::storage::Scheduler& scheduler); /*! * Computes a scheduler for the given prob1EStates such that in the induced system the given psiStates are reached with probability 1. @@ -354,10 +363,10 @@ void computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm * @param scheduler The resulting scheduler for the prob1EStates. The scheduler is not set at the remaining states. * @param rowFilter If given, only scheduler choices within this filter are taken. This filter is ignored for the psiStates. */ -template +template void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, - storm::storage::BitVector const& psiStates, storm::storage::Scheduler& scheduler, + storm::storage::BitVector const& psiStates, storm::storage::Scheduler& scheduler, boost::optional const& rowFilter = boost::none); /*! diff --git a/src/storm/utility/vector.h b/src/storm/utility/vector.h index 5ab453dd75..a3132b9855 100644 --- a/src/storm/utility/vector.h +++ b/src/storm/utility/vector.h @@ -54,6 +54,24 @@ std::size_t findOrInsert(std::vector& vector, T&& element) { return position; } +template +void setAllValues(std::vector& vec, storm::storage::BitVector const& positions, T const& positiveValue = storm::utility::one(), + T const& negativeValue = storm::utility::zero()) { + if (positions.getNumberOfSetBits() * 2 > positions.size()) { + vec.resize(positions.size(), positiveValue); + uint64_t index = positions.getNextUnsetIndex(0); + while (index < positions.size()) { + vec[index] = negativeValue; + index = positions.getNextUnsetIndex(index + 1); + } + } else { + vec.resize(positions.size(), negativeValue); + for (uint64_t index : positions) { + vec[index] = positiveValue; + } + } +} + /*! * Sets the provided values at the provided positions in the given vector. * @@ -63,6 +81,7 @@ std::size_t findOrInsert(std::vector& vector, T&& element) { */ template void setVectorValues(std::vector& vector, storm::storage::BitVector const& positions, std::vector const& values) { + STORM_LOG_ASSERT(positions.size() <= vector.size(), "We cannot set positions that have not been initialized"); STORM_LOG_ASSERT(positions.getNumberOfSetBits() <= values.size(), "The number of selected positions (" << positions.getNumberOfSetBits() << ") exceeds the size of the input vector (" << values.size() << ")."); @@ -74,6 +93,7 @@ void setVectorValues(std::vector& vector, storm::storage::BitVector const& po /*! * Sets the provided value at the provided positions in the given vector. + * Note that the vector must be at least as long. * * @param vector The vector in which the value is to be set. * @param positions The positions at which the value is to be set. @@ -81,6 +101,7 @@ void setVectorValues(std::vector& vector, storm::storage::BitVector const& po */ template void setVectorValues(std::vector& vector, storm::storage::BitVector const& positions, T value) { + STORM_LOG_ASSERT(positions.size() <= vector.size(), "We cannot set positions that have not been initialized"); for (auto position : positions) { vector[position] = value; } @@ -1271,6 +1292,21 @@ std::string toString(std::vector const& vector) { stream << " ]"; return stream.str(); } + +template +std::string toString(std::vector> const& vector) { + std::stringstream stream; + stream << "vector (" << vector.size() << ") [ "; + if (!vector.empty()) { + for (uint_fast64_t i = 0; i < vector.size() - 1; ++i) { + stream << "{" << vector[i].first << "," << vector[i].second << "}, "; + } + stream << "{" << vector.back().first << "," << vector.back().second << "}"; + } + stream << " ]"; + return stream.str(); +} + } // namespace vector } // namespace utility } // namespace storm diff --git a/src/test/storm-dft/api/DftParserTest.cpp b/src/test/storm-dft/api/DftParserTest.cpp index 917286ce30..806bccd6ba 100644 --- a/src/test/storm-dft/api/DftParserTest.cpp +++ b/src/test/storm-dft/api/DftParserTest.cpp @@ -2,6 +2,7 @@ #include "test/storm_gtest.h" #include "storm-dft/api/storm-dft.h" +#include "storm/exceptions/WrongFormatException.h" namespace { diff --git a/src/test/storm-dft/api/DftValidatorTest.cpp b/src/test/storm-dft/api/DftValidatorTest.cpp index cc851a0ecb..092d369fcf 100644 --- a/src/test/storm-dft/api/DftValidatorTest.cpp +++ b/src/test/storm-dft/api/DftValidatorTest.cpp @@ -3,6 +3,7 @@ #include "test/storm_gtest.h" #include "storm-dft/api/storm-dft.h" +#include "storm/exceptions/WrongFormatException.h" namespace { diff --git a/src/test/storm-pars/derivative/SparseDerivativeInstantiationModelCheckerTest.cpp b/src/test/storm-pars/derivative/SparseDerivativeInstantiationModelCheckerTest.cpp index 6013d31ae4..8ef8f4c43f 100644 --- a/src/test/storm-pars/derivative/SparseDerivativeInstantiationModelCheckerTest.cpp +++ b/src/test/storm-pars/derivative/SparseDerivativeInstantiationModelCheckerTest.cpp @@ -18,7 +18,6 @@ #include "storm/storage/expressions/ExpressionManager.h" #include "storm-parsers/api/storm-parsers.h" -#include "storm-parsers/parser/ValueParser.h" #include "storm-pars/analysis/OrderExtender.h" #include "storm-pars/api/storm-pars.h" diff --git a/src/test/storm/modelchecker/prctl/mdp/RobustMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/prctl/mdp/RobustMdpPrctlModelCheckerTest.cpp new file mode 100644 index 0000000000..2ce53079b2 --- /dev/null +++ b/src/test/storm/modelchecker/prctl/mdp/RobustMdpPrctlModelCheckerTest.cpp @@ -0,0 +1,143 @@ +#include "storm-config.h" +#include "test/storm_gtest.h" + +#include "storm-parsers/api/model_descriptions.h" +#include "storm-parsers/api/properties.h" +#include "storm-parsers/parser/DirectEncodingParser.h" +#include "storm/api/builder.h" +#include "storm/api/properties.h" +#include "storm/api/verification.h" +#include "storm/environment/solver/MinMaxSolverEnvironment.h" +#include "storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h" +#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm/models/sparse/Mdp.h" +#include "storm/solver/OptimizationDirection.h" +#include "storm/transformer/AddUncertainty.h" + +std::unique_ptr getInitialStateFilter( + std::shared_ptr> const& model) { + return std::make_unique(model->getInitialStates()); +} + +std::unique_ptr getInitialStateFilter(std::shared_ptr> const& model) { + return std::make_unique(model->getInitialStates()); +} + +double getQuantitativeResultAtInitialState(std::shared_ptr> const& model, + std::unique_ptr& result) { + auto filter = getInitialStateFilter(model); + result->filter(*filter); + return result->asQuantitativeCheckResult().getMin(); +} + +double getQuantitativeResultAtInitialState(std::shared_ptr> const& model, + std::unique_ptr& result) { + auto filter = getInitialStateFilter(model); + result->filter(*filter); + return result->asQuantitativeCheckResult().getMin(); +} + +void expectThrow(std::string const& path, std::string const& formulaString) { + std::shared_ptr> modelPtr = + storm::parser::DirectEncodingParser::parseModel(STORM_TEST_RESOURCES_DIR "/imdp/tiny-04.drn"); + std::vector> formulas = + storm::api::extractFormulasFromProperties(storm::api::parseProperties("Rmin=? [ F \"target\"]")); + + storm::Environment env; + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration); + + std::shared_ptr> mdp = modelPtr->as>(); + ASSERT_EQ(storm::models::ModelType::Mdp, modelPtr->getType()); + auto task = storm::modelchecker::CheckTask(*formulas[0]); + + auto checker = storm::modelchecker::SparseMdpPrctlModelChecker>(*mdp); + STORM_SILENT_EXPECT_THROW(checker.check(env, task), storm::exceptions::InvalidArgumentException); +} + +void checkModel(std::string const& path, std::string const& formulaString, double maxmin, double maxmax, double minmax, double minmin, bool produceScheduler) { + std::shared_ptr> modelPtr = storm::parser::DirectEncodingParser::parseModel(path); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parseProperties(formulaString)); + storm::Environment env; + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration); + + std::shared_ptr> mdp = modelPtr->as>(); + ASSERT_EQ(storm::models::ModelType::Mdp, modelPtr->getType()); + auto taskMax = storm::modelchecker::CheckTask(*formulas[0]); + taskMax.setProduceSchedulers(produceScheduler); + + auto checker = storm::modelchecker::SparseMdpPrctlModelChecker>(*mdp); + auto resultMax = checker.check(env, taskMax); + EXPECT_NEAR(maxmin, getQuantitativeResultAtInitialState(mdp, resultMax), 0.0001); + taskMax.setRobustUncertainty(false); + auto resultMaxNonRobust = checker.check(env, taskMax); + EXPECT_NEAR(maxmax, getQuantitativeResultAtInitialState(mdp, resultMaxNonRobust), 0.0001); + + auto taskMin = storm::modelchecker::CheckTask(*formulas[1]); + taskMin.setProduceSchedulers(produceScheduler); + + auto resultMin = checker.check(env, taskMin); + EXPECT_NEAR(minmax, getQuantitativeResultAtInitialState(mdp, resultMin), 0.0001); + taskMin.setRobustUncertainty(false); + auto resultMinNonRobust = checker.check(env, taskMin); + EXPECT_NEAR(minmin, getQuantitativeResultAtInitialState(mdp, resultMinNonRobust), 0.0001); +} + +void makeUncertainAndCheck(std::string const& path, std::string const& formulaString, double amountOfUncertainty) { + storm::prism::Program program = storm::api::parseProgram(path); + program = storm::utility::prism::preprocess(program, ""); + std::vector> formulas = + storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaString, program)); + std::shared_ptr> modelPtr = storm::api::buildSparseModel(program, formulas); + + auto mdp = modelPtr->as>(); + + ASSERT_TRUE(formulas[0]->isProbabilityOperatorFormula()); + // These tests cases where written with max in mind. + ASSERT_TRUE(formulas[0]->asProbabilityOperatorFormula().getOptimalityType() == storm::solver::OptimizationDirection::Maximize); + auto task = storm::modelchecker::CheckTask(*formulas[0]); + storm::Environment env; + + // First compute certain value + auto checker = storm::modelchecker::SparseMdpPrctlModelChecker>(*mdp); + auto exresult = checker.check(env, task); + double certainValue = getQuantitativeResultAtInitialState(mdp, exresult); + + storm::Environment envIntervals; + envIntervals.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration); + auto transformer = storm::transformer::AddUncertainty(modelPtr); + auto imdp = transformer.transform(amountOfUncertainty)->as>(); + auto ichecker = storm::modelchecker::SparseMdpPrctlModelChecker>(*imdp); + auto iresultMin = checker.check(env, task); + double minValue = getQuantitativeResultAtInitialState(mdp, iresultMin); + EXPECT_LE(minValue, certainValue); + task.setRobustUncertainty(false); + auto iresultMax = checker.check(env, task); + double maxValue = getQuantitativeResultAtInitialState(mdp, iresultMax); + EXPECT_LE(certainValue, maxValue); +} + +TEST(RobustMDPModelCheckingTest, Tiny01maxmin) { + checkModel(STORM_TEST_RESOURCES_DIR "/imdp/tiny-01.drn", "Pmax=? [ F \"target\"];Pmin=? [ F \"target\"]", 0.4, 0.5, 0.5, 0.4, false); +} + +TEST(RobustMDPModelCheckingTest, Tiny03maxmin) { + checkModel(STORM_TEST_RESOURCES_DIR "/imdp/tiny-03.drn", "Pmax=? [ F \"target\"];Pmin=? [ F \"target\"]", 0.4, 0.5, 0.5, 0.4, true); +} + +TEST(RobustMDPModelCheckingTest, BoundedTiny03maxmin) { + expectThrow(STORM_TEST_RESOURCES_DIR "/imdp/tiny-03.drn", "Pmax=? [ F<=3 \"target\"]"); +} + +TEST(RobustMDPModelCheckingTest, Tiny04maxmin) { + checkModel(STORM_TEST_RESOURCES_DIR "/imdp/tiny-04.drn", "Pmax=? [ F \"target\"];Pmin=? [ F \"target\"]", 1, 1, 0.42857, 0.42, false); +} + +TEST(RobustMDPModelCheckingTest, Tiny04maxmin_rewards) { + expectThrow(STORM_TEST_RESOURCES_DIR "/imdp/tiny-04.drn", "Rmin=? [ F \"target\"]"); +} + +TEST(RobustMDPModelCheckingTest, AddUncertaintyCoin22max) { + makeUncertainAndCheck(STORM_TEST_RESOURCES_DIR "/mdp/coin2-2.nm", "Pmax=? [F \"all_coins_equal_1\"]", 0.1); + makeUncertainAndCheck(STORM_TEST_RESOURCES_DIR "/mdp/coin2-2.nm", "Pmax=? [F \"all_coins_equal_1\"]", 0.2); +} diff --git a/src/test/storm/parser/DirectEncodingParserTest.cpp b/src/test/storm/parser/DirectEncodingParserTest.cpp index dd7d95ac67..95bd1f1f54 100644 --- a/src/test/storm/parser/DirectEncodingParserTest.cpp +++ b/src/test/storm/parser/DirectEncodingParserTest.cpp @@ -2,6 +2,7 @@ #include "test/storm_gtest.h" #include "storm-parsers/parser/DirectEncodingParser.h" +#include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/StandardRewardModel.h" @@ -87,3 +88,12 @@ TEST(DirectEncodingParserTest, MarkovAutomatonParsing) { ASSERT_TRUE(modelPtr->hasLabel("one_job_finished")); ASSERT_EQ(6ul, modelPtr->getStates("one_job_finished").getNumberOfSetBits()); } + +TEST(DirectEncodingParserTest, IntervalDtmcTest) { + std::shared_ptr> modelPtr = + storm::parser::DirectEncodingParser::parseModel(STORM_TEST_RESOURCES_DIR "/idtmc/brp-16-2.drn"); + std::shared_ptr> dtmc = modelPtr->as>(); + ASSERT_EQ(storm::models::ModelType::Dtmc, modelPtr->getType()); + ASSERT_EQ(613, dtmc->getNumberOfStates()); + EXPECT_TRUE(modelPtr->hasUncertainty()); +} diff --git a/src/test/storm/transformer/AddUncertaintyTest.cpp b/src/test/storm/transformer/AddUncertaintyTest.cpp new file mode 100644 index 0000000000..a5422068f5 --- /dev/null +++ b/src/test/storm/transformer/AddUncertaintyTest.cpp @@ -0,0 +1,32 @@ +#include "storm-config.h" +#include "storm-parsers/api/storm-parsers.h" +#include "storm-parsers/parser/PrismParser.h" +#include "storm/api/storm.h" +#include "storm/transformer/AddUncertainty.h" +#include "test/storm_gtest.h" + +TEST(AddUncertaintyTransformerTest, BrpTest) { + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/brp-16-2.pm"); + std::string formulasString = "P=? [ F \"target\"]"; + auto formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulasString, program)); + auto model = storm::api::buildSparseModel(program, formulas); + + auto transformer = storm::transformer::AddUncertainty(model); + auto uncertainModel = transformer.transform(0.01); + EXPECT_EQ(uncertainModel->getNumberOfStates(), model->getNumberOfStates()); + EXPECT_EQ(uncertainModel->getNumberOfTransitions(), model->getNumberOfTransitions()); + EXPECT_TRUE(uncertainModel->hasUncertainty()); +} + +TEST(AddUncertaintyTransformerTest, Coin22Test) { + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/coin2-2.nm"); + std::string formulasString = "Pmax=? [ F \"all_coins_equal_1\"]"; + auto formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulasString, program)); + auto model = storm::api::buildSparseModel(program, formulas); + + auto transformer = storm::transformer::AddUncertainty(model); + auto uncertainModel = transformer.transform(0.01); + EXPECT_EQ(uncertainModel->getNumberOfStates(), model->getNumberOfStates()); + EXPECT_EQ(uncertainModel->getNumberOfTransitions(), model->getNumberOfTransitions()); + EXPECT_TRUE(uncertainModel->hasUncertainty()); +} \ No newline at end of file