Browse Source

Fixed a couple of warnings

main
TimQu 8 years ago
parent
commit
43fdf0a89b
  1. 52
      src/storm/storage/geometry/NativePolytope.cpp
  2. 2
      src/storm/storage/geometry/nativepolytopeconversion/HyperplaneEnumeration.cpp
  3. 126
      src/storm/storage/geometry/nativepolytopeconversion/QuickHull.cpp

52
src/storm/storage/geometry/NativePolytope.cpp

@ -18,15 +18,15 @@ namespace storm {
template <typename ValueType> template <typename ValueType>
NativePolytope<ValueType>::NativePolytope(std::vector<Halfspace<ValueType>> const& halfspaces) { NativePolytope<ValueType>::NativePolytope(std::vector<Halfspace<ValueType>> const& halfspaces) {
if(halfspaces.empty()){
if (halfspaces.empty()){
// The polytope is universal // The polytope is universal
emptyStatus = EmptyStatus::Nonempty; emptyStatus = EmptyStatus::Nonempty;
} else { } else {
uint_fast64_t maxCol = halfspaces.front().normalVector().size(); uint_fast64_t maxCol = halfspaces.front().normalVector().size();
uint_fast64_t maxRow = halfspaces.size(); uint_fast64_t maxRow = halfspaces.size();
A = EigenMatrix(maxRow, maxCol); A = EigenMatrix(maxRow, maxCol);
b = EigenVector(static_cast<unsigned long int>(maxRow));
for ( uint_fast64_t row = 0; row < maxRow; ++row ){
b = EigenVector(maxRow);
for (int_fast64_t row = 0; row < A.rows(); ++row ){
assert(halfspaces[row].normalVector().size() == maxCol); assert(halfspaces[row].normalVector().size() == maxCol);
b(row) = halfspaces[row].offset(); b(row) = halfspaces[row].offset();
A.row(row) = storm::adapters::EigenAdapter::toEigenVector(halfspaces[row].normalVector()); A.row(row) = storm::adapters::EigenAdapter::toEigenVector(halfspaces[row].normalVector());
@ -37,7 +37,7 @@ namespace storm {
template <typename ValueType> template <typename ValueType>
NativePolytope<ValueType>::NativePolytope(std::vector<Point> const& points) { NativePolytope<ValueType>::NativePolytope(std::vector<Point> const& points) {
if(points.empty()){
if (points.empty()){
emptyStatus = EmptyStatus::Empty; emptyStatus = EmptyStatus::Empty;
} else { } else {
std::vector<EigenVector> eigenPoints; std::vector<EigenVector> eigenPoints;
@ -56,10 +56,10 @@ namespace storm {
template <typename ValueType> template <typename ValueType>
std::shared_ptr<Polytope<ValueType>> NativePolytope<ValueType>::create(boost::optional<std::vector<Halfspace<ValueType>>> const& halfspaces, boost::optional<std::vector<Point>> const& points) { std::shared_ptr<Polytope<ValueType>> NativePolytope<ValueType>::create(boost::optional<std::vector<Halfspace<ValueType>>> const& halfspaces, boost::optional<std::vector<Point>> const& points) {
if(halfspaces) {
if (halfspaces) {
STORM_LOG_WARN_COND(!points, "Creating a NativePolytope where halfspaces AND points are given. The points will be ignored."); STORM_LOG_WARN_COND(!points, "Creating a NativePolytope where halfspaces AND points are given. The points will be ignored.");
return std::make_shared<NativePolytope<ValueType>>(*halfspaces); return std::make_shared<NativePolytope<ValueType>>(*halfspaces);
} else if(points) {
} else if (points) {
return std::make_shared<NativePolytope<ValueType>>(*points); return std::make_shared<NativePolytope<ValueType>>(*points);
} }
STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Creating a NativePolytope but no representation was given."); STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Creating a NativePolytope but no representation was given.");
@ -96,7 +96,7 @@ namespace storm {
std::vector<EigenVector> eigenVertices = getEigenVertices(); std::vector<EigenVector> eigenVertices = getEigenVertices();
std::vector<Point> result; std::vector<Point> result;
result.reserve(eigenVertices.size()); result.reserve(eigenVertices.size());
for(auto const& p : eigenVertices) {
for (auto const& p : eigenVertices) {
result.push_back(storm::adapters::EigenAdapter::toStdVector(p)); result.push_back(storm::adapters::EigenAdapter::toStdVector(p));
} }
return result; return result;
@ -107,7 +107,7 @@ namespace storm {
std::vector<Halfspace<ValueType>> result; std::vector<Halfspace<ValueType>> result;
result.reserve(A.rows()); result.reserve(A.rows());
for(uint_fast64_t row=0; row < A.rows(); ++row){
for (int_fast64_t row=0; row < A.rows(); ++row){
result.emplace_back(storm::adapters::EigenAdapter::toStdVector(EigenVector(A.row(row))), b(row)); result.emplace_back(storm::adapters::EigenAdapter::toStdVector(EigenVector(A.row(row))), b(row));
} }
return result; return result;
@ -115,7 +115,7 @@ namespace storm {
template <typename ValueType> template <typename ValueType>
bool NativePolytope<ValueType>::isEmpty() const { bool NativePolytope<ValueType>::isEmpty() const {
if(emptyStatus == EmptyStatus::Unknown) {
if (emptyStatus == EmptyStatus::Unknown) {
std::shared_ptr<storm::expressions::ExpressionManager> manager(new storm::expressions::ExpressionManager()); std::shared_ptr<storm::expressions::ExpressionManager> manager(new storm::expressions::ExpressionManager());
std::unique_ptr<storm::solver::SmtSolver> solver = storm::utility::solver::SmtSolverFactory().create(*manager); std::unique_ptr<storm::solver::SmtSolver> solver = storm::utility::solver::SmtSolverFactory().create(*manager);
std::vector<storm::expressions::Expression> constraints = getConstraints(*manager, declareVariables(*manager, "x")); std::vector<storm::expressions::Expression> constraints = getConstraints(*manager, declareVariables(*manager, "x"));
@ -145,8 +145,8 @@ namespace storm {
template <typename ValueType> template <typename ValueType>
bool NativePolytope<ValueType>::contains(Point const& point) const{ bool NativePolytope<ValueType>::contains(Point const& point) const{
EigenVector x = storm::adapters::EigenAdapter::toEigenVector(point); EigenVector x = storm::adapters::EigenAdapter::toEigenVector(point);
for(uint_fast64_t row=0; row < A.rows(); ++row){
if((A.row(row) * x)(0) > b(row)){
for (int_fast64_t row=0; row < A.rows(); ++row){
if ((A.row(row) * x)(0) > b(row)){
return false; return false;
} }
} }
@ -202,7 +202,7 @@ namespace storm {
template <typename ValueType> template <typename ValueType>
std::shared_ptr<Polytope<ValueType>> NativePolytope<ValueType>::intersection(Halfspace<ValueType> const& halfspace) const{ std::shared_ptr<Polytope<ValueType>> NativePolytope<ValueType>::intersection(Halfspace<ValueType> const& halfspace) const{
if(A.rows() == 0) {
if (A.rows() == 0) {
// No constraints yet // No constraints yet
EigenMatrix resultA = storm::adapters::EigenAdapter::toEigenVector(halfspace.normalVector()).transpose(); EigenMatrix resultA = storm::adapters::EigenAdapter::toEigenVector(halfspace.normalVector()).transpose();
EigenVector resultb(1); EigenVector resultb(1);
@ -220,7 +220,7 @@ namespace storm {
template <typename ValueType> template <typename ValueType>
std::shared_ptr<Polytope<ValueType>> NativePolytope<ValueType>::convexUnion(std::shared_ptr<Polytope<ValueType>> const& rhs) const{ std::shared_ptr<Polytope<ValueType>> NativePolytope<ValueType>::convexUnion(std::shared_ptr<Polytope<ValueType>> const& rhs) const{
STORM_LOG_THROW(rhs->isNativePolytope(), storm::exceptions::InvalidArgumentException, "Invoked operation between a NativePolytope and a different polytope implementation. This is not supported"); STORM_LOG_THROW(rhs->isNativePolytope(), storm::exceptions::InvalidArgumentException, "Invoked operation between a NativePolytope and a different polytope implementation. This is not supported");
if(this->isEmpty()) {
if (this->isEmpty()) {
return std::make_shared<NativePolytope<ValueType>>(dynamic_cast<NativePolytope<ValueType> const&>(*rhs)); return std::make_shared<NativePolytope<ValueType>>(dynamic_cast<NativePolytope<ValueType> const&>(*rhs));
} else if (rhs->isEmpty()) { } else if (rhs->isEmpty()) {
return std::make_shared<NativePolytope<ValueType>>(*this); return std::make_shared<NativePolytope<ValueType>>(*this);
@ -244,7 +244,7 @@ namespace storm {
STORM_LOG_THROW(rhs->isNativePolytope(), storm::exceptions::InvalidArgumentException, "Invoked operation between a NativePolytope and a different polytope implementation. This is not supported"); STORM_LOG_THROW(rhs->isNativePolytope(), storm::exceptions::InvalidArgumentException, "Invoked operation between a NativePolytope and a different polytope implementation. This is not supported");
NativePolytope<ValueType> const& nativeRhs = dynamic_cast<NativePolytope<ValueType> const&>(*rhs); NativePolytope<ValueType> const& nativeRhs = dynamic_cast<NativePolytope<ValueType> const&>(*rhs);
if(this->isEmpty() || nativeRhs.isEmpty()) {
if (this->isEmpty() || nativeRhs.isEmpty()) {
return std::make_shared<NativePolytope<ValueType>>(std::vector<Point>()); return std::make_shared<NativePolytope<ValueType>>(std::vector<Point>());
} }
@ -252,7 +252,7 @@ namespace storm {
resultConstraints.reserve(A.rows() + nativeRhs.A.rows()); resultConstraints.reserve(A.rows() + nativeRhs.A.rows());
// evaluation of rhs in directions of lhs // evaluation of rhs in directions of lhs
for (uint_fast64_t i = 0; i < A.rows(); ++i) {
for (int_fast64_t i = 0; i < A.rows(); ++i) {
auto optimizationRes = nativeRhs.optimize(A.row(i)); auto optimizationRes = nativeRhs.optimize(A.row(i));
if ( optimizationRes.second ) { if ( optimizationRes.second ) {
resultConstraints.emplace_back(A.row(i), b(i) + (A.row(i) * optimizationRes.first)(0)); resultConstraints.emplace_back(A.row(i), b(i) + (A.row(i) * optimizationRes.first)(0));
@ -261,7 +261,7 @@ namespace storm {
} }
// evaluation of lhs in directions of rhs // evaluation of lhs in directions of rhs
for (uint_fast64_t i = 0; i < nativeRhs.A.rows(); ++i) {
for (int_fast64_t i = 0; i < nativeRhs.A.rows(); ++i) {
auto optimizationRes = optimize(nativeRhs.A.row(i)); auto optimizationRes = optimize(nativeRhs.A.row(i));
if ( optimizationRes.second ) { if ( optimizationRes.second ) {
resultConstraints.emplace_back(nativeRhs.A.row(i), nativeRhs.b(i) + (nativeRhs.A.row(i) * optimizationRes.first)(0)); resultConstraints.emplace_back(nativeRhs.A.row(i), nativeRhs.b(i) + (nativeRhs.A.row(i) * optimizationRes.first)(0));
@ -269,12 +269,12 @@ namespace storm {
// If optimizationRes.second is false, it means that rhs is unbounded in this direction, i.e., the current constraint is not inserted // If optimizationRes.second is false, it means that rhs is unbounded in this direction, i.e., the current constraint is not inserted
} }
if(resultConstraints.empty()) {
if (resultConstraints.empty()) {
return std::make_shared<NativePolytope<ValueType>>(std::vector<Halfspace<ValueType>>()); return std::make_shared<NativePolytope<ValueType>>(std::vector<Halfspace<ValueType>>());
} else { } else {
EigenMatrix newA(resultConstraints.size(), resultConstraints.front().first.rows()); EigenMatrix newA(resultConstraints.size(), resultConstraints.front().first.rows());
EigenVector newb(resultConstraints.size()); EigenVector newb(resultConstraints.size());
for(uint_fast64_t i = 0; i < newA.rows(); ++i) {
for (int_fast64_t i = 0; i < newA.rows(); ++i) {
newA.row(i) = resultConstraints[i].first; newA.row(i) = resultConstraints[i].first;
newb(i) = resultConstraints[i].second; newb(i) = resultConstraints[i].second;
} }
@ -287,7 +287,7 @@ namespace storm {
STORM_LOG_THROW(!matrix.empty(), storm::exceptions::InvalidArgumentException, "Invoked affine transformation with a matrix without rows."); STORM_LOG_THROW(!matrix.empty(), storm::exceptions::InvalidArgumentException, "Invoked affine transformation with a matrix without rows.");
EigenMatrix eigenMatrix(matrix.size(), matrix.front().size()); EigenMatrix eigenMatrix(matrix.size(), matrix.front().size());
for(uint_fast64_t row = 0; row < matrix.size(); ++row) {
for (uint_fast64_t row = 0; row < matrix.size(); ++row) {
eigenMatrix.row(row) = storm::adapters::EigenAdapter::toEigenVector(matrix[row]); eigenMatrix.row(row) = storm::adapters::EigenAdapter::toEigenVector(matrix[row]);
} }
EigenVector eigenVector = storm::adapters::EigenAdapter::toEigenVector(vector); EigenVector eigenVector = storm::adapters::EigenAdapter::toEigenVector(vector);
@ -301,14 +301,14 @@ namespace storm {
template <typename ValueType> template <typename ValueType>
std::pair<typename NativePolytope<ValueType>::Point, bool> NativePolytope<ValueType>::optimize(Point const& direction) const { std::pair<typename NativePolytope<ValueType>::Point, bool> NativePolytope<ValueType>::optimize(Point const& direction) const {
if(isUniversal()) {
if (isUniversal()) {
return std::make_pair(Point(), false); return std::make_pair(Point(), false);
} }
storm::solver::Z3LpSolver solver(storm::solver::OptimizationDirection::Maximize); storm::solver::Z3LpSolver solver(storm::solver::OptimizationDirection::Maximize);
std::vector<storm::expressions::Variable> variables; std::vector<storm::expressions::Variable> variables;
variables.reserve(A.cols()); variables.reserve(A.cols());
for (uint_fast64_t i = 0; i < A.cols(); ++i) {
for (int_fast64_t i = 0; i < A.cols(); ++i) {
variables.push_back(solver.addUnboundedContinuousVariable("x" + std::to_string(i), direction[i])); variables.push_back(solver.addUnboundedContinuousVariable("x" + std::to_string(i), direction[i]));
} }
std::vector<storm::expressions::Expression> constraints = getConstraints(solver.getManager(), variables); std::vector<storm::expressions::Expression> constraints = getConstraints(solver.getManager(), variables);
@ -332,14 +332,14 @@ namespace storm {
template <typename ValueType> template <typename ValueType>
std::pair<typename NativePolytope<ValueType>::EigenVector, bool> NativePolytope<ValueType>::optimize(EigenVector const& direction) const { std::pair<typename NativePolytope<ValueType>::EigenVector, bool> NativePolytope<ValueType>::optimize(EigenVector const& direction) const {
if(isUniversal()) {
if (isUniversal()) {
return std::make_pair(EigenVector(), false); return std::make_pair(EigenVector(), false);
} }
storm::solver::Z3LpSolver solver(storm::solver::OptimizationDirection::Maximize); storm::solver::Z3LpSolver solver(storm::solver::OptimizationDirection::Maximize);
std::vector<storm::expressions::Variable> variables; std::vector<storm::expressions::Variable> variables;
variables.reserve(A.cols()); variables.reserve(A.cols());
for (uint_fast64_t i = 0; i < A.cols(); ++i) {
for (int_fast64_t i = 0; i < A.cols(); ++i) {
variables.push_back(solver.addUnboundedContinuousVariable("x" + std::to_string(i), direction(i))); variables.push_back(solver.addUnboundedContinuousVariable("x" + std::to_string(i), direction(i)));
} }
std::vector<storm::expressions::Expression> constraints = getConstraints(solver.getManager(), variables); std::vector<storm::expressions::Expression> constraints = getConstraints(solver.getManager(), variables);
@ -375,7 +375,7 @@ namespace storm {
std::vector<storm::expressions::Variable> NativePolytope<ValueType>::declareVariables(storm::expressions::ExpressionManager& manager, std::string const& namePrefix) const { std::vector<storm::expressions::Variable> NativePolytope<ValueType>::declareVariables(storm::expressions::ExpressionManager& manager, std::string const& namePrefix) const {
std::vector<storm::expressions::Variable> result; std::vector<storm::expressions::Variable> result;
result.reserve(A.cols()); result.reserve(A.cols());
for(uint_fast64_t col=0; col < A.cols(); ++col){
for (int_fast64_t col=0; col < A.cols(); ++col){
result.push_back(manager.declareVariable(namePrefix + std::to_string(col), manager.getRationalType())); result.push_back(manager.declareVariable(namePrefix + std::to_string(col), manager.getRationalType()));
} }
return result; return result;
@ -384,9 +384,9 @@ namespace storm {
template <typename ValueType> template <typename ValueType>
std::vector<storm::expressions::Expression> NativePolytope<ValueType>::getConstraints(storm::expressions::ExpressionManager const& manager, std::vector<storm::expressions::Variable> const& variables) const { std::vector<storm::expressions::Expression> NativePolytope<ValueType>::getConstraints(storm::expressions::ExpressionManager const& manager, std::vector<storm::expressions::Variable> const& variables) const {
std::vector<storm::expressions::Expression> result; std::vector<storm::expressions::Expression> result;
for(uint_fast64_t row = 0; row < A.rows(); ++row) {
for (int_fast64_t row = 0; row < A.rows(); ++row) {
storm::expressions::Expression lhs = manager.rational(A(row,0)) * variables[0].getExpression(); storm::expressions::Expression lhs = manager.rational(A(row,0)) * variables[0].getExpression();
for(uint_fast64_t col=1; col < A.cols(); ++col) {
for (int_fast64_t col=1; col < A.cols(); ++col) {
lhs = lhs + manager.rational(A(row,col)) * variables[col].getExpression(); lhs = lhs + manager.rational(A(row,col)) * variables[col].getExpression();
} }
result.push_back(lhs <= manager.rational(b(row))); result.push_back(lhs <= manager.rational(b(row)));

2
src/storm/storage/geometry/nativepolytopeconversion/HyperplaneEnumeration.cpp

@ -91,7 +91,7 @@ namespace storm {
for(auto const& mapEntry : vertexCollector){ for(auto const& mapEntry : vertexCollector){
for(auto const& oldHyperplaneIndex : mapEntry.second){ for(auto const& oldHyperplaneIndex : mapEntry.second){
//ignore the hyperplanes which are redundant, i.e. for which there is no new index //ignore the hyperplanes which are redundant, i.e. for which there is no new index
if(oldToNewIndexMapping[oldHyperplaneIndex] < relevantVector.rows()){
if((int_fast64_t) oldToNewIndexMapping[oldHyperplaneIndex] < relevantVector.rows()){
vertexSets[oldToNewIndexMapping[oldHyperplaneIndex]].insert(resultVertices.size()); vertexSets[oldToNewIndexMapping[oldHyperplaneIndex]].insert(resultVertices.size());
} }
} }

126
src/storm/storage/geometry/nativepolytopeconversion/QuickHull.cpp

@ -23,15 +23,15 @@ namespace storm {
STORM_LOG_DEBUG("Invoked QuickHull on " << points.size() << " points"); STORM_LOG_DEBUG("Invoked QuickHull on " << points.size() << " points");
const uint_fast64_t dimension = points.front().rows(); const uint_fast64_t dimension = points.front().rows();
if(dimension == 1) {
if (dimension == 1) {
handle1DPoints(points, generateRelevantVerticesAndVertexSets); handle1DPoints(points, generateRelevantVerticesAndVertexSets);
} else { } else {
// Generate initial set of d+1 affine independent points (if such a set exists) // Generate initial set of d+1 affine independent points (if such a set exists)
std::vector<uint_fast64_t> vertexIndices; std::vector<uint_fast64_t> vertexIndices;
if(this->findInitialVertices(points, vertexIndices)) {
if (this->findInitialVertices(points, vertexIndices)) {
// compute point inside initial facet // compute point inside initial facet
EigenVector insidePoint(EigenVector::Zero(dimension)); EigenVector insidePoint(EigenVector::Zero(dimension));
for(uint_fast64_t vertexIndex : vertexIndices){
for (uint_fast64_t vertexIndex : vertexIndices){
insidePoint += points[vertexIndex]; insidePoint += points[vertexIndex];
} }
insidePoint /= storm::utility::convertNumber<ValueType>((uint_fast64_t) vertexIndices.size()); insidePoint /= storm::utility::convertNumber<ValueType>((uint_fast64_t) vertexIndices.size());
@ -79,13 +79,13 @@ namespace storm {
ValueType maxValue = points.front()(0); ValueType maxValue = points.front()(0);
uint_fast64_t minIndex = 0; uint_fast64_t minIndex = 0;
uint_fast64_t maxIndex = 0; uint_fast64_t maxIndex = 0;
for(uint_fast64_t pointIndex = 1; pointIndex < points.size(); ++pointIndex) {
for (uint_fast64_t pointIndex = 1; pointIndex < points.size(); ++pointIndex) {
ValueType const& pointValue = points[pointIndex](0); ValueType const& pointValue = points[pointIndex](0);
if(pointValue < minValue) {
if (pointValue < minValue) {
minValue = pointValue; minValue = pointValue;
minIndex = pointIndex; minIndex = pointIndex;
} }
if(pointValue > maxValue) {
if (pointValue > maxValue) {
maxValue = pointValue; maxValue = pointValue;
maxIndex = pointIndex; maxIndex = pointIndex;
} }
@ -96,11 +96,11 @@ namespace storm {
resultVector = EigenVector(2); resultVector = EigenVector(2);
resultVector(0) = -minValue; resultVector(0) = -minValue;
resultVector(1) = maxValue; resultVector(1) = maxValue;
if(generateRelevantVerticesAndVertexSets) {
if (generateRelevantVerticesAndVertexSets) {
relevantVertices.push_back(points[minIndex]); relevantVertices.push_back(points[minIndex]);
std::vector<uint_fast64_t> minVertexSet(1,0); std::vector<uint_fast64_t> minVertexSet(1,0);
vertexSets.push_back(std::move(minVertexSet)); vertexSets.push_back(std::move(minVertexSet));
if(minIndex != maxIndex && points[minIndex] != points[maxIndex]) {
if (minIndex != maxIndex && points[minIndex] != points[maxIndex]) {
relevantVertices.push_back(points[maxIndex]); relevantVertices.push_back(points[maxIndex]);
std::vector<uint_fast64_t> maxVertexSet(1,1); std::vector<uint_fast64_t> maxVertexSet(1,1);
vertexSets.push_back(std::move(maxVertexSet)); vertexSets.push_back(std::move(maxVertexSet));
@ -117,7 +117,7 @@ namespace storm {
vectorMatrix.col(i) << points[subset[i]], storm::utility::one<ValueType>(); vectorMatrix.col(i) << points[subset[i]], storm::utility::one<ValueType>();
} }
vectorMatrix.col(subset.size()) << points[item], storm::utility::one<ValueType>(); vectorMatrix.col(subset.size()) << points[item], storm::utility::one<ValueType>();
return (vectorMatrix.fullPivLu().rank() > subset.size());
return (vectorMatrix.fullPivLu().rank() > (int_fast64_t) subset.size());
} }
template<typename ValueType> template<typename ValueType>
@ -129,13 +129,13 @@ namespace storm {
const uint_fast64_t dimension = points.front().rows(); const uint_fast64_t dimension = points.front().rows();
EigenVector refPoint = points.front(); EigenVector refPoint = points.front();
EigenMatrix constraints(points.size() - 1, dimension); EigenMatrix constraints(points.size() - 1, dimension);
for(unsigned row = 1; row < points.size(); ++row) {
for (unsigned row = 1; row < points.size(); ++row) {
constraints.row(row - 1) = points[row] - refPoint; constraints.row(row - 1) = points[row] - refPoint;
} }
EigenVector normal = constraints.fullPivLu().kernel().col(0); EigenVector normal = constraints.fullPivLu().kernel().col(0);
// Eigen returns the column vector 0...0 if the kernel is empty (i.e., there is no such hyperplane) // Eigen returns the column vector 0...0 if the kernel is empty (i.e., there is no such hyperplane)
if(normal.isZero()) {
if (normal.isZero()) {
pointsAffineDependent = false; pointsAffineDependent = false;
} else { } else {
points.push_back(refPoint + normal); points.push_back(refPoint + normal);
@ -156,7 +156,7 @@ namespace storm {
newA.row(row) = resultMatrix.row(row); newA.row(row) = resultMatrix.row(row);
newb(row) = resultVector(row); newb(row) = resultVector(row);
} }
for(; row < numOfRegularConstraints + numOfAdditionalConstraints; ++row) {
for (; row < numOfRegularConstraints + numOfAdditionalConstraints; ++row) {
newA.row(row) = std::move(additionalConstraints[row - numOfRegularConstraints].first); newA.row(row) = std::move(additionalConstraints[row - numOfRegularConstraints].first);
newb(row) = additionalConstraints[row - numOfRegularConstraints].second; newb(row) = additionalConstraints[row - numOfRegularConstraints].second;
} }
@ -165,9 +165,9 @@ namespace storm {
// clear the additionally added points. Note that the order of the points might have changed // clear the additionally added points. Note that the order of the points might have changed
storm::storage::BitVector keptPoints(points.size(), true); storm::storage::BitVector keptPoints(points.size(), true);
for(uint_fast64_t pointIndex = 0; pointIndex < points.size(); ++pointIndex) {
for(int_fast64_t row = 0; row < resultMatrix.rows(); ++row) {
if((resultMatrix.row(row) * points[pointIndex])(0) > resultVector(row)) {
for (uint_fast64_t pointIndex = 0; pointIndex < points.size(); ++pointIndex) {
for (int_fast64_t row = 0; row < resultMatrix.rows(); ++row) {
if ((resultMatrix.row(row) * points[pointIndex])(0) > resultVector(row)) {
keptPoints.set(pointIndex, false); keptPoints.set(pointIndex, false);
break; break;
} }
@ -175,11 +175,11 @@ namespace storm {
} }
points = storm::utility::vector::filterVector(points, keptPoints); points = storm::utility::vector::filterVector(points, keptPoints);
if(generateRelevantVerticesAndVertexSets) {
if (generateRelevantVerticesAndVertexSets) {
storm::storage::BitVector keptVertices(relevantVertices.size(), true); storm::storage::BitVector keptVertices(relevantVertices.size(), true);
for(uint_fast64_t vertexIndex = 0; vertexIndex < relevantVertices.size(); ++vertexIndex) {
for(int_fast64_t row = 0; row < resultMatrix.rows(); ++row) {
if((resultMatrix.row(row) * relevantVertices[vertexIndex])(0) > resultVector(row)) {
for (uint_fast64_t vertexIndex = 0; vertexIndex < relevantVertices.size(); ++vertexIndex) {
for (int_fast64_t row = 0; row < resultMatrix.rows(); ++row) {
if ((resultMatrix.row(row) * relevantVertices[vertexIndex])(0) > resultVector(row)) {
keptVertices.set(vertexIndex, false); keptVertices.set(vertexIndex, false);
break; break;
} }
@ -195,22 +195,22 @@ namespace storm {
template<typename ValueType> template<typename ValueType>
bool QuickHull<ValueType>::findInitialVertices(std::vector<EigenVector>& points, std::vector<uint_fast64_t>& verticesOfInitialPolytope) const{ bool QuickHull<ValueType>::findInitialVertices(std::vector<EigenVector>& points, std::vector<uint_fast64_t>& verticesOfInitialPolytope) const{
const uint_fast64_t dimension = points.front().rows(); const uint_fast64_t dimension = points.front().rows();
if(points.size() < dimension + 1){
if (points.size() < dimension + 1){
//not enough points to obtain a (non-degenerated) polytope //not enough points to obtain a (non-degenerated) polytope
return false; return false;
} }
// We first find some good candidates to get a (hopefully) large initial mesh. // We first find some good candidates to get a (hopefully) large initial mesh.
storm::storage::BitVector notGoodCandidates(points.size(), true); storm::storage::BitVector notGoodCandidates(points.size(), true);
for(uint_fast64_t dim = 0; dim < dimension; ++dim) {
if(!notGoodCandidates.empty()) {
for (uint_fast64_t dim = 0; dim < dimension; ++dim) {
if (!notGoodCandidates.empty()) {
uint_fast64_t minIndex = *notGoodCandidates.begin(); uint_fast64_t minIndex = *notGoodCandidates.begin();
uint_fast64_t maxIndex = *notGoodCandidates.begin(); uint_fast64_t maxIndex = *notGoodCandidates.begin();
for(uint_fast64_t pointIndex : notGoodCandidates) {
if(points[minIndex](dim) > points[pointIndex](dim)){
for (uint_fast64_t pointIndex : notGoodCandidates) {
if (points[minIndex](dim) > points[pointIndex](dim)){
minIndex = pointIndex; minIndex = pointIndex;
} }
if(points[maxIndex](dim) < points[pointIndex](dim)){
if (points[maxIndex](dim) < points[pointIndex](dim)){
maxIndex = pointIndex; maxIndex = pointIndex;
} }
} }
@ -222,8 +222,8 @@ namespace storm {
//Found candidates. Now swap them to the front. //Found candidates. Now swap them to the front.
const uint_fast64_t numOfGoodCandidates = goodCandidates.getNumberOfSetBits(); const uint_fast64_t numOfGoodCandidates = goodCandidates.getNumberOfSetBits();
for( auto const& goodCandidate : goodCandidates) {
if(goodCandidate >= numOfGoodCandidates) {
for ( auto const& goodCandidate : goodCandidates) {
if (goodCandidate >= numOfGoodCandidates) {
uint_fast64_t notGoodCandidate = *notGoodCandidates.begin(); uint_fast64_t notGoodCandidate = *notGoodCandidates.begin();
assert(notGoodCandidate < numOfGoodCandidates); assert(notGoodCandidate < numOfGoodCandidates);
std::swap(points[notGoodCandidate], points[goodCandidate]); std::swap(points[notGoodCandidate], points[goodCandidate]);
@ -232,7 +232,7 @@ namespace storm {
} }
storm::storage::geometry::SubsetEnumerator<std::vector<EigenVector>> subsetEnum(points.size(), dimension+1, points, affineFilter); storm::storage::geometry::SubsetEnumerator<std::vector<EigenVector>> subsetEnum(points.size(), dimension+1, points, affineFilter);
if(subsetEnum.setToFirstSubset()){
if (subsetEnum.setToFirstSubset()){
verticesOfInitialPolytope = subsetEnum.getCurrentSubset(); verticesOfInitialPolytope = subsetEnum.getCurrentSubset();
return true; return true;
} else { } else {
@ -247,7 +247,7 @@ namespace storm {
std::vector<Facet> result; std::vector<Facet> result;
result.reserve(dimension + 1); result.reserve(dimension + 1);
storm::storage::geometry::SubsetEnumerator<> subsetEnum(verticesOfInitialPolytope.size(), dimension); storm::storage::geometry::SubsetEnumerator<> subsetEnum(verticesOfInitialPolytope.size(), dimension);
if(!subsetEnum.setToFirstSubset()){
if (!subsetEnum.setToFirstSubset()){
STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Could not find an initial subset."); STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Could not find an initial subset.");
} }
do{ do{
@ -255,13 +255,13 @@ namespace storm {
// set the points that lie on the new facet // set the points that lie on the new facet
std::vector<uint_fast64_t> const& subset(subsetEnum.getCurrentSubset()); std::vector<uint_fast64_t> const& subset(subsetEnum.getCurrentSubset());
newFacet.points.reserve(subset.size()); newFacet.points.reserve(subset.size());
for(uint_fast64_t i : subset){
for (uint_fast64_t i : subset){
newFacet.points.push_back(verticesOfInitialPolytope[i]); newFacet.points.push_back(verticesOfInitialPolytope[i]);
} }
//neighbors: these are always the remaining facets //neighbors: these are always the remaining facets
newFacet.neighbors.reserve(dimension); newFacet.neighbors.reserve(dimension);
for(uint_fast64_t i = 0; i < dimension+1; ++i){
if(i != result.size()){ //initFacets.size() will be the index of this new facet!
for (uint_fast64_t i = 0; i < dimension+1; ++i){
if (i != result.size()){ //initFacets.size() will be the index of this new facet!
newFacet.neighbors.push_back(i); newFacet.neighbors.push_back(i);
} }
} }
@ -280,14 +280,14 @@ namespace storm {
assert(facet.points.size() == dimension); assert(facet.points.size() == dimension);
EigenVector const& refPoint = points[facet.points.back()]; EigenVector const& refPoint = points[facet.points.back()];
EigenMatrix constraints(dimension-1, dimension); EigenMatrix constraints(dimension-1, dimension);
for(unsigned row = 0; row < dimension-1; ++row) {
for (unsigned row = 0; row < dimension-1; ++row) {
constraints.row(row) = (points[facet.points[row]] - refPoint); constraints.row(row) = (points[facet.points[row]] - refPoint);
} }
facet.normal = constraints.fullPivLu().kernel().col(0); facet.normal = constraints.fullPivLu().kernel().col(0);
facet.offset = facet.normal.dot(refPoint); facet.offset = facet.normal.dot(refPoint);
// invert the plane if the insidePoint is not contained in it // invert the plane if the insidePoint is not contained in it
if(facet.normal.dot(insidePoint) > facet.offset) {
if (facet.normal.dot(insidePoint) > facet.offset) {
facet.normal = -facet.normal; facet.normal = -facet.normal;
facet.offset = -facet.offset; facet.offset = -facet.offset;
} }
@ -306,19 +306,19 @@ namespace storm {
computeOutsideSetOfFacet(facets[facetIndex], currentOutsidePoints, points); computeOutsideSetOfFacet(facets[facetIndex], currentOutsidePoints, points);
} }
for(uint_fast64_t facetCount = currentFacets.getNextSetIndex(0); facetCount != currentFacets.size(); facetCount = currentFacets.getNextSetIndex(facetCount+1)) {
for (uint_fast64_t facetCount = currentFacets.getNextSetIndex(0); facetCount != currentFacets.size(); facetCount = currentFacets.getNextSetIndex(facetCount+1)) {
// set all points to false to get rid of points that lie within the polytope after each iteration // set all points to false to get rid of points that lie within the polytope after each iteration
currentOutsidePoints.clear(); currentOutsidePoints.clear();
// Find a facet with a non-empty outside set // Find a facet with a non-empty outside set
if(!facets[facetCount].outsideSet.empty()) {
if (!facets[facetCount].outsideSet.empty()) {
uint_fast64_t numberOfNewFacets = 0; uint_fast64_t numberOfNewFacets = 0;
// Now we compute the enlarged mesh // Now we compute the enlarged mesh
uint_fast64_t farAwayPointIndex = facets[facetCount].maxOutsidePointIndex; uint_fast64_t farAwayPointIndex = facets[facetCount].maxOutsidePointIndex;
// get Visible set from maxOutsidePoint of the current facet // get Visible set from maxOutsidePoint of the current facet
std::set<uint_fast64_t> visibleSet = getVisibleSet(facets, facetCount, points[farAwayPointIndex]); std::set<uint_fast64_t> visibleSet = getVisibleSet(facets, facetCount, points[farAwayPointIndex]);
std::set<uint_fast64_t> invisibleSet = getInvisibleNeighbors(facets, visibleSet); std::set<uint_fast64_t> invisibleSet = getInvisibleNeighbors(facets, visibleSet);
for(auto invisFacetIt = invisibleSet.begin(); invisFacetIt != invisibleSet.end(); ++invisFacetIt) {
for(auto visFacetIt = visibleSet.begin(); visFacetIt != visibleSet.end(); ++visFacetIt) {
for (auto invisFacetIt = invisibleSet.begin(); invisFacetIt != invisibleSet.end(); ++invisFacetIt) {
for (auto visFacetIt = visibleSet.begin(); visFacetIt != visibleSet.end(); ++visFacetIt) {
if (std::find(facets[*invisFacetIt].neighbors.begin(), facets[*invisFacetIt].neighbors.end(), *visFacetIt) != facets[*invisFacetIt].neighbors.end()) { if (std::find(facets[*invisFacetIt].neighbors.begin(), facets[*invisFacetIt].neighbors.end(), *visFacetIt) != facets[*invisFacetIt].neighbors.end()) {
Facet newFacet; Facet newFacet;
// Set points of Facet // Set points of Facet
@ -339,14 +339,14 @@ namespace storm {
} }
} }
for(auto visibleFacet : visibleSet){
for(uint_fast64_t outsidePoint : facets[visibleFacet].outsideSet){
for (auto visibleFacet : visibleSet){
for (uint_fast64_t outsidePoint : facets[visibleFacet].outsideSet){
currentOutsidePoints.set(outsidePoint, true); currentOutsidePoints.set(outsidePoint, true);
} }
currentFacets.set(visibleFacet, false); currentFacets.set(visibleFacet, false);
} }
// compute new outside sets // compute new outside sets
for(uint_fast64_t facetIndex : currentFacets){
for (uint_fast64_t facetIndex : currentFacets){
computeOutsideSetOfFacet(facets[facetIndex], currentOutsidePoints, points); computeOutsideSetOfFacet(facets[facetIndex], currentOutsidePoints, points);
} }
@ -360,18 +360,18 @@ namespace storm {
void QuickHull<ValueType>::getPolytopeFromMesh(std::vector<EigenVector> const& points, std::vector<Facet> const& facets, storm::storage::BitVector const& currentFacets, bool generateRelevantVerticesAndVertexSets) { void QuickHull<ValueType>::getPolytopeFromMesh(std::vector<EigenVector> const& points, std::vector<Facet> const& facets, storm::storage::BitVector const& currentFacets, bool generateRelevantVerticesAndVertexSets) {
storm::storage::geometry::HyperplaneCollector<ValueType> hyperplaneCollector; storm::storage::geometry::HyperplaneCollector<ValueType> hyperplaneCollector;
for(auto facet : currentFacets) {
for (auto facet : currentFacets) {
hyperplaneCollector.insert(std::move(facets[facet].normal), std::move(facets[facet].offset), generateRelevantVerticesAndVertexSets ? &facets[facet].points : nullptr); hyperplaneCollector.insert(std::move(facets[facet].normal), std::move(facets[facet].offset), generateRelevantVerticesAndVertexSets ? &facets[facet].points : nullptr);
} }
if(generateRelevantVerticesAndVertexSets){
if (generateRelevantVerticesAndVertexSets){
//Get the mapping from a hyperplane to the set of vertices that lie on that plane, erase the duplicates, and count for each vertex the number of hyperplanes on which that vertex lies //Get the mapping from a hyperplane to the set of vertices that lie on that plane, erase the duplicates, and count for each vertex the number of hyperplanes on which that vertex lies
vertexSets = hyperplaneCollector.getIndexLists(); vertexSets = hyperplaneCollector.getIndexLists();
std::vector<uint_fast64_t> hyperplanesOnVertexCounter(points.size(), 0); std::vector<uint_fast64_t> hyperplanesOnVertexCounter(points.size(), 0);
for(auto& vertexVector : vertexSets){
for (auto& vertexVector : vertexSets){
std::set<uint_fast64_t> vertexSet; std::set<uint_fast64_t> vertexSet;
for(auto const& i : vertexVector){
if(vertexSet.insert(i).second){
for (auto const& i : vertexVector){
if (vertexSet.insert(i).second){
++hyperplanesOnVertexCounter[i]; ++hyperplanesOnVertexCounter[i];
} }
} }
@ -382,8 +382,8 @@ namespace storm {
//Therefore, we additionally store the old indices for every vertex to be able to translate from old to new indices //Therefore, we additionally store the old indices for every vertex to be able to translate from old to new indices
std::unordered_map<EigenVector, std::vector<uint_fast64_t>> relevantVerticesMap; std::unordered_map<EigenVector, std::vector<uint_fast64_t>> relevantVerticesMap;
relevantVerticesMap.reserve(points.size()); relevantVerticesMap.reserve(points.size());
for(uint_fast64_t vertexIndex = 0; vertexIndex < hyperplanesOnVertexCounter.size(); ++vertexIndex){
if(hyperplanesOnVertexCounter[vertexIndex] >= points.front().rows()){
for (uint_fast64_t vertexIndex = 0; vertexIndex < hyperplanesOnVertexCounter.size(); ++vertexIndex){
if ((int_fast64_t) hyperplanesOnVertexCounter[vertexIndex] >= points.front().rows()){
auto mapEntry = relevantVerticesMap.insert(typename std::unordered_map<EigenVector, std::vector<uint_fast64_t>>::value_type(points[vertexIndex], std::vector<uint_fast64_t>())).first; auto mapEntry = relevantVerticesMap.insert(typename std::unordered_map<EigenVector, std::vector<uint_fast64_t>>::value_type(points[vertexIndex], std::vector<uint_fast64_t>())).first;
mapEntry->second.push_back(vertexIndex); mapEntry->second.push_back(vertexIndex);
} }
@ -392,17 +392,17 @@ namespace storm {
std::vector<uint_fast64_t> oldToNewIndexMapping (points.size(), points.size()); //Initialize with some illegal value std::vector<uint_fast64_t> oldToNewIndexMapping (points.size(), points.size()); //Initialize with some illegal value
relevantVertices.clear(); relevantVertices.clear();
relevantVertices.reserve(relevantVerticesMap.size()); relevantVertices.reserve(relevantVerticesMap.size());
for(auto const& mapEntry : relevantVerticesMap){
for(auto const& oldIndex : mapEntry.second){
for (auto const& mapEntry : relevantVerticesMap){
for (auto const& oldIndex : mapEntry.second){
oldToNewIndexMapping[oldIndex] = relevantVertices.size(); oldToNewIndexMapping[oldIndex] = relevantVertices.size();
} }
relevantVertices.push_back(mapEntry.first); relevantVertices.push_back(mapEntry.first);
} }
//Actually translate and erase duplicates //Actually translate and erase duplicates
for(auto& vertexVector : vertexSets){
for (auto& vertexVector : vertexSets){
std::set<uint_fast64_t> vertexSet; std::set<uint_fast64_t> vertexSet;
for(auto const& oldIndex : vertexVector){
if(hyperplanesOnVertexCounter[oldIndex] >= points.front().rows()){
for (auto const& oldIndex : vertexVector){
if ((int_fast64_t) hyperplanesOnVertexCounter[oldIndex] >= points.front().rows()){
vertexSet.insert(oldToNewIndexMapping[oldIndex]); vertexSet.insert(oldToNewIndexMapping[oldIndex]);
} }
} }
@ -424,14 +424,14 @@ namespace storm {
std::set<uint_fast64_t> visibleSet; std::set<uint_fast64_t> visibleSet;
facetsChecked.insert(startIndex); facetsChecked.insert(startIndex);
visibleSet.insert(startIndex); visibleSet.insert(startIndex);
for(uint_fast64_t i = 0; i < facets[startIndex].neighbors.size(); ++i){
for (uint_fast64_t i = 0; i < facets[startIndex].neighbors.size(); ++i){
facetsToCheck.insert(facets[startIndex].neighbors[i]); facetsToCheck.insert(facets[startIndex].neighbors[i]);
} }
while (!facetsToCheck.empty()){ while (!facetsToCheck.empty()){
auto elementIt = facetsToCheck.begin(); auto elementIt = facetsToCheck.begin();
if ( point.dot(facets[*elementIt].normal) > facets[*elementIt].offset) { if ( point.dot(facets[*elementIt].normal) > facets[*elementIt].offset) {
visibleSet.insert(*elementIt); visibleSet.insert(*elementIt);
for(uint_fast64_t i = 0; i < facets[*elementIt].neighbors.size(); ++i){
for (uint_fast64_t i = 0; i < facets[*elementIt].neighbors.size(); ++i){
if (facetsChecked.find(facets[*elementIt].neighbors[i]) == facetsChecked.end()){ if (facetsChecked.find(facets[*elementIt].neighbors[i]) == facetsChecked.end()){
facetsToCheck.insert(facets[*elementIt].neighbors[i]); facetsToCheck.insert(facets[*elementIt].neighbors[i]);
} }
@ -445,8 +445,8 @@ namespace storm {
template<typename ValueType> template<typename ValueType>
void QuickHull<ValueType>::setNeighborhoodOfNewFacets(std::vector<Facet>& facets, uint_fast64_t firstNewFacet, uint_fast64_t dimension) const{ void QuickHull<ValueType>::setNeighborhoodOfNewFacets(std::vector<Facet>& facets, uint_fast64_t firstNewFacet, uint_fast64_t dimension) const{
for(uint_fast64_t currentFacet = firstNewFacet; currentFacet < facets.size(); ++currentFacet){
for(uint_fast64_t otherFacet = currentFacet + 1; otherFacet < facets.size(); ++otherFacet){
for (uint_fast64_t currentFacet = firstNewFacet; currentFacet < facets.size(); ++currentFacet){
for (uint_fast64_t otherFacet = currentFacet + 1; otherFacet < facets.size(); ++otherFacet){
if (getCommonPoints(facets[currentFacet], facets[otherFacet]).size() >= dimension-1) { if (getCommonPoints(facets[currentFacet], facets[otherFacet]).size() >= dimension-1) {
facets[currentFacet].neighbors.push_back(otherFacet); facets[currentFacet].neighbors.push_back(otherFacet);
facets[otherFacet].neighbors.push_back(currentFacet); facets[otherFacet].neighbors.push_back(currentFacet);
@ -466,9 +466,9 @@ namespace storm {
template<typename ValueType> template<typename ValueType>
void QuickHull<ValueType>::computeOutsideSetOfFacet(Facet& facet, storm::storage::BitVector& currentOutsidePoints, std::vector<EigenVector> const& points) const { void QuickHull<ValueType>::computeOutsideSetOfFacet(Facet& facet, storm::storage::BitVector& currentOutsidePoints, std::vector<EigenVector> const& points) const {
ValueType maxMultiplicationResult = facet.offset; ValueType maxMultiplicationResult = facet.offset;
for(uint_fast64_t pointIndex : currentOutsidePoints) {
for (uint_fast64_t pointIndex : currentOutsidePoints) {
ValueType multiplicationResult = points[pointIndex].dot(facet.normal); ValueType multiplicationResult = points[pointIndex].dot(facet.normal);
if( multiplicationResult > facet.offset ) {
if ( multiplicationResult > facet.offset ) {
currentOutsidePoints.set(pointIndex, false); // we already know that the point lies outside so it can be ignored for future facets currentOutsidePoints.set(pointIndex, false); // we already know that the point lies outside so it can be ignored for future facets
facet.outsideSet.push_back(pointIndex); facet.outsideSet.push_back(pointIndex);
if (multiplicationResult > maxMultiplicationResult) { if (multiplicationResult > maxMultiplicationResult) {
@ -482,8 +482,8 @@ namespace storm {
template<typename ValueType> template<typename ValueType>
std::vector<uint_fast64_t> QuickHull<ValueType>::getCommonPoints(Facet const& lhs, Facet const& rhs) const { std::vector<uint_fast64_t> QuickHull<ValueType>::getCommonPoints(Facet const& lhs, Facet const& rhs) const {
std::vector<uint_fast64_t> commonPoints; std::vector<uint_fast64_t> commonPoints;
for(uint_fast64_t lhsPoint : lhs.points){
for(uint_fast64_t rhsPoint : rhs.points){
for (uint_fast64_t lhsPoint : lhs.points){
for (uint_fast64_t rhsPoint : rhs.points){
if (lhsPoint == rhsPoint){ if (lhsPoint == rhsPoint){
commonPoints.push_back(lhsPoint); commonPoints.push_back(lhsPoint);
} }
@ -495,8 +495,8 @@ namespace storm {
template<typename ValueType> template<typename ValueType>
std::set<uint_fast64_t> QuickHull<ValueType>::getInvisibleNeighbors( std::vector<Facet>& facets, std::set<uint_fast64_t> const& visibleSet) const { std::set<uint_fast64_t> QuickHull<ValueType>::getInvisibleNeighbors( std::vector<Facet>& facets, std::set<uint_fast64_t> const& visibleSet) const {
std::set<uint_fast64_t> invisibleNeighbors; std::set<uint_fast64_t> invisibleNeighbors;
for(auto currentFacetIt = visibleSet.begin(); currentFacetIt != visibleSet.end(); ++currentFacetIt){
for(uint_fast64_t currentNeighbor = 0; currentNeighbor < facets[*currentFacetIt].neighbors.size(); ++currentNeighbor){
for (auto currentFacetIt = visibleSet.begin(); currentFacetIt != visibleSet.end(); ++currentFacetIt){
for (uint_fast64_t currentNeighbor = 0; currentNeighbor < facets[*currentFacetIt].neighbors.size(); ++currentNeighbor){
if (visibleSet.find(facets[*currentFacetIt].neighbors[currentNeighbor]) == visibleSet.end()){ if (visibleSet.find(facets[*currentFacetIt].neighbors[currentNeighbor]) == visibleSet.end()){
invisibleNeighbors.insert(facets[*currentFacetIt].neighbors[currentNeighbor]); invisibleNeighbors.insert(facets[*currentFacetIt].neighbors[currentNeighbor]);
} }

Loading…
Cancel
Save