@ -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 > ( ) ) ;
}
if ( allGreaterZero ) {
// 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 ( allGreaterEqZero ) {
halfspaces . push_back ( std : : move ( h ) ) ;
}
}