@ -5,7 +5,7 @@
# include "storm/solver/Z3SmtSolver.h"
# include "storm/solver/Z3SmtSolver.h"
# include "storm/counterexamples/HighLevelCounterexample.h"
# include "storm-counterexamples /counterexamples/HighLevelCounterexample.h"
# include "storm/storage/prism/Program.h"
# include "storm/storage/prism/Program.h"
# include "storm/storage/expressions/Expression.h"
# include "storm/storage/expressions/Expression.h"
@ -1510,7 +1510,7 @@ namespace storm {
* Returns the sub - model obtained from removing all choices that do not originate from the specified filterLabelSet .
* Returns the sub - model obtained from removing all choices that do not originate from the specified filterLabelSet .
* Also returns the Labelsets of the sub - model .
* Also returns the Labelsets of the sub - model .
*/
*/
static std : : pair < std : : shared_ptr < storm : : models : : sparse : : Model < T > > , std : : vector < boost : : container : : flat_set < uint_fast64_t > > > restrictModelToLabelSet ( storm : : models : : sparse : : Model < T > const & model , boost : : container : : flat_set < uint_fast64_t > const & filterLabelSet ) {
static std : : pair < std : : shared_ptr < storm : : models : : sparse : : Model < T > > , std : : vector < boost : : container : : flat_set < uint_fast64_t > > > restrictModelToLabelSet ( storm : : models : : sparse : : Model < T > const & model , boost : : container : : flat_set < uint_fast64_t > const & filterLabelSet , boost : : optional < uint64_t > absorbState = boost : : none ) {
bool customRowGrouping = model . isOfType ( storm : : models : : ModelType : : Mdp ) ;
bool customRowGrouping = model . isOfType ( storm : : models : : ModelType : : Mdp ) ;
@ -1544,7 +1544,8 @@ namespace storm {
if ( customRowGrouping ) {
if ( customRowGrouping ) {
transitionMatrixBuilder . newRowGroup ( currentRow ) ;
transitionMatrixBuilder . newRowGroup ( currentRow ) ;
}
}
transitionMatrixBuilder . addNextValue ( currentRow , state , storm : : utility : : one < T > ( ) ) ;
uint64_t targetState = absorbState = = boost : : none ? state : absorbState . get ( ) ;
transitionMatrixBuilder . addNextValue ( currentRow , targetState , storm : : utility : : one < T > ( ) ) ;
/ / Insert an empty label set for this choice
/ / Insert an empty label set for this choice
resultLabelSet . emplace_back ( ) ;
resultLabelSet . emplace_back ( ) ;
+ + currentRow ;
+ + currentRow ;
@ -1561,17 +1562,25 @@ namespace storm {
return std : : make_pair ( resultModel , std : : move ( resultLabelSet ) ) ;
return std : : make_pair ( resultModel , std : : move ( resultLabelSet ) ) ;
}
}
static T computeMaximalReachabilityProbability ( Environment const & env , storm : : models : : sparse : : Model < T > const & model , storm : : storage : : BitVector const & phiStates , storm : : storage : : BitVector const & psiStates ) {
static T computeMaximalReachabilityProbability ( Environment const & env , storm : : models : : sparse : : Model < T > const & model , storm : : storage : : BitVector const & phiStates , storm : : storage : : BitVector const & psiStates , boost : : optional < std : : string > const & rewardName ) {
T result = storm : : utility : : zero < T > ( ) ;
T result = storm : : utility : : zero < T > ( ) ;
std : : vector < T > allStatesResult ;
std : : vector < T > allStatesResult ;
STORM_LOG_DEBUG ( " Invoking model checker. " ) ;
STORM_LOG_DEBUG ( " Invoking model checker. " ) ;
if ( model . isOfType ( storm : : models : : ModelType : : Dtmc ) ) {
if ( model . isOfType ( storm : : models : : ModelType : : Dtmc ) ) {
allStatesResult = storm : : modelchecker : : helper : : SparseDtmcPrctlHelper < T > : : computeUntilProbabilities ( env , false , model . getTransitionMatrix ( ) , model . getBackwardTransitions ( ) , phiStates , psiStates , false ) ;
if ( rewardName = = boost : : none ) {
allStatesResult = storm : : modelchecker : : helper : : SparseDtmcPrctlHelper < T > : : computeUntilProbabilities ( env , false , model . getTransitionMatrix ( ) , model . getBackwardTransitions ( ) , phiStates , psiStates , false ) ;
} else {
allStatesResult = storm : : modelchecker : : helper : : SparseDtmcPrctlHelper < T > : : computeReachabilityRewards ( env , false , model . getTransitionMatrix ( ) , model . getBackwardTransitions ( ) , model . getRewardModel ( rewardName . get ( ) ) , psiStates , false ) ;
}
} else {
} else {
storm : : modelchecker : : helper : : SparseMdpPrctlHelper < T > modelCheckerHelper ;
allStatesResult = std : : move ( modelCheckerHelper . computeUntilProbabilities ( env , false , model . getTransitionMatrix ( ) , model . getBackwardTransitions ( ) , phiStates , psiStates , false , false ) . values ) ;
if ( rewardName = = boost : : none ) {
storm : : modelchecker : : helper : : SparseMdpPrctlHelper < T > modelCheckerHelper ;
allStatesResult = std : : move ( modelCheckerHelper . computeUntilProbabilities ( env , false , model . getTransitionMatrix ( ) , model . getBackwardTransitions ( ) , phiStates , psiStates , false , false ) . values ) ;
} else {
STORM_LOG_THROW ( rewardName ! = boost : : none , storm : : exceptions : : NotSupportedException , " Reward property counterexample generation is currently only supported for DTMCs. " ) ;
}
}
}
for ( auto state : model . getInitialStates ( ) ) {
for ( auto state : model . getInitialStates ( ) ) {
result = std : : max ( result , allStatesResult [ state ] ) ;
result = std : : max ( result , allStatesResult [ state ] ) ;
@ -1604,11 +1613,12 @@ namespace storm {
* @ param model The sparse model in which to find the minimal command set .
* @ param model The sparse model in which to find the minimal command set .
* @ param phiStates A bit vector characterizing all phi states in the model .
* @ param phiStates A bit vector characterizing all phi states in the model .
* @ param psiStates A bit vector characterizing all psi states in the model .
* @ param psiStates A bit vector characterizing all psi states in the model .
* @ param probabilityThreshold The threshold that is to be achieved or exceeded .
* @ param propertyThreshold The threshold that is to be achieved or exceeded .
* @ param rewardName The name of the reward structure to use , or boost : : none if probabilities are considerd .
* @ param strictBound Indicates whether the threshold needs to be achieved ( true ) or exceeded ( false ) .
* @ param strictBound Indicates whether the threshold needs to be achieved ( true ) or exceeded ( false ) .
* @ param options A set of options for customization .
* @ param options A set of options for customization .
*/
*/
static std : : vector < boost : : container : : flat_set < uint_fast64_t > > getMinimalLabelSet ( Environment const & env , storm : : storage : : SymbolicModelDescription const & symbolicModel , storm : : models : : sparse : : Model < T > const & model , storm : : storage : : BitVector const & phiStates , storm : : storage : : BitVector const & psiStates , double probabilityThreshold , bool strictBound , boost : : container : : flat_set < uint_fast64_t > const & dontCareLabels = boost : : container : : flat_set < uint_fast64_t > ( ) , Options const & options = Options ( ) ) {
static std : : vector < boost : : container : : flat_set < uint_fast64_t > > getMinimalLabelSet ( Environment const & env , storm : : storage : : SymbolicModelDescription const & symbolicModel , storm : : models : : sparse : : Model < T > const & model , storm : : storage : : BitVector const & phiStates , storm : : storage : : BitVector const & psiStates , double propertyThreshold , boost : : optional < std : : string > const & rewardName , bool strictBound , boost : : container : : flat_set < uint_fast64_t > const & dontCareLabels = boost : : container : : flat_set < uint_fast64_t > ( ) , Options const & options = Options ( ) ) {
# ifdef STORM_HAVE_Z3
# ifdef STORM_HAVE_Z3
std : : vector < boost : : container : : flat_set < uint_fast64_t > > result ;
std : : vector < boost : : container : : flat_set < uint_fast64_t > > result ;
/ / Set up all clocks used for time measurement .
/ / Set up all clocks used for time measurement .
@ -1650,10 +1660,10 @@ namespace storm {
/ / ( 1 ) Check whether its possible to exceed the threshold if checkThresholdFeasible is set .
/ / ( 1 ) Check whether its possible to exceed the threshold if checkThresholdFeasible is set .
double maximalReachabilityProbability = 0 ;
double maximalReachabilityProbability = 0 ;
if ( options . checkThresholdFeasible ) {
if ( options . checkThresholdFeasible ) {
maximalReachabilityProbability = computeMaximalReachabilityProbability ( env , model , phiStates , psiStates ) ;
maximalReachabilityProbability = computeMaximalReachabilityProbability ( env , model , phiStates , psiStates , rewardName ) ;
STORM_LOG_THROW ( ( strictBound & & maximalReachabilityProbability > = probabili tyThreshold ) | | ( ! strictBound & & maximalReachabilityProbability > probabili tyThreshold ) , storm : : exceptions : : InvalidArgumentException , " Given probability threshold " < < probabili tyThreshold < < " can not be " < < ( strictBound ? " achieved " : " exceeded " ) < < " in model with maximal reachability probability of " < < maximalReachabilityProbability < < " . " ) ;
std : : cout < < std : : endl < < " Maximal reachability in model is " < < maximalReachabilityProbability < < " . " < < std : : endl < < std : : endl ;
STORM_LOG_THROW ( ( strictBound & & maximalReachabilityProbability > = proper tyThreshold ) | | ( ! strictBound & & maximalReachabilityProbability > proper tyThreshold ) , storm : : exceptions : : InvalidArgumentException , " Given probability threshold " < < proper tyThreshold < < " can not be " < < ( strictBound ? " achieved " : " exceeded " ) < < " in model with maximal reachability probability of " < < maximalReachabilityProbability < < " . " ) ;
std : : cout < < std : : endl < < " Maximal property value in model is " < < maximalReachabilityProbability < < " . " < < std : : endl < < std : : endl ;
}
}
/ / ( 2 ) Identify all states and commands that are relevant , because only these need to be considered later .
/ / ( 2 ) Identify all states and commands that are relevant , because only these need to be considered later .
@ -1705,7 +1715,7 @@ namespace storm {
uint_fast64_t lastSize = 0 ;
uint_fast64_t lastSize = 0 ;
uint_fast64_t iterations = 0 ;
uint_fast64_t iterations = 0 ;
uint_fast64_t currentBound = 0 ;
uint_fast64_t currentBound = 0 ;
maximalReachabilityProbability = 0 ;
double maximalPropertyValue = 0 ;
uint_fast64_t zeroProbabilityCount = 0 ;
uint_fast64_t zeroProbabilityCount = 0 ;
uint64_t smallestCounterexampleSize = model . getNumberOfChoices ( ) ; / / Definitive u
uint64_t smallestCounterexampleSize = model . getNumberOfChoices ( ) ; / / Definitive u
uint64_t progressDelay = storm : : settings : : getModule < storm : : settings : : modules : : GeneralSettings > ( ) . getShowProgressDelay ( ) ;
uint64_t progressDelay = storm : : settings : : getModule < storm : : settings : : modules : : GeneralSettings > ( ) . getShowProgressDelay ( ) ;
@ -1732,18 +1742,18 @@ namespace storm {
}
}
auto subChoiceOrigins = restrictModelToLabelSet ( model , commandSet ) ;
auto subChoiceOrigins = restrictModelToLabelSet ( model , commandSet , psiStates . getNextSetIndex ( 0 ) ) ;
std : : shared_ptr < storm : : models : : sparse : : Model < T > > const & subModel = subChoiceOrigins . first ;
std : : shared_ptr < storm : : models : : sparse : : Model < T > > const & subModel = subChoiceOrigins . first ;
std : : vector < boost : : container : : flat_set < uint_fast64_t > > const & subLabelSets = subChoiceOrigins . second ;
std : : vector < boost : : container : : flat_set < uint_fast64_t > > const & subLabelSets = subChoiceOrigins . second ;
/ / Now determine the maximal reachability probability in the sub - model .
/ / Now determine the maximal reachability probability in the sub - model .
maximalReachabilityProbability = computeMaximalReachabilityProbability ( env , * subModel , phiStates , psiStates ) ;
maximalPropertyValue = computeMaximalReachabilityProbability ( env , * subModel , phiStates , psiStates , rewardName ) ;
totalModelCheckingTime + = std : : chrono : : high_resolution_clock : : now ( ) - modelCheckingClock ;
totalModelCheckingTime + = std : : chrono : : high_resolution_clock : : now ( ) - modelCheckingClock ;
/ / Depending on whether the threshold was successfully achieved or not , we proceed by either analyzing the bad solution or stopping the iteration process .
/ / Depending on whether the threshold was successfully achieved or not , we proceed by either analyzing the bad solution or stopping the iteration process .
analysisClock = std : : chrono : : high_resolution_clock : : now ( ) ;
analysisClock = std : : chrono : : high_resolution_clock : : now ( ) ;
if ( ( strictBound & & maximalReachabilityProbability < probabili tyThreshold ) | | ( ! strictBound & & maximalReachabilityProbability < = probabili tyThreshold ) ) {
if ( maximalReachabilityProbability = = storm : : utility : : zero < T > ( ) ) {
if ( ( strictBound & & maximalPropertyValue < proper tyThreshold ) | | ( ! strictBound & & maximalPropertyValue < = proper tyThreshold ) ) {
if ( maximalPropertyValue = = storm : : utility : : zero < T > ( ) ) {
+ + zeroProbabilityCount ;
+ + zeroProbabilityCount ;
}
}
@ -1759,6 +1769,10 @@ namespace storm {
/ / the given threshold , we analyze the solution and try to guide the solver into the right direction .
/ / the given threshold , we analyze the solution and try to guide the solver into the right direction .
analyzeInsufficientProbabilitySolution ( * solver , * subModel , subLabelSets , model , labelSets , phiStates , psiStates , commandSet , variableInformation , relevancyInformation ) ;
analyzeInsufficientProbabilitySolution ( * solver , * subModel , subLabelSets , model , labelSets , phiStates , psiStates , commandSet , variableInformation , relevancyInformation ) ;
}
}
if ( relevancyInformation . dontCareLabels . size ( ) > 0 ) {
ruleOutSingleSolution ( * solver , commandSet , variableInformation , relevancyInformation ) ;
}
} else {
} else {
/ / Do not guide solver , just rule out current solution .
/ / Do not guide solver , just rule out current solution .
ruleOutSingleSolution ( * solver , commandSet , variableInformation , relevancyInformation ) ;
ruleOutSingleSolution ( * solver , commandSet , variableInformation , relevancyInformation ) ;
@ -1915,22 +1929,41 @@ namespace storm {
std : : cout < < std : : endl < < " Generating minimal label counterexample for formula " < < * formula < < std : : endl ;
std : : cout < < std : : endl < < " Generating minimal label counterexample for formula " < < * formula < < std : : endl ;
}
}
STORM_LOG_THROW ( formula - > isProbabilityOperatorFormula ( ) , storm : : exceptions : : InvalidPropertyException , " Counterexample generation does not support this kind of formula. Expecting a probability operator as the outermost formula element. " ) ;
storm : : logic : : ProbabilityOperatorFormula const & probabilityOperator = formula - > asProbabilityOperatorFormula ( ) ;
STORM_LOG_THROW ( probabilityOperator . hasBound ( ) , storm : : exceptions : : InvalidPropertyException , " Counterexample generation only supports bounded formulas. " ) ;
STORM_LOG_THROW ( probabilityOperator . getSubformula ( ) . isUntilFormula ( ) | | probabilityOperator . getSubformula ( ) . isEventuallyFormula ( ) , storm : : exceptions : : InvalidPropertyException , " Path formula is required to be of the form 'phi U psi' for counterexample generation. " ) ;
storm : : logic : : ComparisonType comparisonType ;
double threshold ;
boost : : optional < std : : string > rewardName = boost : : none ;
STORM_LOG_THROW ( formula - > isProbabilityOperatorFormula ( ) | | formula - > isRewardOperatorFormula ( ) , storm : : exceptions : : InvalidPropertyException , " Counterexample generation does not support this kind of formula. Expecting a probability operator as the outermost formula element. " ) ;
if ( formula - > isProbabilityOperatorFormula ( ) ) {
storm : : logic : : ProbabilityOperatorFormula const & probabilityOperator = formula - > asProbabilityOperatorFormula ( ) ;
STORM_LOG_THROW ( probabilityOperator . hasBound ( ) , storm : : exceptions : : InvalidPropertyException , " Counterexample generation only supports bounded formulas. " ) ;
STORM_LOG_THROW ( probabilityOperator . getSubformula ( ) . isUntilFormula ( ) | | probabilityOperator . getSubformula ( ) . isEventuallyFormula ( ) , storm : : exceptions : : InvalidPropertyException , " Path formula is required to be of the form 'phi U psi' for counterexample generation. " ) ;
comparisonType = probabilityOperator . getComparisonType ( ) ;
threshold = probabilityOperator . getThresholdAs < T > ( ) ;
} else {
assert ( formula - > isRewardOperatorFormula ( ) ) ;
storm : : logic : : RewardOperatorFormula const & rewardOperator = formula - > asRewardOperatorFormula ( ) ;
STORM_LOG_THROW ( rewardOperator . hasBound ( ) , storm : : exceptions : : InvalidPropertyException , " Counterexample generation only supports bounded formulas. " ) ;
STORM_LOG_THROW ( rewardOperator . getSubformula ( ) . isEventuallyFormula ( ) , storm : : exceptions : : InvalidPropertyException , " Path formula is required to be of the form 'F phi' for counterexample generation. " ) ;
comparisonType = rewardOperator . getComparisonType ( ) ;
threshold = rewardOperator . getThresholdAs < T > ( ) ;
rewardName = rewardOperator . getRewardModelName ( ) ;
storm : : logic : : ComparisonType comparisonType = probabilityOperator . getComparisonType ( ) ;
bool strictBound = comparisonType = = storm : : logic : : ComparisonType : : Less ;
double threshold = probabilityOperator . getThresholdAs < T > ( ) ;
STORM_LOG_THROW ( ! storm : : logic : : isLowerBound ( comparisonType ) , storm : : exceptions : : NotSupportedException , " Lower bounds in counterexamples are only supported for probability formulas. " ) ;
}
bool strictBound = comparisonType = = storm : : logic : : ComparisonType : : Less ;
storm : : logic : : Formula const & subformula = formula - > asOperatorFormula ( ) . getSubformula ( ) ;
storm : : storage : : BitVector phiStates ;
storm : : storage : : BitVector phiStates ;
storm : : storage : : BitVector psiStates ;
storm : : storage : : BitVector psiStates ;
storm : : modelchecker : : SparsePropositionalModelChecker < storm : : models : : sparse : : Model < T > > modelchecker ( model ) ;
storm : : modelchecker : : SparsePropositionalModelChecker < storm : : models : : sparse : : Model < T > > modelchecker ( model ) ;
if ( probabilityOperator . getSubformula ( ) . isUntilFormula ( ) ) {
if ( s ubformula. isUntilFormula ( ) ) {
STORM_LOG_THROW ( ! storm : : logic : : isLowerBound ( comparisonType ) , storm : : exceptions : : NotSupportedException , " Lower bounds in counterexamples are only supported for eventually formulas. " ) ;
STORM_LOG_THROW ( ! storm : : logic : : isLowerBound ( comparisonType ) , storm : : exceptions : : NotSupportedException , " Lower bounds in counterexamples are only supported for eventually formulas. " ) ;
storm : : logic : : UntilFormula const & untilFormula = probabilityOperator . getSubformula ( ) . asUntilFormula ( ) ;
storm : : logic : : UntilFormula const & untilFormula = s ubformula. asUntilFormula ( ) ;
std : : unique_ptr < storm : : modelchecker : : CheckResult > leftResult = modelchecker . check ( env , untilFormula . getLeftSubformula ( ) ) ;
std : : unique_ptr < storm : : modelchecker : : CheckResult > leftResult = modelchecker . check ( env , untilFormula . getLeftSubformula ( ) ) ;
std : : unique_ptr < storm : : modelchecker : : CheckResult > rightResult = modelchecker . check ( env , untilFormula . getRightSubformula ( ) ) ;
std : : unique_ptr < storm : : modelchecker : : CheckResult > rightResult = modelchecker . check ( env , untilFormula . getRightSubformula ( ) ) ;
@ -1940,8 +1973,8 @@ namespace storm {
phiStates = leftQualitativeResult . getTruthValuesVector ( ) ;
phiStates = leftQualitativeResult . getTruthValuesVector ( ) ;
psiStates = rightQualitativeResult . getTruthValuesVector ( ) ;
psiStates = rightQualitativeResult . getTruthValuesVector ( ) ;
} else if ( probabilityOperator . getS ubformula( ) . isEventuallyFormula ( ) ) {
storm : : logic : : EventuallyFormula const & eventuallyFormula = probabilityOperator . getS ubformula( ) . asEventuallyFormula ( ) ;
} else if ( s ubformula. isEventuallyFormula ( ) ) {
storm : : logic : : EventuallyFormula const & eventuallyFormula = s ubformula. asEventuallyFormula ( ) ;
std : : unique_ptr < storm : : modelchecker : : CheckResult > subResult = modelchecker . check ( env , eventuallyFormula . getSubformula ( ) ) ;
std : : unique_ptr < storm : : modelchecker : : CheckResult > subResult = modelchecker . check ( env , eventuallyFormula . getSubformula ( ) ) ;
@ -1981,7 +2014,7 @@ namespace storm {
/ / Delegate the actual computation work to the function of equal name .
/ / Delegate the actual computation work to the function of equal name .
auto startTime = std : : chrono : : high_resolution_clock : : now ( ) ;
auto startTime = std : : chrono : : high_resolution_clock : : now ( ) ;
auto labelSets = getMinimalLabelSet ( env , symbolicModel , model , phiStates , psiStates , threshold , strictBound , dontCareLabels , options ) ;
auto labelSets = getMinimalLabelSet ( env , symbolicModel , model , phiStates , psiStates , threshold , rewardName , strictBound , dontCareLabels , options ) ;
auto endTime = std : : chrono : : high_resolution_clock : : now ( ) ;
auto endTime = std : : chrono : : high_resolution_clock : : now ( ) ;
if ( ! options . silent ) {
if ( ! options . silent ) {
for ( auto const & labelSet : labelSets ) {
for ( auto const & labelSet : labelSets ) {