Browse Source

more tests for reward unfolding

tempestpy_adaptions
TimQu 7 years ago
parent
commit
e1aba323bf
  1. 31
      resources/examples/testfiles/mdp/tiny_reward_bounded.nm
  2. 269
      resources/examples/testfiles/mdp/zeroconf_dl_not_unfolded.nm
  3. 126
      src/test/storm/modelchecker/SparseMdpMultiDimensionalRewardUnfoldingTest.cpp

31
resources/examples/testfiles/mdp/tiny_reward_bounded.nm

@ -0,0 +1,31 @@
mdp
module main
x : [0..4] init 0;
[a] x=0 -> (x'=1);
[b] x=0 -> (x'=2);
[] x=1 | x=2 -> 3/10 : (x'=1) + 7/10 : (x'=2);
[] x=1 -> (x'=3);
[] x=1 -> (x'=1);
[] x=3 -> (x'=2);
[c] x=2 -> 1/5 : (x'=4) + 4/5 : (x'=2);
[c] x=3 -> 1/10 : (x'=5) + 9/10 : (x'=0);
[] x=4 -> (x'=0);
[] x=5 -> (x'=0);
endmodule
rewards "a"
[a] true : 1;
[c] true : 3;
endrewards
rewards "b"
[b] true : 2;
[c] true : 6;
endrewards
rewards "c"
[c] true : 2/5;
endrewards

269
resources/examples/testfiles/mdp/zeroconf_dl_not_unfolded.nm

@ -0,0 +1,269 @@
// IPv4: PTA model with digitial clocks
// one concrete host attempting to choose an ip address
// when a number of (abstract) hosts have already got ip addresses
// gxn/dxp/jzs 02/05/03
//-------------------------------------------------------------
// we suppose that
// - the abstract hosts have already picked their addresses
// and always defend their addresses
// - the concrete host never picks the same ip address twice
// (this can happen only with a verys small probability)
// under these assumptions we do not need message types because:
// 1) since messages to the concrete host will never be a probe,
// this host will react to all messages in the same way
// 2) since the abstract hosts always defend their addresses,
// all messages from the host will get an arp reply if the ip matches
// following from the above assumptions we require only three abstract IP addresses
// (0,1 and 2) which correspond to the following sets of IP addresses:
// 0 - the IP addresses of the abstract hosts which the concrete host
// previously tried to configure
// 1 - an IP address of an abstract host which the concrete host is
// currently trying to configure
// 2 - a fresh IP address which the concrete host is currently trying to configure
// if the host picks an address that is being used it may end up picking another ip address
// in which case there may still be messages corresponding to the old ip address
// to be sent both from and to the host which the host should now disregard
// (since it will never pick the same ip address)
// to deal with this situation: when a host picks a new ip address we reconfigure the
// messages that are still be be sent or are being sent by changing the ip address to 0
// (an old ip address of the host)
// all the messages from the abstract hosts for the 'old' address (in fact the
// set of old addresses since it may have started again more than once)
// can arrive in any order since they are equivalent to the host - it ignores then all
// also the messages for the old and new address will come from different hosts
// (the ones with that ip address) which we model by allowing them to arrive in any order
// i.e. not neccessarily in the order they where sent
//-------------------------------------------------------------
// model is an mdp
mdp
//-------------------------------------------------------------
// VARIABLES
// reset or noreset model
const bool reset;
const int N; // number of abstract hosts
const int K; // number of probes to send
const double loss = 0.1; // probability of message loss
// PROBABILITIES
const double old = N/65024; // probability pick an ip address being used
const double new = (1-old); // probability pick a new ip address
// TIMING CONSTANTS
const int CONSEC = 2; // time interval between sending consecutive probles
const int TRANSTIME = 1; // upper bound on transmission time delay
const int LONGWAIT = 60; // minimum time delay after a high number of address collisions
const int DEFEND = 10;
const int TIME_MAX_X = 60; // max value of clock x
const int TIME_MAX_Y = 10; // max value of clock y
const int TIME_MAX_Z = 1; // max value of clock z
// OTHER CONSTANTS
const int MAXCOLL = 10; // maximum number of collisions before long wait
// size of buffers for other hosts
const int B0 = 20; // buffer size for one abstract host
const int B1 = 8; // buffer sizes for all abstract hosts
//-------------------------------------------------------------
// ENVIRONMENT - models: medium, output buffer of concrete host and all other hosts
module environment
// buffer of concrete host
b_ip7 : [0..2]; // ip address of message in buffer position 8
b_ip6 : [0..2]; // ip address of message in buffer position 7
b_ip5 : [0..2]; // ip address of message in buffer position 6
b_ip4 : [0..2]; // ip address of message in buffer position 5
b_ip3 : [0..2]; // ip address of message in buffer position 4
b_ip2 : [0..2]; // ip address of message in buffer position 3
b_ip1 : [0..2]; // ip address of message in buffer position 2
b_ip0 : [0..2]; // ip address of message in buffer position 1
n : [0..8]; // number of places in the buffer used (from host)
// messages to be sent from abstract hosts to concrete host
n0 : [0..B0]; // number of messages which do not have the host's current ip address
n1 : [0..B1]; // number of messages which have the host's current ip address
b : [0..2]; // local state
// 0 - idle
// 1 - sending message from concrete host
// 2 - sending message from abstract host
z : [0..1]; // clock of environment (needed for the time to send a message)
ip_mess : [0..2]; // ip in the current message being sent
// 0 - different from concrete host
// 1 - same as the concrete host and in use
// 2 - same as the concrete host and not in use
// RESET/RECONFIG: when host is about to choose new ip address
// suppose that the host cannot choose the same ip address
// (since happens with very small probability).
// Therefore all messages will have a different ip address,
// i.e. all n1 messages become n0 ones.
// Note this include any message currently being sent (ip is set to zero 0)
[reset] true -> (n1'=0) & (n0'=min(B0,n0+n1)) // abstract buffers
& (ip_mess'=0) // message being set
& (n'=(reset)?0:n) // concrete buffer (remove this update to get NO_RESET model)
& (b_ip7'=0)
& (b_ip6'=0)
& (b_ip5'=0)
& (b_ip4'=0)
& (b_ip3'=0)
& (b_ip2'=0)
& (b_ip1'=0)
& (b_ip0'=0);
// note: prevent anything else from happening when reconfiguration needs to take place
// time passage (only if no messages to send or sending a message)
[time] l>0 & b=0 & n=0 & n0=0 & n1=0 -> (b'=b); // cannot send a message
[time] l>0 & b>0 & z<1 -> (z'=min(z+1,TIME_MAX_Z)); // sending a message
// get messages to be sent (so message has same ip address as host)
[send] l>0 & n=0 -> (b_ip0'=ip) & (n'=n+1);
[send] l>0 & n=1 -> (b_ip1'=ip) & (n'=n+1);
[send] l>0 & n=2 -> (b_ip2'=ip) & (n'=n+1);
[send] l>0 & n=3 -> (b_ip3'=ip) & (n'=n+1);
[send] l>0 & n=4 -> (b_ip4'=ip) & (n'=n+1);
[send] l>0 & n=5 -> (b_ip5'=ip) & (n'=n+1);
[send] l>0 & n=6 -> (b_ip6'=ip) & (n'=n+1);
[send] l>0 & n=7 -> (b_ip7'=ip) & (n'=n+1);
[send] l>0 & n=8 -> (n'=n); // buffer full so lose message
// start sending message from host
[] l>0 & b=0 & n>0 -> (1-loss) : (b'=1) & (ip_mess'=b_ip0)
& (n'=n-1)
& (b_ip7'=0)
& (b_ip6'=b_ip7)
& (b_ip5'=b_ip6)
& (b_ip4'=b_ip5)
& (b_ip3'=b_ip4)
& (b_ip2'=b_ip3)
& (b_ip1'=b_ip2)
& (b_ip0'=b_ip1) // send message
+ loss : (n'=n-1)
& (b_ip7'=0)
& (b_ip6'=b_ip7)
& (b_ip5'=b_ip6)
& (b_ip4'=b_ip5)
& (b_ip3'=b_ip4)
& (b_ip2'=b_ip3)
& (b_ip1'=b_ip2)
& (b_ip0'=b_ip1); // lose message
// start sending message to host
[] l>0 & b=0 & n0>0 -> (1-loss) : (b'=2) & (ip_mess'=0) & (n0'=n0-1) + loss : (n0'=n0-1); // different ip
[] l>0 & b=0 & n1>0 -> (1-loss) : (b'=2) & (ip_mess'=1) & (n1'=n1-1) + loss : (n1'=n1-1); // same ip
// finish sending message from host
[] l>0 & b=1 & ip_mess=0 -> (b'=0) & (z'=0) & (n0'=min(n0+1,B0)) & (ip_mess'=0);
[] l>0 & b=1 & ip_mess=1 -> (b'=0) & (z'=0) & (n1'=min(n1+1,B1)) & (ip_mess'=0);
[] l>0 & b=1 & ip_mess=2 -> (b'=0) & (z'=0) & (ip_mess'=0);
// finish sending message to host
[rec] l>0 & b=2 -> (b'=0) & (z'=0) & (ip_mess'=0);
endmodule
//-------------------------------------------------------------
// CONCRETE HOST
module host0
x : [0..TIME_MAX_X]; // first clock of the host
y : [0..TIME_MAX_Y]; // second clock of the host
coll : [0..MAXCOLL]; // number of address collisions
probes : [0..K]; // counter (number of probes sent)
mess : [0..1]; // need to send a message or not
defend : [0..1]; // defend (if =1, try to defend IP address)
ip : [1..2]; // ip address (1 - in use & 2 - fresh)
l : [0..4] init 1; // location
// 0 : RECONFIGURE
// 1 : RANDOM
// 2 : WAITSP
// 3 : WAITSG
// 4 : USE
// RECONFIGURE
[reset] l=0 -> (l'=1);
// RANDOM (choose IP address)
[rec] (l=1) -> true; // get message (ignore since have no ip address)
// small number of collisions (choose straight away)
[] l=1 & coll<MAXCOLL -> 1/3*old : (l'=2) & (ip'=1) & (x'=0)
+ 1/3*old : (l'=2) & (ip'=1) & (x'=1)
+ 1/3*old : (l'=2) & (ip'=1) & (x'=2)
+ 1/3*new : (l'=2) & (ip'=2) & (x'=0)
+ 1/3*new : (l'=2) & (ip'=2) & (x'=1)
+ 1/3*new : (l'=2) & (ip'=2) & (x'=2);
// large number of collisions: (wait for LONGWAIT)
[time] l=1 & coll=MAXCOLL & x<LONGWAIT -> (x'=min(x+1,TIME_MAX_X));
[] l=1 & coll=MAXCOLL & x=LONGWAIT -> 1/3*old : (l'=2) & (ip'=1) & (x'=0)
+ 1/3*old : (l'=2) & (ip'=1) & (x'=1)
+ 1/3*old : (l'=2) & (ip'=1) & (x'=2)
+ 1/3*new : (l'=2) & (ip'=2) & (x'=0)
+ 1/3*new : (l'=2) & (ip'=2) & (x'=1)
+ 1/3*new : (l'=2) & (ip'=2) & (x'=2);
// WAITSP
// let time pass
[time] l=2 & x<2 -> (x'=min(x+1,2));
// send probe
[send] l=2 & x=2 & probes<K -> (x'=0) & (probes'=probes+1);
// sent K probes and waited 2 seconds
[] l=2 & x=2 & probes=K -> (l'=3) & (probes'=0) & (coll'=0) & (x'=0);
// get message and ip does not match: ignore
[rec] l=2 & ip_mess!=ip -> (l'=l);
// get a message with matching ip: reconfigure
[rec] l=2 & ip_mess=ip -> (l'=0) & (coll'=min(coll+1,MAXCOLL)) & (x'=0) & (probes'=0);
// WAITSG (sends two gratuitious arp probes)
// time passage
[time] l=3 & mess=0 & defend=0 & x<CONSEC -> (x'=min(x+1,TIME_MAX_X));
[time] l=3 & mess=0 & defend=1 & x<CONSEC -> (x'=min(x+1,TIME_MAX_X)) & (y'=min(y+1,DEFEND));
// receive message and same ip: defend
[rec] l=3 & mess=0 & ip_mess=ip & (defend=0 | y>=DEFEND) -> (defend'=1) & (mess'=1) & (y'=0);
// receive message and same ip: defer
[rec] l=3 & mess=0 & ip_mess=ip & (defend=0 | y<DEFEND) -> (l'=0) & (probes'=0) & (defend'=0) & (x'=0) & (y'=0);
// receive message and different ip
[rec] l=3 & mess=0 & ip_mess!=ip -> (l'=l);
// send probe reply or message for defence
[send] l=3 & mess=1 -> (mess'=0);
// send first gratuitous arp message
[send] l=3 & mess=0 & x=CONSEC & probes<1 -> (x'=0) & (probes'=probes+1);
// send second gratuitous arp message (move to use)
[send] l=3 & mess=0 & x=CONSEC & probes=1 -> (l'=4) & (x'=0) & (y'=0) & (probes'=0);
// USE (only interested in reaching this state so do not need to add anything here)
[] l=4 -> true;
endmodule
//-------------------------------------------------------------
label "ipfound" = l=4 & ip=2;
rewards "t"
[time] true : 1;
endrewards
rewards "r"
[reset] true : 1;
endrewards

126
src/test/storm/modelchecker/SparseMdpMultiDimensionalRewardUnfoldingTest.cpp

@ -11,6 +11,7 @@
#include "storm/utility/constants.h"
#include "storm/api/storm.h"
#if defined STORM_HAVE_HYPRO || defined STORM_HAVE_Z3_OPTIMIZE
TEST(SparseMdpMultiDimensionalRewardUnfoldingTest, one_dim_walk_small) {
@ -111,3 +112,128 @@ TEST(SparseMdpMultiDimensionalRewardUnfoldingTest, one_dim_walk_large) {
}
TEST(SparseMdpMultiDimensionalRewardUnfoldingTest, tiny_ec) {
std::string programFile = STORM_TEST_RESOURCES_DIR "/mdp/tiny_reward_bounded.nm";
std::string constantsDef = "";
std::string formulasAsString = "multi(Pmax=? [ F{\"a\"}<=3 x=4 ]) "; // 0.2
formulasAsString += "; \n multi(Pmin=? [ F{\"a\"}<=3 x=4 ]) "; // 0.0
formulasAsString += "; \n multi(Pmin=? [ F{\"a\"}<1 x=1 ]) "; // 0.0
formulasAsString += "; \n multi(Pmax=? [multi( F{\"a\"}<=4 x=4, F{\"b\"}<=12 x=5 )]) "; // 0.02
formulasAsString += "; \n multi(Pmin=? [multi( F{\"a\"}<=4 x=4, F{\"b\"}<=12 x=5 )]) "; // 0.0
formulasAsString += "; \n multi(Pmax=? [multi( F{\"a\"}<=4 x=4, F{\"b\"}<13 x=5, F{\"c\"}<0.4 x=3 )]) "; // 0.02
formulasAsString += "; \n multi(Pmax=? [multi( F{\"a\"}<=0 x=3, F{\"b\"}<=17 x=4, F{\"c\"}<0.8 x=5 )]) "; // 0.02
formulasAsString += "; \n multi(Pmax=? [multi( F{\"a\"}<=0 x=0, F{\"c\"}<0.5 x=5 )], Pmax=? [multi( F{\"b\"}<=0 x=3, F{\"c\"}<=0.8 x=5 )]) "; // (0.1, 0) , (0, 0.19)
// programm, model, formula
storm::prism::Program program = storm::api::parseProgram(programFile);
program = storm::utility::prism::preprocess(program, constantsDef);
std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulasAsString, program));
std::shared_ptr<storm::models::sparse::Mdp<storm::RationalNumber>> mdp = storm::api::buildSparseModel<storm::RationalNumber>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalNumber>>();
uint_fast64_t const initState = *mdp->getInitialStates().begin();;
std::unique_ptr<storm::modelchecker::CheckResult> result;
result = storm::modelchecker::multiobjective::performMultiObjectiveModelChecking(*mdp, formulas[0]->asMultiObjectiveFormula());
ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
storm::RationalNumber expectedResult = storm::utility::convertNumber<storm::RationalNumber, std::string>("1/5");
EXPECT_EQ(expectedResult, result->asExplicitQuantitativeCheckResult<storm::RationalNumber>()[initState]);
result = storm::modelchecker::multiobjective::performMultiObjectiveModelChecking(*mdp, formulas[1]->asMultiObjectiveFormula());
ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
expectedResult = storm::utility::convertNumber<storm::RationalNumber, std::string>("0");
EXPECT_EQ(expectedResult, result->asExplicitQuantitativeCheckResult<storm::RationalNumber>()[initState]);
result = storm::modelchecker::multiobjective::performMultiObjectiveModelChecking(*mdp, formulas[2]->asMultiObjectiveFormula());
ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
expectedResult = storm::utility::convertNumber<storm::RationalNumber, std::string>("0");
EXPECT_EQ(expectedResult, result->asExplicitQuantitativeCheckResult<storm::RationalNumber>()[initState]);
result = storm::modelchecker::multiobjective::performMultiObjectiveModelChecking(*mdp, formulas[3]->asMultiObjectiveFormula());
ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
expectedResult = storm::utility::convertNumber<storm::RationalNumber, std::string>("1/50");
EXPECT_EQ(expectedResult, result->asExplicitQuantitativeCheckResult<storm::RationalNumber>()[initState]);
result = storm::modelchecker::multiobjective::performMultiObjectiveModelChecking(*mdp, formulas[4]->asMultiObjectiveFormula());
ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
expectedResult = storm::utility::convertNumber<storm::RationalNumber, std::string>("0");
EXPECT_EQ(expectedResult, result->asExplicitQuantitativeCheckResult<storm::RationalNumber>()[initState]);
result = storm::modelchecker::multiobjective::performMultiObjectiveModelChecking(*mdp, formulas[5]->asMultiObjectiveFormula());
ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
expectedResult = storm::utility::convertNumber<storm::RationalNumber, std::string>("1/50");
EXPECT_EQ(expectedResult, result->asExplicitQuantitativeCheckResult<storm::RationalNumber>()[initState]);
result = storm::modelchecker::multiobjective::performMultiObjectiveModelChecking(*mdp, formulas[6]->asMultiObjectiveFormula());
ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
expectedResult = storm::utility::convertNumber<storm::RationalNumber, std::string>("1/50");
EXPECT_EQ(expectedResult, result->asExplicitQuantitativeCheckResult<storm::RationalNumber>()[initState]);
result = storm::modelchecker::multiobjective::performMultiObjectiveModelChecking(*mdp, formulas[7]->asMultiObjectiveFormula());
ASSERT_TRUE(result->isExplicitParetoCurveCheckResult());
std::vector<storm::RationalNumber> p = {storm::utility::convertNumber<storm::RationalNumber, std::string>("1/10"), storm::utility::convertNumber<storm::RationalNumber, std::string>("0")};
std::vector<storm::RationalNumber> q = {storm::utility::convertNumber<storm::RationalNumber, std::string>("0"), storm::utility::convertNumber<storm::RationalNumber, std::string>("19/100")};
auto expectedAchievableValues = storm::storage::geometry::Polytope<storm::RationalNumber>::createDownwardClosure(std::vector<std::vector<storm::RationalNumber>>({p, q}));
EXPECT_TRUE(expectedAchievableValues->contains(result->asExplicitParetoCurveCheckResult<storm::RationalNumber>().getUnderApproximation()));
EXPECT_TRUE(result->asExplicitParetoCurveCheckResult<storm::RationalNumber>().getOverApproximation()->contains(expectedAchievableValues));
}
TEST(SparseMdpMultiDimensionalRewardUnfoldingTest, zeroconf_dl) {
std::string programFile = STORM_TEST_RESOURCES_DIR "/mdp/zeroconf_dl_not_unfolded.nm";
std::string constantsDef = "N=1000,K=2,reset=true";
std::string formulasAsString = "multi(Pmin=? [ F{\"t\"}<50 \"ipfound\" ])";
formulasAsString += "; \n multi(Pmax=? [multi(F{\"t\"}<50 \"ipfound\", F{\"r\"}<=0 \"ipfound\") ])";
// programm, model, formula
storm::prism::Program program = storm::api::parseProgram(programFile);
program = storm::utility::prism::preprocess(program, constantsDef);
std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulasAsString, program));
std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = storm::api::buildSparseModel<double>(program, formulas)->as<storm::models::sparse::Mdp<double>>();
uint_fast64_t const initState = *mdp->getInitialStates().begin();;
std::unique_ptr<storm::modelchecker::CheckResult> result;
result = storm::modelchecker::multiobjective::performMultiObjectiveModelChecking(*mdp, formulas[0]->asMultiObjectiveFormula());
ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
EXPECT_NEAR(0.9989804701, result->asExplicitQuantitativeCheckResult<double>()[initState], storm::settings::getModule<storm::settings::modules::GeneralSettings>().getPrecision());
result = storm::modelchecker::multiobjective::performMultiObjectiveModelChecking(*mdp, formulas[1]->asMultiObjectiveFormula());
ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
EXPECT_NEAR(0.984621063, result->asExplicitQuantitativeCheckResult<double>()[initState], storm::settings::getModule<storm::settings::modules::GeneralSettings>().getPrecision());
}
TEST(SparseMdpMultiDimensionalRewardUnfoldingTest, csma) {
std::string programFile = STORM_TEST_RESOURCES_DIR "/mdp/csma2_2.nm";
std::string constantsDef = "";
std::string formulasAsString = "multi(Pmax=? [ F{\"time\"}<=70 \"all_delivered\" ])";
formulasAsString += "; \n multi(Pmax=? [ F{\"time\"}<=70 \"all_delivered\" ], P>=0 [ !\"collision_max_backoff\" U \"all_delivered\"] )";
// programm, model, formula
storm::prism::Program program = storm::api::parseProgram(programFile);
program = storm::utility::prism::preprocess(program, constantsDef);
std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulasAsString, program));
std::shared_ptr<storm::models::sparse::Mdp<storm::RationalNumber>> mdp = storm::api::buildSparseModel<storm::RationalNumber>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalNumber>>();
uint_fast64_t const initState = *mdp->getInitialStates().begin();;
std::unique_ptr<storm::modelchecker::CheckResult> result;
result = storm::modelchecker::multiobjective::performMultiObjectiveModelChecking(*mdp, formulas[0]->asMultiObjectiveFormula());
ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
storm::RationalNumber expectedResult = storm::utility::convertNumber<storm::RationalNumber, std::string>("29487882838281/35184372088832");
EXPECT_EQ(expectedResult, result->asExplicitQuantitativeCheckResult<storm::RationalNumber>()[initState]);
result = storm::modelchecker::multiobjective::performMultiObjectiveModelChecking(*mdp, formulas[1]->asMultiObjectiveFormula());
ASSERT_TRUE(result->isExplicitParetoCurveCheckResult());
std::vector<storm::RationalNumber> p = {storm::utility::convertNumber<storm::RationalNumber, std::string>("29487882838281/35184372088832"), storm::utility::convertNumber<storm::RationalNumber, std::string>("6979344855/8589934592")};
auto expectedAchievableValues = storm::storage::geometry::Polytope<storm::RationalNumber>::createDownwardClosure(std::vector<std::vector<storm::RationalNumber>>({p}));
EXPECT_TRUE(expectedAchievableValues->contains(result->asExplicitParetoCurveCheckResult<storm::RationalNumber>().getUnderApproximation()));
EXPECT_TRUE(result->asExplicitParetoCurveCheckResult<storm::RationalNumber>().getOverApproximation()->contains(expectedAchievableValues));
}
#endif /* STORM_HAVE_HYPRO || defined STORM_HAVE_Z3_OPTIMIZE */
Loading…
Cancel
Save