@ -11,158 +11,213 @@ namespace storm {
template < typename ValueType >
DFTModelChecker < ValueType > : : DFTModelChecker ( ) {
// Intentionally left empty.
checkResult = storm : : utility : : zero < ValueType > ( ) ;
}
template < typename ValueType >
void DFTModelChecker < ValueType > : : check ( storm : : storage : : DFT < ValueType > const & origDft , std : : shared_ptr < const storm : : logic : : Formula > const & formula , bool symred , bool allowModularisation , bool enableDC ) {
void DFTModelChecker < ValueType > : : check ( storm : : storage : : DFT < ValueType > const & origDft , std : : shared_ptr < const storm : : logic : : Formula > const & formula , bool symred , bool allowModularisation , bool enableDC , double approximationError ) {
// Initialize
this - > buildingTime = std : : chrono : : duration < double > : : zero ( ) ;
this - > explorationTime = std : : chrono : : duration < double > : : zero ( ) ;
this - > bisimulationTime = std : : chrono : : duration < double > : : zero ( ) ;
this - > modelCheckingTime = std : : chrono : : duration < double > : : zero ( ) ;
this - > totalTime = std : : chrono : : duration < double > : : zero ( ) ;
this - > approximationError = approximationError ;
std : : chrono : : high_resolution_clock : : time_point totalStart = std : : chrono : : high_resolution_clock : : now ( ) ;
// Optimizing DFT
storm : : storage : : DFT < ValueType > dft = origDft . optimize ( ) ;
checkResult = checkHelper ( dft , formula , symred , allowModularisation , enableDC ) ;
totalTime = std : : chrono : : high_resolution_clock : : now ( ) - totalStart ;
// TODO Matthias: check that all paths reach the target state!
// Checking DFT
checkResult = checkHelper ( dft , formula , symred , allowModularisation , enableDC , approximationError ) ;
this - > totalTime = std : : chrono : : high_resolution_clock : : now ( ) - totalStart ;
}
template < typename ValueType >
ValueType DFTModelChecker < ValueType > : : checkHelper ( storm : : storage : : DFT < ValueType > const & dft , std : : shared_ptr < const storm : : logic : : Formula > const & formula , bool symred , bool allowModularisation , bool enableDC ) {
typename DFTModelChecker < ValueType > : : dft_result DFTModelChecker < ValueType > : : checkHelper ( storm : : storage : : DFT < ValueType > const & dft , std : : shared_ptr < const storm : : logic : : Formula > const & formula , bool symred , bool allowModularisation , bool enableDC , double approximationError ) {
STORM_LOG_TRACE ( " Check helper called " ) ;
bool invResults = false ;
std : : vector < storm : : storage : : DFT < ValueType > > dfts = { dft } ;
std : : vector < ValueType > res ;
size_t nrK = 0 ; // K out of M
size_t nrM = 0 ; // K out of M
bool modularisationPossible = allowModularisation ;
// Try modularisation
if ( allowModularisation ) {
if ( dft . topLevelType ( ) = = storm : : storage : : DFTElementType : : AND ) {
STORM_LOG_TRACE ( " top modularisation called AND " ) ;
dfts = dft . topModularisation ( ) ;
STORM_LOG_TRACE ( " Modularsation into " < < dfts . size ( ) < < " submodules. " ) ;
nrK = dfts . size ( ) ;
nrM = dfts . size ( ) ;
}
if ( dft . topLevelType ( ) = = storm : : storage : : DFTElementType : : OR ) {
STORM_LOG_TRACE ( " top modularisation called OR " ) ;
dfts = dft . topModularisation ( ) ;
STORM_LOG_TRACE ( " Modularsation into " < < dfts . size ( ) < < " submodules. " ) ;
nrK = 0 ;
nrM = dfts . size ( ) ;
invResults = true ;
}
if ( dft . topLevelType ( ) = = storm : : storage : : DFTElementType : : VOT ) {
STORM_LOG_TRACE ( " top modularisation called VOT " ) ;
dfts = dft . topModularisation ( ) ;
STORM_LOG_TRACE ( " Modularsation into " < < dfts . size ( ) < < " submodules. " ) ;
nrK = std : : static_pointer_cast < storm : : storage : : DFTVot < ValueType > const > ( dft . getTopLevelGate ( ) ) - > threshold ( ) ;
nrM = dfts . size ( ) ;
if ( nrK < = nrM / 2 ) {
nrK - = 1 ;
if ( modularisationPossible ) {
bool invResults = false ;
std : : vector < storm : : storage : : DFT < ValueType > > dfts ;
size_t nrK = 0 ; // K out of M
size_t nrM = 0 ; // K out of M
switch ( dft . topLevelType ( ) ) {
case storm : : storage : : DFTElementType : : AND :
STORM_LOG_TRACE ( " top modularisation called AND " ) ;
dfts = dft . topModularisation ( ) ;
STORM_LOG_TRACE ( " Modularsation into " < < dfts . size ( ) < < " submodules. " ) ;
nrK = dfts . size ( ) ;
nrM = dfts . size ( ) ;
modularisationPossible = dfts . size ( ) > 1 ;
break ;
case storm : : storage : : DFTElementType : : OR :
STORM_LOG_TRACE ( " top modularisation called OR " ) ;
dfts = dft . topModularisation ( ) ;
STORM_LOG_TRACE ( " Modularsation into " < < dfts . size ( ) < < " submodules. " ) ;
nrK = 0 ;
nrM = dfts . size ( ) ;
invResults = true ;
}
modularisationPossible = dfts . size ( ) > 1 ;
break ;
case storm : : storage : : DFTElementType : : VOT :
STORM_LOG_TRACE ( " top modularisation called VOT " ) ;
dfts = dft . topModularisation ( ) ;
STORM_LOG_TRACE ( " Modularsation into " < < dfts . size ( ) < < " submodules. " ) ;
nrK = std : : static_pointer_cast < storm : : storage : : DFTVot < ValueType > const > ( dft . getTopLevelGate ( ) ) - > threshold ( ) ;
nrM = dfts . size ( ) ;
if ( nrK < = nrM / 2 ) {
nrK - = 1 ;
invResults = true ;
}
modularisationPossible = dfts . size ( ) > 1 ;
break ;
default :
// No static gate -> no modularisation applicable
modularisationPossible = false ;
break ;
}
if ( dfts . size ( ) > 1 ) {
if ( modularisationPossible ) {
STORM_LOG_TRACE ( " Recursive CHECK Call " ) ;
// TODO Matthias: enable modularisation for approximation
STORM_LOG_ASSERT ( approximationError = = 0.0 , " Modularisation not possible for approximation. " ) ;
// Recursively call model checking
std : : vector < ValueType > res ;
for ( auto const ft : dfts ) {
res . push_back ( checkHelper ( ft , formula , symred , allowModularisation , enableDC ) ) ;
dft_result ftResult = checkHelper ( ft , formula , symred , true , enableDC , 0.0 ) ;
res . push_back ( boost : : get < ValueType > ( ftResult ) ) ;
}
}
}
if ( res . empty ( ) ) {
// Model based modularisation.
auto const & models = buildMarkovModels ( dfts , formula , symred , enableDC ) ;
for ( auto const & model : models ) {
// Model checking
STORM_LOG_INFO ( " Model checking... " ) ;
std : : chrono : : high_resolution_clock : : time_point modelCheckingStart = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : unique_ptr < storm : : modelchecker : : CheckResult > result ( storm : : verifySparseModel ( model , formula ) ) ;
STORM_LOG_INFO ( " Model checking done. " ) ;
STORM_LOG_ASSERT ( result , " Result does not exist. " ) ;
result - > filter ( storm : : modelchecker : : ExplicitQualitativeCheckResult ( model - > getInitialStates ( ) ) ) ;
modelCheckingTime + = std : : chrono : : high_resolution_clock : : now ( ) - modelCheckingStart ;
res . push_back ( result - > asExplicitQuantitativeCheckResult < ValueType > ( ) . getValueMap ( ) . begin ( ) - > second ) ;
// Combine modularisation results
STORM_LOG_TRACE ( " Combining all results... K= " < < nrK < < " ; M= " < < nrM < < " ; invResults= " < < ( invResults ? " On " : " Off " ) ) ;
ValueType result = storm : : utility : : zero < ValueType > ( ) ;
int limK = invResults ? - 1 : nrM + 1 ;
int chK = invResults ? - 1 : 1 ;
for ( int cK = nrK ; cK ! = limK ; cK + = chK ) {
STORM_LOG_ASSERT ( cK > = 0 , " ck negative. " ) ;
size_t permutation = smallestIntWithNBitsSet ( static_cast < size_t > ( cK ) ) ;
do {
STORM_LOG_TRACE ( " Permutation= " < < permutation ) ;
ValueType permResult = storm : : utility : : one < ValueType > ( ) ;
for ( size_t i = 0 ; i < res . size ( ) ; + + i ) {
if ( permutation & ( 1 < < i ) ) {
permResult * = res [ i ] ;
} else {
permResult * = storm : : utility : : one < ValueType > ( ) - res [ i ] ;
}
}
STORM_LOG_TRACE ( " Result for permutation: " < < permResult ) ;
permutation = nextBitPermutation ( permutation ) ;
result + = permResult ;
} while ( permutation < ( 1 < < nrM ) & & permutation ! = 0 ) ;
}
if ( invResults ) {
result = storm : : utility : : one < ValueType > ( ) - result ;
}
return result ;
}
}
if ( nrM < = 1 ) {
// No modularisation done.
STORM_LOG_ASSERT ( res . size ( ) = = 1 , " Result size not 1. " ) ;
return res [ 0 ] ;
}
STORM_LOG_TRACE ( " Combining all results... K= " < < nrK < < " ; M= " < < nrM < < " ; invResults= " < < ( invResults ? " On " : " Off " ) ) ;
ValueType result = storm : : utility : : zero < ValueType > ( ) ;
int limK = invResults ? - 1 : nrM + 1 ;
int chK = invResults ? - 1 : 1 ;
for ( int cK = nrK ; cK ! = limK ; cK + = chK ) {
STORM_LOG_ASSERT ( cK > = 0 , " ck negative. " ) ;
size_t permutation = smallestIntWithNBitsSet ( static_cast < size_t > ( cK ) ) ;
do {
STORM_LOG_TRACE ( " Permutation= " < < permutation ) ;
ValueType permResult = storm : : utility : : one < ValueType > ( ) ;
for ( size_t i = 0 ; i < res . size ( ) ; + + i ) {
if ( permutation & ( 1 < < i ) ) {
permResult * = res [ i ] ;
} else {
permResult * = storm : : utility : : one < ValueType > ( ) - res [ i ] ;
}
}
STORM_LOG_TRACE ( " Result for permutation: " < < permResult ) ;
permutation = nextBitPermutation ( permutation ) ;
result + = permResult ;
} while ( permutation < ( 1 < < nrM ) & & permutation ! = 0 ) ;
}
if ( invResults ) {
return storm : : utility : : one < ValueType > ( ) - result ;
}
return result ;
// If we are here, no modularisation was possible
STORM_LOG_ASSERT ( ! modularisationPossible , " Modularisation should not be possible. " ) ;
return checkDFT ( dft , formula , symred , enableDC , approximationError ) ;
}
template < typename ValueType >
std : : vector < ValueType > DFTModelChecker < ValueType > : : checkModel ( std : : vector < storm : : storage : : DFT < ValueType > > const & dfts , std : : shared_ptr < const storm : : logic : : Formula > const & formula , bool symred , bool enableDC , double approximationError ) {
std : : vector < ValueType > results ;
typename DFTModelChecker < ValueType > : : dft_result DFTModelChecker < ValueType > : : checkDFT ( storm : : storage : : DFT < ValueType > const & dft , std : : shared_ptr < const storm : : logic : : Formula > const & formula , bool symred , bool enableDC , double approximationError ) {
std : : chrono : : high_resolution_clock : : time_point buildingStart = std : : chrono : : high_resolution_clock : : now ( ) ;
auto const & models = buildMarkovModels ( dfts , formula , symred , enableDC ) ;
for ( auto const & model : models ) {
// Model checking
STORM_LOG_INFO ( " Model checking... " ) ;
std : : chrono : : high_resolution_clock : : time_point modelCheckingStart = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : unique_ptr < storm : : modelchecker : : CheckResult > result ( storm : : verifySparseModel ( model , formula ) ) ;
STORM_LOG_INFO ( " Model checking done. " ) ;
STORM_LOG_ASSERT ( result , " Result does not exist. " ) ;
result - > filter ( storm : : modelchecker : : ExplicitQualitativeCheckResult ( model - > getInitialStates ( ) ) ) ;
modelCheckingTime + = std : : chrono : : high_resolution_clock : : now ( ) - modelCheckingStart ;
results . push_back ( result - > asExplicitQuantitativeCheckResult < ValueType > ( ) . getValueMap ( ) . begin ( ) - > second ) ;
// Find symmetries
std : : map < size_t , std : : vector < std : : vector < size_t > > > emptySymmetry ;
storm : : storage : : DFTIndependentSymmetries symmetries ( emptySymmetry ) ;
if ( symred ) {
auto colouring = dft . colourDFT ( ) ;
symmetries = dft . findSymmetries ( colouring ) ;
STORM_LOG_INFO ( " Found " < < symmetries . groups . size ( ) < < " symmetries. " ) ;
STORM_LOG_TRACE ( " Symmetries: " < < std : : endl < < symmetries ) ;
}
return results ;
}
std : : chrono : : high_resolution_clock : : time_point buildingEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
buildingTime + = buildingEnd - buildingStart ;
template < typename ValueType >
std : : vector < std : : shared_ptr < storm : : models : : sparse : : Model < ValueType > > > DFTModelChecker < ValueType > : : buildMarkovModels ( std : : vector < storm : : storage : : DFT < ValueType > > const & dfts , std : : shared_ptr < const storm : : logic : : Formula > const & formula , bool symred , bool enableDC , double approximationError ) {
std : : vector < std : : shared_ptr < storm : : models : : sparse : : Model < ValueType > > > models ;
for ( auto & dft : dfts ) {
std : : chrono : : high_resolution_clock : : time_point buildingStart = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : map < size_t , std : : vector < std : : vector < size_t > > > emptySymmetry ;
storm : : storage : : DFTIndependentSymmetries symmetries ( emptySymmetry ) ;
if ( symred ) {
auto colouring = dft . colourDFT ( ) ;
symmetries = dft . findSymmetries ( colouring ) ;
STORM_LOG_INFO ( " Found " < < symmetries . groups . size ( ) < < " symmetries. " ) ;
STORM_LOG_TRACE ( " Symmetries: " < < std : : endl < < symmetries ) ;
}
std : : chrono : : high_resolution_clock : : time_point buildingEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
buildingTime + = buildingEnd - buildingStart ;
if ( approximationError > 0.0 ) {
// Build approximate Markov Automata for lower and upper bound
double currentApproximationError = approximationError ;
approximation_result approxResult = std : : make_pair ( storm : : utility : : zero < ValueType > ( ) , storm : : utility : : zero < ValueType > ( ) ) ;
std : : chrono : : high_resolution_clock : : time_point explorationStart ;
std : : shared_ptr < storm : : models : : sparse : : Model < ValueType > > model ;
storm : : builder : : ExplicitDFTModelBuilderApprox < ValueType > builder ( dft , symmetries , enableDC ) ;
typename storm : : builder : : ExplicitDFTModelBuilderApprox < ValueType > : : LabelOptions labeloptions ; // TODO initialize this with the formula
// Building Markov Automaton
size_t iteration = 0 ;
do {
// Iteratively build finer models
// TODO Matthias: implement refinement
STORM_LOG_ASSERT ( iteration < 1 , " Iterative refinement not yet implemented. " ) ;
explorationStart = std : : chrono : : high_resolution_clock : : now ( ) ;
STORM_LOG_INFO ( " Building model... " ) ;
// TODO Matthias refine model using existing model and MC results
currentApproximationError = pow ( 0.1 , iteration ) * approximationError ;
builder . buildModel ( labeloptions , currentApproximationError ) ;
// TODO Matthias: possible to do bisimulation on approximated model and not on concrete one?
// Build model for lower bound
STORM_LOG_INFO ( " Getting model for lower bound... " ) ;
model = builder . getModelApproximation ( true ) ;
//model->printModelInformationToStream(std::cout);
STORM_LOG_INFO ( " No. states (Explored): " < < model - > getNumberOfStates ( ) ) ;
STORM_LOG_INFO ( " No. transitions (Explored): " < < model - > getNumberOfTransitions ( ) ) ;
if ( model - > getNumberOfStates ( ) < = 15 ) {
STORM_LOG_TRACE ( " Transition matrix: " < < std : : endl < < model - > getTransitionMatrix ( ) ) ;
} else {
STORM_LOG_TRACE ( " Transition matrix: too big to print " ) ;
}
explorationTime + = std : : chrono : : high_resolution_clock : : now ( ) - explorationStart ;
// Check lower bound
std : : unique_ptr < storm : : modelchecker : : CheckResult > result = checkModel ( model , formula ) ;
result - > filter ( storm : : modelchecker : : ExplicitQualitativeCheckResult ( model - > getInitialStates ( ) ) ) ;
approxResult . first = result - > asExplicitQuantitativeCheckResult < ValueType > ( ) . getValueMap ( ) . begin ( ) - > second ;
// Build model for upper bound
STORM_LOG_INFO ( " Getting model for upper bound... " ) ;
explorationStart = std : : chrono : : high_resolution_clock : : now ( ) ;
model = builder . getModelApproximation ( false ) ;
//model->printModelInformationToStream(std::cout);
STORM_LOG_INFO ( " No. states (Explored): " < < model - > getNumberOfStates ( ) ) ;
STORM_LOG_INFO ( " No. transitions (Explored): " < < model - > getNumberOfTransitions ( ) ) ;
if ( model - > getNumberOfStates ( ) < = 15 ) {
STORM_LOG_TRACE ( " Transition matrix: " < < std : : endl < < model - > getTransitionMatrix ( ) ) ;
} else {
STORM_LOG_TRACE ( " Transition matrix: too big to print " ) ;
}
explorationTime + = std : : chrono : : high_resolution_clock : : now ( ) - explorationStart ;
// Check upper bound
result = checkModel ( model , formula ) ;
result - > filter ( storm : : modelchecker : : ExplicitQualitativeCheckResult ( model - > getInitialStates ( ) ) ) ;
approxResult . second = result - > asExplicitQuantitativeCheckResult < ValueType > ( ) . getValueMap ( ) . begin ( ) - > second ;
+ + iteration ;
STORM_LOG_TRACE ( " Result after iteration " < < iteration < < " : ( " < < approxResult . first < < " , " < < approxResult . second < < " ) " ) ;
} while ( ! isApproximationSufficient ( approxResult . first , approxResult . second , approximationError ) ) ;
STORM_LOG_INFO ( " Finished approximation after " < < iteration < < " iteration " < < ( iteration > 1 ? " s. " : " . " ) ) ;
return approxResult ;
} else {
// Build a single Markov Automaton
STORM_LOG_INFO ( " Building Model... " ) ;
std : : shared_ptr < storm : : models : : sparse : : Model < ValueType > > model ;
// TODO Matthias: use only one builder if everything works again
if ( storm : : settings : : getModule < storm : : settings : : modules : : DFTSettings > ( ) . computeApproximation ( ) ) {
if ( approximationError > = 0.0 ) {
storm : : builder : : ExplicitDFTModelBuilderApprox < ValueType > builder ( dft , symmetries , enableDC ) ;
typename storm : : builder : : ExplicitDFTModelBuilderApprox < ValueType > : : LabelOptions labeloptions ; // TODO initialize this with the formula
model = builder . buildModel ( labeloptions ) ;
builder . buildModel ( labeloptions ) ;
model = builder . getModel ( ) ;
} else {
storm : : builder : : ExplicitDFTModelBuilder < ValueType > builder ( dft , symmetries , enableDC ) ;
typename storm : : builder : : ExplicitDFTModelBuilder < ValueType > : : LabelOptions labeloptions ; // TODO initialize this with the formula
@ -171,21 +226,45 @@ namespace storm {
//model->printModelInformationToStream(std::cout);
STORM_LOG_INFO ( " No. states (Explored): " < < model - > getNumberOfStates ( ) ) ;
STORM_LOG_INFO ( " No. transitions (Explored): " < < model - > getNumberOfTransitions ( ) ) ;
std : : chrono : : high_resolution_clock : : time_point explorationEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
explorationTime + = explorationEnd - buildingEnd ;
explorationTime + = std : : chrono : : high_resolution_clock : : now ( ) - buildingEnd ;
// Bisimulation
if ( model - > isOfType ( storm : : models : : ModelType : : Ctmc ) & & storm : : settings : : getModule < storm : : settings : : modules : : GeneralSettings > ( ) . isBisimulationSet ( ) ) {
STORM_LOG_INFO ( " Bisimulation... " ) ;
model = storm : : performDeterministicSparseBisimulationMinimization < storm : : models : : sparse : : Ctmc < ValueType > > ( model - > template as < storm : : models : : sparse : : Ctmc < ValueType > > ( ) , { formula } , storm : : storage : : BisimulationType : : Weak ) - > template as < storm : : models : : sparse : : Ctmc < ValueType > > ( ) ;
//model->printModelInformationToStream(std::cout);
}
// Model checking
std : : unique_ptr < storm : : modelchecker : : CheckResult > result = checkModel ( model , formula ) ;
result - > filter ( storm : : modelchecker : : ExplicitQualitativeCheckResult ( model - > getInitialStates ( ) ) ) ;
return result - > asExplicitQuantitativeCheckResult < ValueType > ( ) . getValueMap ( ) . begin ( ) - > second ;
}
}
template < typename ValueType >
std : : unique_ptr < storm : : modelchecker : : CheckResult > DFTModelChecker < ValueType > : : checkModel ( std : : shared_ptr < storm : : models : : sparse : : Model < ValueType > > & model , std : : shared_ptr < const storm : : logic : : Formula > const & formula ) {
// Bisimulation
std : : chrono : : high_resolution_clock : : time_point bisimulationStart = std : : chrono : : high_resolution_clock : : now ( ) ;
if ( model - > isOfType ( storm : : models : : ModelType : : Ctmc ) & & storm : : settings : : getModule < storm : : settings : : modules : : GeneralSettings > ( ) . isBisimulationSet ( ) ) {
STORM_LOG_INFO ( " Bisimulation... " ) ;
model = storm : : performDeterministicSparseBisimulationMinimization < storm : : models : : sparse : : Ctmc < ValueType > > ( model - > template as < storm : : models : : sparse : : Ctmc < ValueType > > ( ) , { formula } , storm : : storage : : BisimulationType : : Weak ) - > template as < storm : : models : : sparse : : Ctmc < ValueType > > ( ) ;
STORM_LOG_INFO ( " No. states (Bisimulation): " < < model - > getNumberOfStates ( ) ) ;
STORM_LOG_INFO ( " No. transitions (Bisimulation): " < < model - > getNumberOfTransitions ( ) ) ;
bisimulationTime + = std : : chrono : : high_resolution_clock : : now ( ) - explorationEnd ;
models . push_back ( model ) ;
}
return models ;
std : : chrono : : high_resolution_clock : : time_point bisimulationEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
bisimulationTime + = bisimulationEnd - bisimulationStart ;
// Check the model
STORM_LOG_INFO ( " Model checking... " ) ;
std : : unique_ptr < storm : : modelchecker : : CheckResult > result ( storm : : verifySparseModel ( model , formula ) ) ;
STORM_LOG_INFO ( " Model checking done. " ) ;
STORM_LOG_ASSERT ( result , " Result does not exist. " ) ;
modelCheckingTime + = std : : chrono : : high_resolution_clock : : now ( ) - bisimulationEnd ;
return result ;
}
template < typename ValueType >
bool DFTModelChecker < ValueType > : : isApproximationSufficient ( ValueType lowerBound , ValueType upperBound , double approximationError ) {
STORM_LOG_THROW ( false , storm : : exceptions : : NotImplementedException , " Approximation works only for double. " ) ;
}
template < >
bool DFTModelChecker < double > : : isApproximationSufficient ( double lowerBound , double upperBound , double approximationError ) {
return upperBound - lowerBound < = approximationError ;
}
template < typename ValueType >
@ -201,7 +280,13 @@ namespace storm {
template < typename ValueType >
void DFTModelChecker < ValueType > : : printResult ( std : : ostream & os ) {
os < < " Result: [ " ;
os < < checkResult < < " ] " < < std : : endl ;
if ( this - > approximationError > 0.0 ) {
approximation_result result = boost : : get < approximation_result > ( checkResult ) ;
os < < " ( " < < result . first < < " , " < < result . second < < " ) " ;
} else {
os < < boost : : get < ValueType > ( checkResult ) ;
}
os < < " ] " < < std : : endl ;
}