@ -4,12 +4,14 @@ 
			
		
	
		
			
				
					# include  <vector> 
  
			
		
	
		
			
				
					# include  <memory> 
  
			
		
	
		
			
				
					# include  <boost/optional.hpp> 
  
			
		
	
		
			
				
					# include  <storm/exceptions/NotSupportedException.h> 
  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# include  "storm/models/sparse/Mdp.h" 
  
			
		
	
		
			
				
					# include  "storm/modelchecker/prctl/helper/rewardbounded/MultiDimensionalRewardUnfolding.h" 
  
			
		
	
		
			
				
					# include  "storm/storage/expressions/ExpressionManager.h" 
  
			
		
	
		
			
				
					# include  "storm/storage/expressions/Expressions.h" 
  
			
		
	
		
			
				
					# include  "storm/storage/BitVector.h" 
  
			
		
	
		
			
				
					# include  "storm/storage/MaximalEndComponentDecomposition.h" 
  
			
		
	
		
			
				
					# include  "storm/utility/vector.h" 
  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# include  "storm/logic/ProbabilityOperatorFormula.h" 
  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -23,11 +25,23 @@ namespace storm { 
			
		
	
		
			
				
					                template < typename  ModelType >  
			
		
	
		
			
				
					                QuantileHelper < ModelType > : : QuantileHelper ( ModelType  const &  model ,  storm : : logic : : QuantileFormula  const &  quantileFormula )  :  model ( model ) ,  quantileFormula ( quantileFormula )  {  
			
		
	
		
			
				
					                    // Intentionally left empty
  
			
		
	
		
			
				
					                    /* Todo: Current assumption:
  
			
		
	
		
			
				
					                     *  Subformula  is  always  prob  operator  with  bounded  until  
			
		
	
		
			
				
					                     *  Each  bound  variable  occurs  at  most  once  ( change  this ? )  
			
		
	
		
			
				
					                     *  cost  bounds  can  either  be  < =  or  >   ( the  epochs  returned  by  the  reward  unfolding  assume  this .  One  could  translate  them ,  though )  
			
		
	
		
			
				
					                     *  ' reasonable '  quantile  ( e . g .  not  quantile ( max  B ,  Pmax > 0.5  [ F  < = B  G ] )  ( we  could  also  filter  out  these  things  early  on )  
			
		
	
		
			
				
					                     */  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                std : : shared_ptr < storm : : logic : : ProbabilityOperatorFormula >  replaceBoundsByGreaterEqZero ( storm : : logic : : ProbabilityOperatorFormula  const &  boundedUntilOperator ,  storm : : storage : : BitVector  const &  dimensionsToReplace )  {  
			
		
	
		
			
				
					                enum  class  BoundTransformation  {  
			
		
	
		
			
				
					                    None ,  
			
		
	
		
			
				
					                    GreaterZero ,  
			
		
	
		
			
				
					                    GreaterEqualZero ,  
			
		
	
		
			
				
					                    LessEqualZero  
			
		
	
		
			
				
					                } ;  
			
		
	
		
			
				
					                std : : shared_ptr < storm : : logic : : ProbabilityOperatorFormula >  transformBoundedUntilOperator ( storm : : logic : : ProbabilityOperatorFormula  const &  boundedUntilOperator ,  std : : vector < BoundTransformation >  const &  transformations )  {  
			
		
	
		
			
				
					                    auto  const &  origBoundedUntil  =  boundedUntilOperator . getSubformula ( ) . asBoundedUntilFormula ( ) ;  
			
		
	
		
			
				
					                    STORM_LOG_ASSERT ( dimensionsToReplace . size ( )  = =  origBoundedUntil . getDimension ( ) ,  " Tried to replace the bound of a dimension that is higher than the number of dimensions of the formula. " ) ;  
			
		
	
		
			
				
					                    STORM_LOG_ASSERT ( transformations . size ( )  = =  origBoundedUntil . getDimension ( ) ,  " Tried to replace the bound of a dimension that is higher than the number of dimensions of the formula. " ) ;  
			
		
	
		
			
				
					                    std : : vector < std : : shared_ptr < storm : : logic : : Formula  const > >  leftSubformulas ,  rightSubformulas ;  
			
		
	
		
			
				
					                    std : : vector < boost : : optional < storm : : logic : : TimeBound > >  lowerBounds ,  upperBounds ;  
			
		
	
		
			
				
					                    std : : vector < storm : : logic : : TimeBoundReference >  timeBoundReferences ;  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -36,7 +50,19 @@ namespace storm { 
			
		
	
		
			
				
					                        leftSubformulas . push_back ( origBoundedUntil . getLeftSubformula ( dim ) . asSharedPointer ( ) ) ;  
			
		
	
		
			
				
					                        rightSubformulas . push_back ( origBoundedUntil . getRightSubformula ( dim ) . asSharedPointer ( ) ) ;  
			
		
	
		
			
				
					                        timeBoundReferences . push_back ( origBoundedUntil . getTimeBoundReference ( dim ) ) ;  
			
		
	
		
			
				
					                        if  ( dimensionsToReplace . get ( dim ) )  {  
			
		
	
		
			
				
					                        if  ( transformations [ dim ]  = =  BoundTransformation : : None )  {  
			
		
	
		
			
				
					                            if  ( origBoundedUntil . hasLowerBound ( ) )  {  
			
		
	
		
			
				
					                                lowerBounds . push_back ( storm : : logic : : TimeBound ( origBoundedUntil . isLowerBoundStrict ( dim ) ,  origBoundedUntil . getLowerBound ( dim ) ) ) ;  
			
		
	
		
			
				
					                            }  else  {  
			
		
	
		
			
				
					                                lowerBounds . push_back ( boost : : none ) ;  
			
		
	
		
			
				
					                            }  
			
		
	
		
			
				
					                            if  ( origBoundedUntil . hasUpperBound ( ) )  {  
			
		
	
		
			
				
					                                upperBounds . push_back ( storm : : logic : : TimeBound ( origBoundedUntil . isUpperBoundStrict ( dim ) ,  origBoundedUntil . getUpperBound ( dim ) ) ) ;  
			
		
	
		
			
				
					                            }  else  {  
			
		
	
		
			
				
					                                upperBounds . push_back ( boost : : none ) ;  
			
		
	
		
			
				
					                            }  
			
		
	
		
			
				
					                        }  else  {  
			
		
	
		
			
				
					                            // We need a zero expression in all other cases
  
			
		
	
		
			
				
					                            storm : : expressions : : Expression  zero ;  
			
		
	
		
			
				
					                            if  ( origBoundedUntil . hasLowerBound ( dim ) )  {  
			
		
	
		
			
				
					                                zero  =  origBoundedUntil . getLowerBound ( dim ) . getManager ( ) . rational ( 0.0 ) ;  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -44,17 +70,12 @@ namespace storm { 
			
		
	
		
			
				
					                                STORM_LOG_THROW ( origBoundedUntil . hasUpperBound ( dim ) ,  storm : : exceptions : : InvalidOperationException ,  " The given bounded until formula has no cost-bound for one dimension. " ) ;  
			
		
	
		
			
				
					                                zero  =  origBoundedUntil . getUpperBound ( dim ) . getManager ( ) . rational ( 0.0 ) ;  
			
		
	
		
			
				
					                            }  
			
		
	
		
			
				
					                            lowerBounds . push_back ( storm : : logic : : TimeBound ( false ,  zero ) ) ;  
			
		
	
		
			
				
					                            upperBounds . push_back ( boost : : none ) ;  
			
		
	
		
			
				
					                        }  else  {  
			
		
	
		
			
				
					                            if  ( origBoundedUntil . hasLowerBound ( ) )  {  
			
		
	
		
			
				
					                                lowerBounds . push_back ( storm : : logic : : TimeBound ( origBoundedUntil . isLowerBoundStrict ( dim ) ,  origBoundedUntil . getLowerBound ( dim ) ) ) ;  
			
		
	
		
			
				
					                            }  else  {  
			
		
	
		
			
				
					                            if  ( transformations [ dim ]  = =  BoundTransformation : : LessEqualZero )  {  
			
		
	
		
			
				
					                                lowerBounds . push_back ( boost : : none ) ;  
			
		
	
		
			
				
					                            }  
			
		
	
		
			
				
					                            if  ( origBoundedUntil . hasUpperBound ( ) )  {  
			
		
	
		
			
				
					                                lowerBounds . push_back ( storm : : logic : : TimeBound ( origBoundedUntil . isUpperBoundStrict ( dim ) ,  origBoundedUntil . getUpperBound ( dim ) ) ) ;  
			
		
	
		
			
				
					                                upperBounds . push_back ( storm : : logic : : TimeBound ( false ,  zero ) ) ;  
			
		
	
		
			
				
					                            }  else  {  
			
		
	
		
			
				
					                                STORM_LOG_ASSERT ( transformations [ dim ]  = =  BoundTransformation : : GreaterZero  | |  transformations [ dim ]  = =  BoundTransformation : : GreaterEqualZero ,  " Unhandled bound transformation. " ) ;  
			
		
	
		
			
				
					                                lowerBounds . push_back ( storm : : logic : : TimeBound ( transformations [ dim ]  = =  BoundTransformation : : GreaterZero ,  zero ) ) ;  
			
		
	
		
			
				
					                                upperBounds . push_back ( boost : : none ) ;  
			
		
	
		
			
				
					                            }  
			
		
	
		
			
				
					                        }  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -63,15 +84,36 @@ namespace storm { 
			
		
	
		
			
				
					                    return  std : : make_shared < storm : : logic : : ProbabilityOperatorFormula > ( newBoundedUntil ,  boundedUntilOperator . getOperatorInformation ( ) ) ;  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                template < typename  ModelType >  
			
		
	
		
			
				
					                uint64_t  QuantileHelper < ModelType > : : getDimension ( )  const  {  
			
		
	
		
			
				
					                    return  quantileFormula . getSubformula ( ) . asProbabilityOperatorFormula ( ) . getSubformula ( ) . asBoundedUntilFormula ( ) . getDimension ( ) ;  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                template < typename  ModelType >  
			
		
	
		
			
				
					                storm : : storage : : BitVector  QuantileHelper < ModelType > : : getDimensionsForVariable ( storm : : expressions : : Variable  const &  var )  {  
			
		
	
		
			
				
					                storm : : storage : : BitVector  QuantileHelper < ModelType > : : getOpenDimensions ( )  const  {  
			
		
	
		
			
				
					                    auto  const &  boundedUntil  =  quantileFormula . getSubformula ( ) . asProbabilityOperatorFormula ( ) . getSubformula ( ) . asBoundedUntilFormula ( ) ;  
			
		
	
		
			
				
					                    storm : : storage : : BitVector  res ( getDimension ( ) ) ;  
			
		
	
		
			
				
					                    for  ( uint64_t  dim  =  0 ;  dim  <  getDimension ( ) ;  + + dim )  {  
			
		
	
		
			
				
					                        res . set ( dim ,  boundedUntil . hasLowerBound ( dim )  ?  boundedUntil . getLowerBound ( dim ) . containsVariables ( )  :  boundedUntil . getUpperBound ( dim ) . containsVariables ( ) ) ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                    return  res ;  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                template < typename  ModelType >  
			
		
	
		
			
				
					                storm : : solver : : OptimizationDirection  const &  QuantileHelper < ModelType > : : getOptimizationDirForDimension ( uint64_t  const &  dim )  const  {  
			
		
	
		
			
				
					                    auto  const &  boundedUntil  =  quantileFormula . getSubformula ( ) . asProbabilityOperatorFormula ( ) . getSubformula ( ) . asBoundedUntilFormula ( ) ;  
			
		
	
		
			
				
					                    storm : : expressions : : Variable  const &  dimVar  =  ( boundedUntil . hasLowerBound ( )  ?  boundedUntil . getLowerBound ( dim )  :  boundedUntil . getUpperBound ( dim ) ) . getBaseExpression ( ) . asVariableExpression ( ) . getVariable ( ) ;  
			
		
	
		
			
				
					                    for  ( auto  const &  boundVar  :  quantileFormula . getBoundVariables ( ) )  {  
			
		
	
		
			
				
					                        if  ( boundVar . second  = =  dimVar )  {  
			
		
	
		
			
				
					                            return  boundVar . first ;  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                    STORM_LOG_THROW ( false ,  storm : : exceptions : : InvalidOperationException ,  " The bound variable ' "  < <  dimVar . getName ( )  < <  " ' is not specified within the quantile formula ' "  < <  quantileFormula  < <  " '. " ) ;  
			
		
	
		
			
				
					                    return  quantileFormula . getOptimizationDirection ( ) ;  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					                 
			
		
	
		
			
				
					                template < typename  ModelType >  
			
		
	
		
			
				
					                storm : : storage : : BitVector  QuantileHelper < ModelType > : : getDimensionsForVariable ( storm : : expressions : : Variable  const &  var )  const  {  
			
		
	
		
			
				
					                    auto  const &  boundedUntil  =  quantileFormula . getSubformula ( ) . asProbabilityOperatorFormula ( ) . getSubformula ( ) . asBoundedUntilFormula ( ) ;  
			
		
	
		
			
				
					                    storm : : storage : : BitVector  result ( boundedUntil . getDimension ( ) ,  false ) ;  
			
		
	
		
			
				
					                    for  ( uint64_t  dim  =  0 ;  dim  <  boundedUntil . getDimension ( ) ;  + + dim )  {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -86,24 +128,166 @@ namespace storm { 
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                template < typename  ModelType >  
			
		
	
		
			
				
					                std : : vector < std : : vector < typename  ModelType : : ValueType > >  QuantileHelper < ModelType > : : computeMultiDimensional Quantile ( Environment  const &  env )  {  
			
		
	
		
			
				
					                std : : vector < std : : vector < typename  ModelType : : ValueType > >  QuantileHelper < ModelType > : : computeQuantile ( Environment  const &  env )  {  
			
		
	
		
			
				
					                    std : : vector < std : : vector < ValueType > >  result ;  
			
		
	
		
			
				
					                    if  ( ! computeUnboundedValue ( env ) )  {  
			
		
	
		
			
				
					                    if  ( getOpenDimensions ( ) . getNumberOfSetBits ( )  = =  1 )  {  
			
		
	
		
			
				
					                        uint64_t  dimension  =  * getOpenDimensions ( ) . begin ( ) ;  
			
		
	
		
			
				
					                        auto  const &  boundedUntilOperator  =  quantileFormula . getSubformula ( ) . asProbabilityOperatorFormula ( ) ;  
			
		
	
		
			
				
					                         
			
		
	
		
			
				
					                        bool  maxProbSatisfiesFormula  =  boundedUntilOperator . getBound ( ) . isSatisfied ( computeExtremalValue ( env ,  storm : : storage : : BitVector ( getDimension ( ) ,  false ) ) ) ;  
			
		
	
		
			
				
					                        bool  minProbSatisfiesFormula  =  boundedUntilOperator . getBound ( ) . isSatisfied ( computeExtremalValue ( env ,  getOpenDimensions ( ) ) ) ;  
			
		
	
		
			
				
					                        if  ( maxProbSatisfiesFormula  ! =  minProbSatisfiesFormula )  {  
			
		
	
		
			
				
					                            auto  quantileRes  =  computeQuantileForDimension ( env ,  dimension ) ;  
			
		
	
		
			
				
					                            result  =  { { storm : : utility : : convertNumber < ValueType > ( quantileRes . first )  *  quantileRes . second } } ;  
			
		
	
		
			
				
					                        }  else  if  ( maxProbSatisfiesFormula )  {  
			
		
	
		
			
				
					                            // i.e., all bound values satisfy the formula
  
			
		
	
		
			
				
					                            bool  minimizingRewardBound  =  storm : : solver : : minimize ( getOptimizationDirForDimension ( dimension ) ) ;  
			
		
	
		
			
				
					                            bool  upperCostBound  =  boundedUntilOperator . getSubformula ( ) . asBoundedUntilFormula ( ) . hasUpperBound ( dimension ) ;  
			
		
	
		
			
				
					                            if  ( minimizingRewardBound )  {  
			
		
	
		
			
				
					                                result  =  { {  ( upperCostBound  ?  storm : : utility : : zero < ValueType > ( )  :  - storm : : utility : : one < ValueType > ( ) ) } } ;  
			
		
	
		
			
				
					                            }  else  {  
			
		
	
		
			
				
					                                result  =  { {  storm : : utility : : infinity < ValueType > ( ) } } ;  
			
		
	
		
			
				
					                            }  
			
		
	
		
			
				
					                        }  else  {  
			
		
	
		
			
				
					                            // i.e., no bound value satisfies the formula
  
			
		
	
		
			
				
					                            result  =  { { } } ;  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                    }  else  if  ( getOpenDimensions ( ) . getNumberOfSetBits ( )  = =  2 )  {  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    }  else  {  
			
		
	
		
			
				
					                        STORM_LOG_THROW ( false ,  storm : : exceptions : : NotSupportedException ,  " The quantile formula considers  "  < <  getOpenDimensions ( ) . getNumberOfSetBits ( )  < <  "  open dimensions. Only one- or two-dimensional quantiles are supported. " ) ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                    return  result ;  
			
		
	
		
			
				
					                    /*
  
			
		
	
		
			
				
					                                        return  unboundedFormula - > getBound ( ) . isSatisfied ( numericResult ) ;  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    if  ( ! checkUnboundedValue ( env ) )  {  
			
		
	
		
			
				
					                        STORM_LOG_INFO ( " Bound is not satisfiable. " ) ;  
			
		
	
		
			
				
					                        result . emplace_back ( ) ;  
			
		
	
		
			
				
					                        for  ( auto  const &  bv  :  quantileFormula . getBoundVariables ( ) )  {  
			
		
	
		
			
				
					                            result . front ( ) . push_back ( storm : : solver : : minimize ( bv . first )  ?  storm : : utility : : infinity < ValueType > ( )  :  - storm : : utility : : infinity < ValueType > ( ) ) ;  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                    }  else  {  
			
		
	
		
			
				
					                        std : : vector < bool >  limitProbCheckResults ;  
			
		
	
		
			
				
					                        for  ( uint64_t  dim  =  0 ;  dim  <  getDimension ( ) ;  + + dim )  {  
			
		
	
		
			
				
					                            storm : : storage : : BitVector  dimAsBitVector ( getDimension ( ) ,  false ) ;  
			
		
	
		
			
				
					                            dimAsBitVector . set ( dim ,  true ) ;  
			
		
	
		
			
				
					                            limitProbCheckResults . push_back ( checkLimitProbability ( env ,  dimAsBitVector ) ) ;  
			
		
	
		
			
				
					                            auto  quantileRes  =  computeQuantileForDimension ( env ,  dim ) ;  
			
		
	
		
			
				
					                            std : : cout  < <  " Quantile for dim  "  < <  dim  < <  "  is  "  < <  ( storm : : utility : : convertNumber < ValueType > ( quantileRes . first )  *  quantileRes . second )  < <  std : : endl ;  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                         
			
		
	
		
			
				
					                        result  =  { { 27 } } ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                    return  result ;  
			
		
	
		
			
				
					                    return  result ; */  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                template < typename  ModelType >  
			
		
	
		
			
				
					                bool  QuantileHelper < ModelType > : : computeUnboundedValue ( Environment  const &  env )  {  
			
		
	
		
			
				
					                    auto  unboundedFormula  =  replaceBoundsByGreaterEqZero ( quantileFormula . getSubformula ( ) . asProbabilityOperatorFormula ( ) ,  storm : : storage : : BitVector ( getDimension ( ) ,  true ) ) ;  
			
		
	
		
			
				
					                    MultiDimensionalRewardUnfolding < ValueType ,  true >  rewardUnfolding ( model ,  unboundedFormula ) ;  
			
		
	
		
			
				
					                std : : pair < uint64_t ,  typename  ModelType : : ValueType >  QuantileHelper < ModelType > : : computeQuantileForDimension ( Environment  const &  env ,  uint64_t  dimension )  const  {  
			
		
	
		
			
				
					                    // We assume that their is one bound value that violates the quantile and one bound value that satisfies it.
  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    // 'Drop' all other open bounds
  
			
		
	
		
			
				
					                    std : : vector < BoundTransformation >  bts ( getDimension ( ) ,  BoundTransformation : : None ) ;  
			
		
	
		
			
				
					                    for  ( auto  const &  d  :  getOpenDimensions ( ) )  {  
			
		
	
		
			
				
					                        if  ( d  ! =  dimension )  {  
			
		
	
		
			
				
					                            bts [ d ]  =  BoundTransformation : : GreaterEqualZero ;  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                    auto  transformedFormula  =  transformBoundedUntilOperator ( quantileFormula . getSubformula ( ) . asProbabilityOperatorFormula ( ) ,  bts ) ;  
			
		
	
		
			
				
					                    MultiDimensionalRewardUnfolding < ValueType ,  true >  rewardUnfolding ( model ,  transformedFormula ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                    bool  upperCostBound  =  transformedFormula - > getSubformula ( ) . asBoundedUntilFormula ( ) . hasUpperBound ( dimension ) ;  
			
		
	
		
			
				
					                   // bool lowerProbabilityBound = storm::logic::isLowerBound(transformedFormula->getBound().comparisonType);
  
			
		
	
		
			
				
					                    bool  minimizingRewardBound  =  storm : : solver : : minimize ( getOptimizationDirForDimension ( dimension ) ) ;  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    // initialize data that will be needed for each epoch
  
			
		
	
		
			
				
					                    auto  lowerBound  =  rewardUnfolding . getLowerObjectiveBound ( ) ;  
			
		
	
		
			
				
					                    auto  upperBound  =  rewardUnfolding . getUpperObjectiveBound ( ) ;  
			
		
	
		
			
				
					                    std : : vector < ValueType >  x ,  b ;  
			
		
	
		
			
				
					                    std : : unique_ptr < storm : : solver : : MinMaxLinearEquationSolver < ValueType > >  minMaxSolver ;  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    int64_t  epochValue  =  0 ;  // -1 is actally allowed since we express >=0 as >-1
  
			
		
	
		
			
				
					                    std : : set < typename  EpochManager : : Epoch >  exploredEpochs ;  
			
		
	
		
			
				
					                    while  ( true )  {  
			
		
	
		
			
				
					                        auto  currEpoch  =  rewardUnfolding . getStartEpoch ( true ) ;  
			
		
	
		
			
				
					                        rewardUnfolding . getEpochManager ( ) . setDimensionOfEpoch ( currEpoch ,  dimension ,  ( uint64_t )  epochValue ) ;  
			
		
	
		
			
				
					                        auto  epochOrder  =  rewardUnfolding . getEpochComputationOrder ( currEpoch ) ;  
			
		
	
		
			
				
					                        for  ( auto  const &  epoch  :  epochOrder )  {  
			
		
	
		
			
				
					                            if  ( exploredEpochs . count ( epoch )  = =  0 )  {  
			
		
	
		
			
				
					                                auto &  epochModel  =  rewardUnfolding . setCurrentEpoch ( epoch ) ;  
			
		
	
		
			
				
					                                rewardUnfolding . setSolutionForCurrentEpoch ( epochModel . analyzeSingleObjective ( env ,  quantileFormula . getSubformula ( ) . asProbabilityOperatorFormula ( ) . getOptimalityType ( ) ,  x ,  b ,  minMaxSolver ,  lowerBound ,  upperBound ) ) ;  
			
		
	
		
			
				
					                                exploredEpochs . insert ( epoch ) ;  
			
		
	
		
			
				
					                            }  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                        ValueType  currValue  =  rewardUnfolding . getInitialStateResult ( currEpoch ) ;  
			
		
	
		
			
				
					                        std : : cout  < <  " Numeric result for epoch  "  < <  rewardUnfolding . getEpochManager ( ) . toString ( currEpoch )  < <  "  is  "  < <  currValue  < <  std : : endl ;  
			
		
	
		
			
				
					                        bool  propertySatisfied  =  transformedFormula - > getBound ( ) . isSatisfied ( currValue ) ;  
			
		
	
		
			
				
					                        // If the reward bound should be as small as possible, we should stop as soon as the property is satisfied.
  
			
		
	
		
			
				
					                        // If the reward bound should be as large as possible, we should stop as soon as sthe property is violated and then go a step backwards
  
			
		
	
		
			
				
					                        if  ( minimizingRewardBound  & &  propertySatisfied )  {  
			
		
	
		
			
				
					                            break ;  
			
		
	
		
			
				
					                        }  else  if  ( ! minimizingRewardBound  & &  ! propertySatisfied )  {  
			
		
	
		
			
				
					                            STORM_LOG_ASSERT ( epochValue  >  0  | |  ! upperCostBound ,  " The property does not seem to be satisfiable. This case should have been treated earlier. " ) ;  
			
		
	
		
			
				
					                            - - epochValue ;  
			
		
	
		
			
				
					                            break ;  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                        + + epochValue ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                    return  { epochValue ,  rewardUnfolding . getDimension ( dimension ) . scalingFactor } ;  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					                 
			
		
	
		
			
				
					                template < typename  ModelType >  
			
		
	
		
			
				
					                typename  ModelType : : ValueType  QuantileHelper < ModelType > : : computeExtremalValue ( Environment  const &  env ,  storm : : storage : : BitVector  const &  minimizingDimensions )  const  {  
			
		
	
		
			
				
					                    // For maximizing in a dimension, we can simply 'drop' the bound by replacing it with >=0
  
			
		
	
		
			
				
					                    // For minimizing an upper-bounded dimension, we can replace it with <=0
  
			
		
	
		
			
				
					                    // For minimizing a lower-bounded dimension, the lower bound needs to approach infinity.
  
			
		
	
		
			
				
					                    // To compute this limit probability, we only consider epoch steps that lie in an end component and check for the bound >0 instead.
  
			
		
	
		
			
				
					                    // Notice, however, that this approach fails if we try to minimize for a lower and an upper bounded dimension
  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    std : : vector < BoundTransformation >  bts ( getDimension ( ) ,  BoundTransformation : : None ) ;  
			
		
	
		
			
				
					                    storm : : storage : : BitVector  minimizingLowerBoundedDimensions ( getDimension ( ) ,  false ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                    for  ( auto  const &  d  :  getOpenDimensions ( ) )  {  
			
		
	
		
			
				
					                        if  ( minimizingDimensions . get ( d ) )  {  
			
		
	
		
			
				
					                            bool  upperCostBound  =  quantileFormula . getSubformula ( ) . asProbabilityOperatorFormula ( ) . getSubformula ( ) . asBoundedUntilFormula ( ) . hasUpperBound ( d ) ;  
			
		
	
		
			
				
					                            if  ( upperCostBound )  {  
			
		
	
		
			
				
					                                bts [ d ]  =  BoundTransformation : : LessEqualZero ;  
			
		
	
		
			
				
					                                STORM_LOG_ASSERT ( std : : find ( bts . begin ( ) ,  bts . end ( ) ,  BoundTransformation : : GreaterZero )  = =  bts . end ( ) ,  " Unable to compute extremal value for minimizing lower and upper bounded dimensions. " ) ;  
			
		
	
		
			
				
					                            }  else  {  
			
		
	
		
			
				
					                                bts [ d ]  =  BoundTransformation : : GreaterZero ;  
			
		
	
		
			
				
					                                minimizingLowerBoundedDimensions . set ( d ,  true ) ;  
			
		
	
		
			
				
					                                STORM_LOG_ASSERT ( std : : find ( bts . begin ( ) ,  bts . end ( ) ,  BoundTransformation : : LessEqualZero )  = =  bts . end ( ) ,  " Unable to compute extremal value for minimizing lower and upper bounded dimensions. " ) ;  
			
		
	
		
			
				
					                            }  
			
		
	
		
			
				
					                        }  else  {  
			
		
	
		
			
				
					                            bts [ d ]  =  BoundTransformation : : GreaterEqualZero ;  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                    auto  transformedFormula  =  transformBoundedUntilOperator ( quantileFormula . getSubformula ( ) . asProbabilityOperatorFormula ( ) ,  bts ) ;  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    storm : : storage : : BitVector  nonMecChoices ;  
			
		
	
		
			
				
					                    if  ( ! minimizingLowerBoundedDimensions . empty ( ) )  {  
			
		
	
		
			
				
					                        // Get the choices that do not lie on a mec
  
			
		
	
		
			
				
					                        nonMecChoices . resize ( model . getNumberOfChoices ( ) ,  true ) ;  
			
		
	
		
			
				
					                        auto  mecDecomposition  =  storm : : storage : : MaximalEndComponentDecomposition < ValueType > ( model ) ;  
			
		
	
		
			
				
					                        for  ( auto  const &  mec  :  mecDecomposition )  {  
			
		
	
		
			
				
					                            for  ( auto  const &  stateChoicesPair  :  mec )  {  
			
		
	
		
			
				
					                                for  ( auto  const &  choice  :  stateChoicesPair . second )  {  
			
		
	
		
			
				
					                                    nonMecChoices . set ( choice ,  false ) ;  
			
		
	
		
			
				
					                                }  
			
		
	
		
			
				
					                            }  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                    MultiDimensionalRewardUnfolding < ValueType ,  true >  rewardUnfolding ( model ,  transformedFormula ,  [ & ] ( std : : vector < EpochManager : : Epoch > &  epochSteps ,  EpochManager  const &  epochManager )  {  
			
		
	
		
			
				
					                        if  ( ! minimizingLowerBoundedDimensions . empty ( ) )  {  
			
		
	
		
			
				
					                            for  ( auto  const &  choice  :  nonMecChoices )  {  
			
		
	
		
			
				
					                                for  ( auto  const &  dim  :  minimizingLowerBoundedDimensions )  {  
			
		
	
		
			
				
					                                    epochManager . setDimensionOfEpoch ( epochSteps [ choice ] ,  dim ,  0 ) ;  
			
		
	
		
			
				
					                                }  
			
		
	
		
			
				
					                            }  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                    } ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                    // Get lower and upper bounds for the solution.
  
			
		
	
		
			
				
					                    auto  lowerBound  =  rewardUnfolding . getLowerObjectiveBound ( ) ;  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -112,20 +296,20 @@ namespace storm { 
			
		
	
		
			
				
					                    // Initialize epoch models
  
			
		
	
		
			
				
					                    auto  initEpoch  =  rewardUnfolding . getStartEpoch ( ) ;  
			
		
	
		
			
				
					                    auto  epochOrder  =  rewardUnfolding . getEpochComputationOrder ( initEpoch ) ;  
			
		
	
		
			
				
					                    STORM_LOG_ASSERT ( epochOrder . size ( )  = =  1 ,  " unexpected epoch order size. " ) ;  
			
		
	
		
			
				
					                    // initialize data that will be needed for each epoch
  
			
		
	
		
			
				
					                    std : : vector < ValueType >  x ,  b ;  
			
		
	
		
			
				
					                    std : : unique_ptr < storm : : solver : : MinMaxLinearEquationSolver < ValueType > >  minMaxSolver ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                    auto &  epochModel  =  rewardUnfolding . setCurrentEpoch ( initEpoch ) ;  
			
		
	
		
			
				
					                    rewardUnfolding . setSolutionForCurrentEpoch ( epochModel . analyzeSingleObjective ( env ,  quantileFormula . getSubformula ( ) . asProbabilityOperatorFormula ( ) . getOptimalityType ( ) ,  x ,  b ,  minMaxSolver ,  lowerBound ,  upperBound ) ) ;  
			
		
	
		
			
				
					                    for  ( auto  const &  epoch  :  epochOrder )  {  
			
		
	
		
			
				
					                        auto &  epochModel  =  rewardUnfolding . setCurrentEpoch ( epoch ) ;  
			
		
	
		
			
				
					                        rewardUnfolding . setSolutionForCurrentEpoch ( epochModel . analyzeSingleObjective ( env ,  quantileFormula . getSubformula ( ) . asProbabilityOperatorFormula ( ) . getOptimalityType ( ) ,  x ,  b ,  minMaxSolver ,  lowerBound ,  upperBound ) ) ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                    ValueType  numericResult  =  rewardUnfolding . getInitialStateResult ( initEpoch ) ;  
			
		
	
		
			
				
					                    std : : cout < <  " Numeric result  is "  < <  numericResult ;  
			
		
	
		
			
				
					                    return  unbound edFormula- > getBound ( ) . isSatisfied ( numericResult ) ;  
			
		
	
		
			
				
					                    STORM_LOG_TRACE ( " Extremal probability for minimizing dimensions  "  < <  minimizingDimensions < <  "  is  "  < <  numericResult  < <  " . " )  ;  
			
		
	
		
			
				
					                    return  transform edFormula- > getBound ( ) . isSatisfied ( numericResult ) ;  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                template  class  QuantileHelper < storm : : models : : sparse : : Mdp < double > > ;  
			
		
	
		
			
				
					                template  class  QuantileHelper < storm : : models : : sparse : : Mdp < storm : : RationalNumber > > ;