@ -14,30 +14,29 @@ namespace storm {
namespace solver {
namespace solver {
template < typename ValueType >
template < typename ValueType >
NativeMinMaxLinearEquationSolver < ValueType > : : NativeMinMaxLinearEquationSolver ( storm : : storage : : SparseMatrix < ValueType > const & A ) : A ( A ) {
// Get the settings object to customize solving.
storm : : settings : : modules : : NativeEquationSolverSettings const & settings = storm : : settings : : nativeEquationSolverSettings ( ) ;
storm : : settings : : modules : : GeneralSettings const & generalSettings = storm : : settings : : generalSettings ( ) ;
// Get appropriate settings.
precision = settings . getPrecision ( ) ;
relative = settings . getConvergenceCriterion ( ) = = storm : : settings : : modules : : NativeEquationSolverSettings : : ConvergenceCriterion : : Relative ;
maximalNumberOfIterations = settings . getMaximalIterationCount ( ) ;
useValueIteration = ( generalSettings . getMinMaxEquationSolvingTechnique ( ) = = storm : : settings : : modules : : GeneralSettings : : MinMaxTechnique : : ValueIteration ) ;
NativeMinMaxLinearEquationSolver < ValueType > : : NativeMinMaxLinearEquationSolver ( storm : : storage : : SparseMatrix < ValueType > const & A , MinMaxTechniqueSelection preferredTechnique , bool trackPolicy ) :
MinMaxLinearEquationSolver < ValueType > ( A , storm : : settings : : nativeEquationSolverSettings ( ) . getPrecision ( ) , \
storm : : settings : : nativeEquationSolverSettings ( ) . getConvergenceCriterion ( ) = = storm : : settings : : modules : : NativeEquationSolverSettings : : ConvergenceCriterion : : Relative , \
storm : : settings : : nativeEquationSolverSettings ( ) . getMaximalIterationCount ( ) , trackPolicy , preferredTechnique )
{
// Intentionally left empty.
}
}
template < typename ValueType >
template < typename ValueType >
NativeMinMaxLinearEquationSolver < ValueType > : : NativeMinMaxLinearEquationSolver ( storm : : storage : : SparseMatrix < ValueType > const & A , double precision , uint_fast64_t maximalNumberOfIterations , bool useValueIteration , bool relative ) : A ( A ) , precision ( precision ) , relative ( relative ) , maximalNumberOfIterations ( maximalNumberOfIterations ) , useValueIteration ( useValueIteration ) {
NativeMinMaxLinearEquationSolver < ValueType > : : NativeMinMaxLinearEquationSolver ( storm : : storage : : SparseMatrix < ValueType > const & A , double precision , uint_fast64_t maximalNumberOfIterations , MinMaxTechniqueSelection tech , bool relative , bool trackPolicy ) :
MinMaxLinearEquationSolver < ValueType > ( A , precision , \
relative , \
maximalNumberOfIterations , trackPolicy , tech ) {
// Intentionally left empty.
// Intentionally left empty.
}
}
template < typename ValueType >
template < typename ValueType >
void NativeMinMaxLinearEquationSolver < ValueType > : : solveEquationSystem ( bool minimize , std : : vector < ValueType > & x , std : : vector < ValueType > const & b , std : : vector < ValueType > * multiplyResult , std : : vector < ValueType > * newX ) const {
void NativeMinMaxLinearEquationSolver < ValueType > : : solveEquationSystem ( bool minimize , std : : vector < ValueType > & x , std : : vector < ValueType > const & b , std : : vector < ValueType > * multiplyResult , std : : vector < ValueType > * newX ) const {
if ( useValueIteration ) {
if ( this - > useValueIteration ) {
// Set up the environment for the power method. If scratch memory was not provided, we need to create it.
// Set up the environment for the power method. If scratch memory was not provided, we need to create it.
bool multiplyResultMemoryProvided = true ;
bool multiplyResultMemoryProvided = true ;
if ( multiplyResult = = nullptr ) {
if ( multiplyResult = = nullptr ) {
multiplyResult = new std : : vector < ValueType > ( A . getRowCount ( ) ) ;
multiplyResult = new std : : vector < ValueType > ( this - > A . getRowCount ( ) ) ;
multiplyResultMemoryProvided = false ;
multiplyResultMemoryProvided = false ;
}
}
std : : vector < ValueType > * currentX = & x ;
std : : vector < ValueType > * currentX = & x ;
@ -54,21 +53,17 @@ namespace storm {
// Proceed with the iterations as long as the method did not converge or reach the
// Proceed with the iterations as long as the method did not converge or reach the
// user-specified maximum number of iterations.
// user-specified maximum number of iterations.
while ( ! converged & & iterations < maximalNumberOfIterations ) {
while ( ! converged & & iterations < this - > maximalNumberOfIterations ) {
// Compute x' = A*x + b.
// Compute x' = A*x + b.
A . multiplyWithVector ( * currentX , * multiplyResult ) ;
this - > A . multiplyWithVector ( * currentX , * multiplyResult ) ;
storm : : utility : : vector : : addVectors ( * multiplyResult , b , * multiplyResult ) ;
storm : : utility : : vector : : addVectors ( * multiplyResult , b , * multiplyResult ) ;
// Reduce the vector x' by applying min/max for all non-deterministic choices as given by the topmost
// Reduce the vector x' by applying min/max for all non-deterministic choices as given by the topmost
// element of the min/max operator stack.
// element of the min/max operator stack.
if ( minimize ) {
storm : : utility : : vector : : reduceVectorMin ( * multiplyResult , * newX , A . getRowGroupIndices ( ) ) ;
} else {
storm : : utility : : vector : : reduceVectorMax ( * multiplyResult , * newX , A . getRowGroupIndices ( ) ) ;
}
storm : : utility : : vector : : reduceVectorMinOrMax ( minimize , * multiplyResult , * newX , this - > A . getRowGroupIndices ( ) ) ;
// Determine whether the method converged.
// Determine whether the method converged.
converged = storm : : utility : : vector : : equalModuloPrecision < ValueType > ( * currentX , * newX , static_cast < ValueType > ( precision ) , relative ) ;
converged = storm : : utility : : vector : : equalModuloPrecision < ValueType > ( * currentX , * newX , static_cast < ValueType > ( this - > precision ) , this - > relative ) ;
// Update environment variables.
// Update environment variables.
std : : swap ( currentX , newX ) ;
std : : swap ( currentX , newX ) ;
@ -98,11 +93,11 @@ namespace storm {
} else {
} else {
// We will use Policy Iteration to solve the given system.
// We will use Policy Iteration to solve the given system.
// We first guess an initial choice resolution which will be refined after each iteration.
// We first guess an initial choice resolution which will be refined after each iteration.
std : : vector < typename storm : : storage : : SparseMatrix < ValueType > : : index_type > choiceVector ( A . getRowGroupIndices ( ) . size ( ) - 1 ) ;
this - > policy = std : : vector < storm : : storage : : sparse : : state_type > ( this - > A . getRowGroupIndices ( ) . size ( ) - 1 ) ;
// Create our own multiplyResult for solving the deterministic sub-instances.
// Create our own multiplyResult for solving the deterministic sub-instances.
std : : vector < ValueType > deterministicMultiplyResult ( A . getRowGroupIndices ( ) . size ( ) - 1 ) ;
std : : vector < ValueType > subB ( A . getRowGroupIndices ( ) . size ( ) - 1 ) ;
std : : vector < ValueType > deterministicMultiplyResult ( this - > A . getRowGroupIndices ( ) . size ( ) - 1 ) ;
std : : vector < ValueType > subB ( this - > A . getRowGroupIndices ( ) . size ( ) - 1 ) ;
// Check whether intermediate storage was provided and create it otherwise.
// Check whether intermediate storage was provided and create it otherwise.
bool multiplyResultMemoryProvided = true ;
bool multiplyResultMemoryProvided = true ;
@ -126,13 +121,13 @@ namespace storm {
// Proceed with the iterations as long as the method did not converge or reach the user-specified maximum number
// Proceed with the iterations as long as the method did not converge or reach the user-specified maximum number
// of iterations.
// of iterations.
while ( ! converged & & iterations < maximalNumberOfIterations ) {
while ( ! converged & & iterations < this - > maximalNumberOfIterations ) {
// Take the sub-matrix according to the current choices
// Take the sub-matrix according to the current choices
storm : : storage : : SparseMatrix < ValueType > submatrix = A . selectRowsFromRowGroups ( choiceVector , true ) ;
storm : : storage : : SparseMatrix < ValueType > submatrix = this - > A . selectRowsFromRowGroups ( this - > policy , true ) ;
submatrix . convertToEquationSystem ( ) ;
submatrix . convertToEquationSystem ( ) ;
NativeLinearEquationSolver < ValueType > nativeLinearEquationSolver ( submatrix ) ;
NativeLinearEquationSolver < ValueType > nativeLinearEquationSolver ( submatrix ) ;
storm : : utility : : vector : : selectVectorValues < ValueType > ( subB , choiceVector , A . getRowGroupIndices ( ) , b ) ;
storm : : utility : : vector : : selectVectorValues < ValueType > ( subB , this - > policy , this - > A . getRowGroupIndices ( ) , b ) ;
// Copy X since we will overwrite it
// Copy X since we will overwrite it
std : : copy ( currentX - > begin ( ) , currentX - > end ( ) , newX - > begin ( ) ) ;
std : : copy ( currentX - > begin ( ) , currentX - > end ( ) , newX - > begin ( ) ) ;
@ -141,16 +136,13 @@ namespace storm {
nativeLinearEquationSolver . solveEquationSystem ( * newX , subB , & deterministicMultiplyResult ) ;
nativeLinearEquationSolver . solveEquationSystem ( * newX , subB , & deterministicMultiplyResult ) ;
// Compute x' = A*x + b. This step is necessary to allow the choosing of the optimal policy for the next iteration.
// Compute x' = A*x + b. This step is necessary to allow the choosing of the optimal policy for the next iteration.
A . multiplyWithVector ( * newX , * multiplyResult ) ;
this - > A . multiplyWithVector ( * newX , * multiplyResult ) ;
storm : : utility : : vector : : addVectors ( * multiplyResult , b , * multiplyResult ) ;
storm : : utility : : vector : : addVectors ( * multiplyResult , b , * multiplyResult ) ;
// Reduce the vector x by applying min/max over all nondeterministic choices.
// Reduce the vector x by applying min/max over all nondeterministic choices.
// Here, we capture which choice was taken in each state, thereby refining our initial guess.
// Here, we capture which choice was taken in each state, thereby refining our initial guess.
if ( minimize ) {
storm : : utility : : vector : : reduceVectorMin ( * multiplyResult , * newX , A . getRowGroupIndices ( ) , & choiceVector ) ;
} else {
storm : : utility : : vector : : reduceVectorMax ( * multiplyResult , * newX , A . getRowGroupIndices ( ) , & choiceVector ) ;
}
storm : : utility : : vector : : reduceVectorMinOrMax ( minimize , * multiplyResult , * newX , this - > A . getRowGroupIndices ( ) , & ( this - > policy ) ) ;
// Determine whether the method converged.
// Determine whether the method converged.
converged = storm : : utility : : vector : : equalModuloPrecision < ValueType > ( * currentX , * newX , static_cast < ValueType > ( this - > precision ) , this - > relative ) ;
converged = storm : : utility : : vector : : equalModuloPrecision < ValueType > ( * currentX , * newX , static_cast < ValueType > ( this - > precision ) , this - > relative ) ;
@ -166,6 +158,7 @@ namespace storm {
} else {
} else {
LOG4CPLUS_WARN ( logger , " Iterative solver did not converge after " < < iterations < < " iterations. " ) ;
LOG4CPLUS_WARN ( logger , " Iterative solver did not converge after " < < iterations < < " iterations. " ) ;
}
}
// If we performed an odd number of iterations, we need to swap the x and currentX, because the newest result
// If we performed an odd number of iterations, we need to swap the x and currentX, because the newest result
// is currently stored in currentX, but x is the output vector.
// is currently stored in currentX, but x is the output vector.
@ -189,13 +182,13 @@ namespace storm {
// If scratch memory was not provided, we need to create it.
// If scratch memory was not provided, we need to create it.
bool multiplyResultMemoryProvided = true ;
bool multiplyResultMemoryProvided = true ;
if ( multiplyResult = = nullptr ) {
if ( multiplyResult = = nullptr ) {
multiplyResult = new std : : vector < ValueType > ( A . getRowCount ( ) ) ;
multiplyResult = new std : : vector < ValueType > ( this - > A . getRowCount ( ) ) ;
multiplyResultMemoryProvided = false ;
multiplyResultMemoryProvided = false ;
}
}
// Now perform matrix-vector multiplication as long as we meet the bound of the formula.
// Now perform matrix-vector multiplication as long as we meet the bound of the formula.
for ( uint_fast64_t i = 0 ; i < n ; + + i ) {
for ( uint_fast64_t i = 0 ; i < n ; + + i ) {
A . multiplyWithVector ( x , * multiplyResult ) ;
this - > A . multiplyWithVector ( x , * multiplyResult ) ;
// Add b if it is non-null.
// Add b if it is non-null.
if ( b ! = nullptr ) {
if ( b ! = nullptr ) {
@ -204,11 +197,8 @@ namespace storm {
// Reduce the vector x' by applying min/max for all non-deterministic choices as given by the topmost
// Reduce the vector x' by applying min/max for all non-deterministic choices as given by the topmost
// element of the min/max operator stack.
// element of the min/max operator stack.
if ( minimize ) {
storm : : utility : : vector : : reduceVectorMin ( * multiplyResult , x , A . getRowGroupIndices ( ) ) ;
} else {
storm : : utility : : vector : : reduceVectorMax ( * multiplyResult , x , A . getRowGroupIndices ( ) ) ;
}
storm : : utility : : vector : : reduceVectorMinOrMax ( minimize , * multiplyResult , x , this - > A . getRowGroupIndices ( ) ) ;
}
}
if ( ! multiplyResultMemoryProvided ) {
if ( ! multiplyResultMemoryProvided ) {