@ -47,35 +47,47 @@ namespace storm {
template < typename ValueType >
std : : shared_ptr < Polytope < ValueType > > Polytope < ValueType > : : createDownwardClosure ( std : : vector < Point > const & points ) {
if ( points . empty ( ) ) {
if ( points . empty ( ) ) {
// In this case, the downwardclosure is empty
return createEmptyPolytope ( ) ;
}
uint_fast64_t const dimensions = points . front ( ) . size ( ) ;
// Reduce this call to a more general method
storm : : storage : : BitVector dimensions ( points . front ( ) . size ( ) , true ) ;
return createSelectiveDownwardClosure ( points , dimensions ) ;
}
template < typename ValueType >
std : : shared_ptr < Polytope < ValueType > > Polytope < ValueType > : : createSelectiveDownwardClosure ( std : : vector < Point > const & points , storm : : storage : : BitVector const & selectedDimensions ) {
if ( points . empty ( ) ) {
// In this case, the downwardclosure is empty
return createEmptyPolytope ( ) ;
}
if ( selectedDimensions . empty ( ) ) {
return create ( points ) ;
}
assert ( points . front ( ) . size ( ) = = selectedDimensions . size ( ) ) ;
uint64_t dimensions = selectedDimensions . size ( ) ;
std : : vector < Halfspace < ValueType > > halfspaces ;
// We build the convex hull of the given points.
// However, auxiliary points (that will always be in the downward closure) are added.
// However, auxiliary points (that will always be in the selective downward closure) are added.
// Then, the halfspaces of the resulting polytope are a superset of the halfspaces of the downward closure.
std : : vector < Point > auxiliaryPoints = points ;
auxiliaryPoints . reserve ( auxiliaryPoints . size ( ) * ( 1 + dimensions ) ) ;
for ( auto const & point : points ) {
for ( uint_fast64_t dim = 0 ; dim < dimensions ; + + dim ) {
auxiliaryPoints . reserve ( auxiliaryPoints . size ( ) * ( 1 + selecte dD imensions. getNumberOfSetBits ( ) ) ) ;
for ( auto const & point : points ) {
for ( auto const & dim : selectedDimensions ) {
auxiliaryPoints . push_back ( point ) ;
auxiliaryPoints . back ( ) [ dim ] - = storm : : utility : : one < ValueType > ( ) ;
}
}
std : : vector < Halfspace < ValueType > > auxiliaryHalfspaces = create ( auxiliaryPoints ) - > getHalfspaces ( ) ;
// The downward closure is obtained by selecting the halfspaces for which the normal vector is non-negative (coordinate wise).
// Note that due to the auxiliary points, the polytope is never degenerated and thus there is always one unique halfspace-representation which is necessary:
// Consider, e.g., the convex hull of two points (1,0,0) and (0,1,1).
// There are multiple halfspace-representations for this set. In particular, there is one where all but one normalVectors have negative entries.
// However, the downward closure of this set can only be represented with 5 halfspaces.
for ( auto & h : auxiliaryHalfspaces ) {
bool allGreaterZero = true ;
for ( auto const & value : h . normalVector ( ) ) {
allGreaterZero & = ( value > = storm : : utility : : zero < ValueType > ( ) ) ;
// The downward closure is obtained by erasing the halfspaces for which the normal vector is negative for one of the selected dimensions.
for ( auto & h : auxiliaryHalfspaces ) {
bool allGreaterEqZero = true ;
for ( auto const & dim : selectedDimensions ) {
allGreaterEqZero & = ( h . normalVector ( ) [ dim ] > = storm : : utility : : zero < ValueType > ( ) ) ;
}
if ( allGreaterZero ) {
if ( allGreaterEqZero ) {
halfspaces . push_back ( std : : move ( h ) ) ;
}
}
@ -155,11 +167,55 @@ namespace storm {
return std : : vector < Point > ( ) ;
}
template < typename ValueType >
std : : shared_ptr < Polytope < ValueType > > Polytope < ValueType > : : shift ( Point const & b ) const {
// perform an affine transformation with identity matrix
std : : vector < Point > idMatrix ( b . size ( ) , Point ( b . size ( ) , storm : : utility : : zero < ValueType > ( ) ) ) ;
for ( uint64_t i = 0 ; i < b . size ( ) ; + + i ) {
idMatrix [ i ] [ i ] = storm : : utility : : one < ValueType > ( ) ;
}
return affineTransformation ( idMatrix , b ) ;
}
template < typename ValueType >
std : : vector < std : : shared_ptr < Polytope < ValueType > > > Polytope < ValueType > : : setMinus ( std : : shared_ptr < Polytope < ValueType > > const & rhs ) const {
std : : vector < std : : shared_ptr < Polytope < ValueType > > > result ;
auto rhsHalfspaces = rhs - > getHalfspaces ( ) ;
std : : shared_ptr < Polytope < ValueType > > remaining = nullptr ;
for ( auto const & h : rhsHalfspaces ) {
Polytope < ValueType > const & ref = ( remaining = = nullptr ) ? * this : * remaining ;
auto next = ref . intersection ( h . invert ( ) ) ;
if ( ! next - > isEmpty ( ) ) {
result . push_back ( next ) ;
}
remaining = ref . intersection ( h ) ;
if ( remaining - > isEmpty ( ) ) {
break ;
}
}
return result ;
}
template < typename ValueType >
std : : shared_ptr < Polytope < ValueType > > Polytope < ValueType > : : downwardClosure ( ) const {
return createDownwardClosure ( this - > getVertices ( ) ) ;
}
template < typename ValueType >
std : : vector < storm : : expressions : : Variable > Polytope < ValueType > : : declareVariables ( storm : : expressions : : ExpressionManager & manager , std : : string const & namePrefix ) const {
STORM_LOG_THROW ( false , storm : : exceptions : : NotImplementedException , " Functionality not implemented for this polytope implementation. " ) ;
std : : vector < storm : : expressions : : Variable > result ;
return result ;
}
template < typename ValueType >
std : : vector < storm : : expressions : : Expression > Polytope < ValueType > : : getConstraints ( storm : : expressions : : ExpressionManager const & manager , std : : vector < storm : : expressions : : Variable > const & variables ) const {
STORM_LOG_THROW ( false , storm : : exceptions : : NotImplementedException , " Functionality not implemented for this polytope implementation. " ) ;
std : : vector < storm : : expressions : : Expression > result ;
return result ;
}
template < typename ValueType >
template < typename TargetType >
std : : shared_ptr < Polytope < TargetType > > Polytope < ValueType > : : convertNumberRepresentation ( ) const {
@ -197,6 +253,12 @@ namespace storm {
return false ;
}
template < typename ValueType >
std : : shared_ptr < Polytope < ValueType > > Polytope < ValueType > : : clean ( ) {
STORM_LOG_THROW ( false , storm : : exceptions : : NotImplementedException , " functionality not implemented for this polytope type. " ) ;
return nullptr ;
}
template class Polytope < double > ;
template std : : shared_ptr < Polytope < double > > Polytope < double > : : convertNumberRepresentation ( ) const ;