Browse Source
			
			
			added function that reduces the nesting of expressions (e.g. when considering a big sum with many summands. This fixes stack overflows when translating expressions
			
			
				main
			
			
		
		added function that reduces the nesting of expressions (e.g. when considering a big sum with many summands. This fixes stack overflows when translating expressions
	
		
	
			
			
				main
			
			
		
				 8 changed files with 255 additions and 11 deletions
			
			
		- 
					8src/storm/storage/expressions/BaseExpression.cpp
- 
					7src/storm/storage/expressions/BaseExpression.h
- 
					4src/storm/storage/expressions/Expression.cpp
- 
					7src/storm/storage/expressions/Expression.h
- 
					180src/storm/storage/expressions/ReduceNestingVisitor.cpp
- 
					36src/storm/storage/expressions/ReduceNestingVisitor.h
- 
					7src/storm/storage/jani/JSONExporter.cpp
- 
					17src/storm/utility/ExpressionHelper.cpp
| @ -0,0 +1,180 @@ | |||||
|  | #include <string>
 | ||||
|  | 
 | ||||
|  | #include "storm/storage/expressions/ReduceNestingVisitor.h"
 | ||||
|  | #include "storm/storage/expressions/Expressions.h"
 | ||||
|  | 
 | ||||
|  | namespace storm { | ||||
|  |     namespace expressions  { | ||||
|  |          | ||||
|  |         ReduceNestingVisitor::ReduceNestingVisitor() { | ||||
|  |             // Intentionally left empty.
 | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         Expression ReduceNestingVisitor::reduceNesting(Expression const& expression) { | ||||
|  |             return Expression(boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getBaseExpression().accept(*this, boost::none))); | ||||
|  |         } | ||||
|  |          | ||||
|  |         boost::any ReduceNestingVisitor::visit(IfThenElseExpression const& expression, boost::any const& data) { | ||||
|  |             std::shared_ptr<BaseExpression const> conditionExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getCondition()->accept(*this, data)); | ||||
|  |             std::shared_ptr<BaseExpression const> thenExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getThenExpression()->accept(*this, data)); | ||||
|  |             std::shared_ptr<BaseExpression const> elseExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getElseExpression()->accept(*this, data)); | ||||
|  | 
 | ||||
|  |             // If the arguments did not change, we simply push the expression itself.
 | ||||
|  |             if (conditionExpression.get() == expression.getCondition().get() && thenExpression.get() == expression.getThenExpression().get() && elseExpression.get() == expression.getElseExpression().get()) { | ||||
|  |                 return expression.getSharedPointer(); | ||||
|  |             } else { | ||||
|  | 				return std::const_pointer_cast<BaseExpression const>(std::shared_ptr<BaseExpression>(new IfThenElseExpression(expression.getManager(), expression.getType(), conditionExpression, thenExpression, elseExpression))); | ||||
|  |             } | ||||
|  |         } | ||||
|  |          | ||||
|  |         template <typename BinaryFunc> | ||||
|  |         std::vector<std::shared_ptr<BaseExpression const>> getAllOperands(BinaryFunc const& binaryExpression) { | ||||
|  |             auto opType = binaryExpression.getOperatorType(); | ||||
|  |             std::vector<std::shared_ptr<BaseExpression const>> stack = {binaryExpression.getSharedPointer()}; | ||||
|  |             std::vector<std::shared_ptr<BaseExpression const>> res; | ||||
|  |             while (!stack.empty()) { | ||||
|  |                 auto f = std::move(stack.back()); | ||||
|  |                 stack.pop_back(); | ||||
|  |                  | ||||
|  |                 for (uint64_t opIndex = 0; opIndex < 2; ++opIndex) { | ||||
|  |                     BinaryFunc const* subexp = dynamic_cast<BinaryFunc const*>(f->getOperand(opIndex).get()); | ||||
|  |                     if (subexp != nullptr && subexp->getOperatorType() == opType) { | ||||
|  |                         stack.push_back(f->getOperand(opIndex)); | ||||
|  |                     } else { | ||||
|  |                         res.push_back(f->getOperand(opIndex)); | ||||
|  |                     } | ||||
|  |                 } | ||||
|  |             } | ||||
|  |             return res; | ||||
|  |         } | ||||
|  |          | ||||
|  |         boost::any ReduceNestingVisitor::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) { | ||||
|  |              | ||||
|  |             // Check if the operator is commutative and associative
 | ||||
|  |             if (expression.getOperatorType() == BinaryBooleanFunctionExpression::OperatorType::Or || expression.getOperatorType() == BinaryBooleanFunctionExpression::OperatorType::And || expression.getOperatorType() == BinaryBooleanFunctionExpression::OperatorType::Iff) { | ||||
|  |                  | ||||
|  |                 std::vector<std::shared_ptr<BaseExpression const>> operands = getAllOperands<BinaryBooleanFunctionExpression>(expression); | ||||
|  |                  | ||||
|  |                 // Balance the syntax tree if there are enough operands
 | ||||
|  |                 if (operands.size() >= 4) { | ||||
|  |                      | ||||
|  |                     for (auto& operand : operands) { | ||||
|  |                         operand = boost::any_cast<std::shared_ptr<BaseExpression const>>(operand->accept(*this, data)); | ||||
|  |                     } | ||||
|  |                      | ||||
|  |                     auto opIt = operands.begin(); | ||||
|  |                     while (operands.size() > 1) { | ||||
|  |                         if (opIt == operands.end() || opIt == operands.end() - 1) { | ||||
|  |                             opIt = operands.begin(); | ||||
|  |                         } | ||||
|  |                         *opIt = std::const_pointer_cast<BaseExpression const>(std::shared_ptr<BaseExpression>(new BinaryBooleanFunctionExpression(expression.getManager(), expression.getType(), *opIt, operands.back(), expression.getOperatorType()))); | ||||
|  |                         operands.pop_back(); | ||||
|  |                         ++opIt; | ||||
|  |                     } | ||||
|  |                     return operands.front(); | ||||
|  |                 } | ||||
|  |             } | ||||
|  |              | ||||
|  |             std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this, data)); | ||||
|  |             std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this, data)); | ||||
|  | 
 | ||||
|  |             // If the arguments did not change, we simply push the expression itself.
 | ||||
|  |             if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { | ||||
|  |                 return expression.getSharedPointer(); | ||||
|  |             } else { | ||||
|  |                 return std::const_pointer_cast<BaseExpression const>(std::shared_ptr<BaseExpression>(new BinaryBooleanFunctionExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getOperatorType()))); | ||||
|  |             } | ||||
|  |         } | ||||
|  |          | ||||
|  |         boost::any ReduceNestingVisitor::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) { | ||||
|  |             // Check if the operator is commutative and associative
 | ||||
|  |             if (expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Plus || expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Times || expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Max || expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Min) { | ||||
|  |                  | ||||
|  |                 std::vector<std::shared_ptr<BaseExpression const>> operands = getAllOperands<BinaryNumericalFunctionExpression>(expression); | ||||
|  |                  | ||||
|  |                 // Balance the syntax tree if there are enough operands
 | ||||
|  |                 if (operands.size() >= 4) { | ||||
|  |                      | ||||
|  |                     for (auto& operand : operands) { | ||||
|  |                         operand = boost::any_cast<std::shared_ptr<BaseExpression const>>(operand->accept(*this, data)); | ||||
|  |                     } | ||||
|  |                      | ||||
|  |                     auto opIt = operands.begin(); | ||||
|  |                     while (operands.size() > 1) { | ||||
|  |                         if (opIt == operands.end() || opIt == operands.end() - 1) { | ||||
|  |                             opIt = operands.begin(); | ||||
|  |                         } | ||||
|  |                         *opIt = std::const_pointer_cast<BaseExpression const>(std::shared_ptr<BaseExpression>(new BinaryNumericalFunctionExpression(expression.getManager(), expression.getType(), *opIt, operands.back(), expression.getOperatorType()))); | ||||
|  |                         operands.pop_back(); | ||||
|  |                         ++opIt; | ||||
|  |                     } | ||||
|  |                     return operands.front(); | ||||
|  |                 } | ||||
|  |             } | ||||
|  | 
 | ||||
|  |              | ||||
|  |              | ||||
|  |             std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this, data)); | ||||
|  |             std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this, data)); | ||||
|  |              | ||||
|  |             // If the arguments did not change, we simply push the expression itself.
 | ||||
|  |             if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { | ||||
|  |                 return expression.getSharedPointer(); | ||||
|  |             } else { | ||||
|  | 				return std::const_pointer_cast<BaseExpression const>(std::shared_ptr<BaseExpression>(new BinaryNumericalFunctionExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getOperatorType()))); | ||||
|  |             } | ||||
|  |         } | ||||
|  |          | ||||
|  |         boost::any ReduceNestingVisitor::visit(BinaryRelationExpression const& expression, boost::any const& data) { | ||||
|  |              | ||||
|  |             std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this, data)); | ||||
|  |             std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this, data)); | ||||
|  |              | ||||
|  |             // If the arguments did not change, we simply push the expression itself.
 | ||||
|  |             if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { | ||||
|  |                 return expression.getSharedPointer(); | ||||
|  |             } else { | ||||
|  | 				return std::const_pointer_cast<BaseExpression const>(std::shared_ptr<BaseExpression>(new BinaryRelationExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getRelationType()))); | ||||
|  |             } | ||||
|  |         } | ||||
|  |          | ||||
|  |         boost::any ReduceNestingVisitor::visit(VariableExpression const& expression, boost::any const&) { | ||||
|  |             return expression.getSharedPointer(); | ||||
|  |         } | ||||
|  |          | ||||
|  |         boost::any ReduceNestingVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) { | ||||
|  |             std::shared_ptr<BaseExpression const> operandExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getOperand()->accept(*this, data)); | ||||
|  |              | ||||
|  |             // If the argument did not change, we simply push the expression itself.
 | ||||
|  |             if (operandExpression.get() == expression.getOperand().get()) { | ||||
|  |                 return expression.getSharedPointer(); | ||||
|  |             } else { | ||||
|  | 				return std::const_pointer_cast<BaseExpression const>(std::shared_ptr<BaseExpression>(new UnaryBooleanFunctionExpression(expression.getManager(), expression.getType(), operandExpression, expression.getOperatorType()))); | ||||
|  |             } | ||||
|  |         } | ||||
|  |          | ||||
|  |         boost::any ReduceNestingVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) { | ||||
|  |             std::shared_ptr<BaseExpression const> operandExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getOperand()->accept(*this, data)); | ||||
|  |              | ||||
|  |             // If the argument did not change, we simply push the expression itself.
 | ||||
|  |             if (operandExpression.get() == expression.getOperand().get()) { | ||||
|  |                 return expression.getSharedPointer(); | ||||
|  |             } else { | ||||
|  | 				return std::const_pointer_cast<BaseExpression const>(std::shared_ptr<BaseExpression>(new UnaryNumericalFunctionExpression(expression.getManager(), expression.getType(), operandExpression, expression.getOperatorType()))); | ||||
|  |             } | ||||
|  |         } | ||||
|  |          | ||||
|  |         boost::any ReduceNestingVisitor::visit(BooleanLiteralExpression const& expression, boost::any const&) { | ||||
|  |             return expression.getSharedPointer(); | ||||
|  |         } | ||||
|  |          | ||||
|  |         boost::any ReduceNestingVisitor::visit(IntegerLiteralExpression const& expression, boost::any const&) { | ||||
|  |             return expression.getSharedPointer(); | ||||
|  |         } | ||||
|  |          | ||||
|  |         boost::any ReduceNestingVisitor::visit(RationalLiteralExpression const& expression, boost::any const&) { | ||||
|  |             return expression.getSharedPointer(); | ||||
|  |         } | ||||
|  |          | ||||
|  |     } | ||||
|  | } | ||||
| @ -0,0 +1,36 @@ | |||||
|  | #pragma once | ||||
|  | 
 | ||||
|  | #include "storm/storage/expressions/Expression.h" | ||||
|  | #include "storm/storage/expressions/ExpressionVisitor.h" | ||||
|  | 
 | ||||
|  | namespace storm { | ||||
|  |     namespace expressions { | ||||
|  |         class ReduceNestingVisitor : public ExpressionVisitor { | ||||
|  |         public: | ||||
|  |             /*! | ||||
|  |              * Creates a new reduce nesting visitor. | ||||
|  |              */ | ||||
|  |             ReduceNestingVisitor(); | ||||
|  |              | ||||
|  |             /*! | ||||
|  |              * Reduces the nesting in the given expression | ||||
|  |              * | ||||
|  |              * @return A semantically equivalent expression with reduced nesting | ||||
|  |              */ | ||||
|  |             Expression reduceNesting(Expression const& expression); | ||||
|  |              | ||||
|  |             virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override; | ||||
|  |             virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override; | ||||
|  |             virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override; | ||||
|  |             virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override; | ||||
|  |             virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override; | ||||
|  |             virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override; | ||||
|  |             virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override; | ||||
|  |             virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override; | ||||
|  |             virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override; | ||||
|  |             virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override; | ||||
|  |              | ||||
|  |         private: | ||||
|  |         }; | ||||
|  |     } | ||||
|  | } | ||||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue